aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSvetlana Abramenkova <sabramenkova@luxoft.com>2018-12-16 12:25:30 +0300
committerSvetlana Abramenkova <sabramenkova@luxoft.com>2019-06-24 20:52:59 +0300
commit3904a615557e2b73d5430e2487980e92091b6aaa (patch)
tree98f0f793102fcfb936dc587ad8219fcc1e1c326b
parentb742d4b9a83306a07dda63f942371e951b732b59 (diff)
Bench: move rendering to separate process
Changed rendering from in-process in QML Live bench to rendereing in the separate process. Now it is possible to start multiple runtimes with different QML files to watch on live updates Change-Id: I94b6a070504926c03cfd7aad92dd9bfa2cc45f94 Fixes: AUTOSUITE-886 Reviewed-by: Nikolay Zamotaev <nzamotaev@luxoft.com>
-rw-r--r--doc/examples/customruntime.qdoc2
-rw-r--r--doc/usage.qdoc2
-rw-r--r--examples/customruntime/main.cpp3
-rw-r--r--src/bench/bench.pro11
-rw-r--r--src/bench/host.cpp4
-rw-r--r--src/bench/hostmodel.cpp1
-rw-r--r--src/bench/mainwindow.cpp80
-rw-r--r--src/bench/mainwindow.h8
-rw-r--r--src/bench/options.h3
-rw-r--r--src/bench/optionsdialog.cpp10
-rw-r--r--src/bench/optionsdialog.h3
-rw-r--r--src/bench/runtimemanager.cpp302
-rw-r--r--src/bench/runtimemanager.h91
-rw-r--r--src/bench/runtimeoptionpage.cpp89
-rw-r--r--src/bench/runtimeoptionpage.h65
-rw-r--r--src/bench/runtimeoptionpage.ui58
-rw-r--r--src/bench/runtimeprocess.cpp163
-rw-r--r--src/bench/runtimeprocess.h74
-rw-r--r--src/constants.cpp62
-rw-r--r--src/constants.h48
-rw-r--r--src/ipc/ipcclient.cpp15
-rw-r--r--src/ipc/ipcclient.h1
-rw-r--r--src/ipc/ipcserver.cpp2
-rw-r--r--src/livedocument.cpp1
-rw-r--r--src/livenodeengine.cpp1
-rw-r--r--src/remotepublisher.cpp9
-rw-r--r--src/remotepublisher.h1
-rw-r--r--src/remotereceiver.cpp1
-rw-r--r--src/runtime/main.cpp41
-rw-r--r--src/src.pri2
-rw-r--r--src/widgets/workspaceview.cpp17
-rw-r--r--src/widgets/workspaceview.h6
32 files changed, 1112 insertions, 64 deletions
diff --git a/doc/examples/customruntime.qdoc b/doc/examples/customruntime.qdoc
index 0182da3..39b490e 100644
--- a/doc/examples/customruntime.qdoc
+++ b/doc/examples/customruntime.qdoc
@@ -41,7 +41,7 @@ view setup, combined with additional C++ code and the QML Live system.
Start with the \l LiveNodeEngine class. We need to modify this class to be
able to receive workspace changes and active document updates. By default,
-the IPC listens to port 10234.
+the IPC listens on port 49156.
The code snippet below shows a minimal custom QML Live runtime:
diff --git a/doc/usage.qdoc b/doc/usage.qdoc
index c5ca3d0..ae68a56 100644
--- a/doc/usage.qdoc
+++ b/doc/usage.qdoc
@@ -239,7 +239,7 @@ You can create your own custom runtime with QML Live features. This way, you can
setup with your additional C++ code together with the QML Live system.
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 listens on port 10234.
+active document updates. By default, the IPC listens on port 49156.
The code snippet below shows an example of a minimal custom QML Live runtime:
diff --git a/examples/customruntime/main.cpp b/examples/customruntime/main.cpp
index 39bbff2..7abae05 100644
--- a/examples/customruntime/main.cpp
+++ b/examples/customruntime/main.cpp
@@ -37,6 +37,7 @@
// Use QML Live headers
#include "livenodeengine.h"
#include "remotereceiver.h"
+#include "constants.h"
class MyQmlApplicationEngine : public QQmlApplicationEngine
{
@@ -79,7 +80,7 @@ int main(int argc, char **argv)
// Listen to IPC call from remote QML Live Bench
RemoteReceiver receiver;
receiver.registerNode(&node);
- receiver.listen(10234);
+ receiver.listen(Constants::DEFAULT_PORT());
// Advanced use: let it know the initially loaded QML component (do this
// only after registering to receiver!)
diff --git a/src/bench/bench.pro b/src/bench/bench.pro
index df2b09a..576973a 100644
--- a/src/bench/bench.pro
+++ b/src/bench/bench.pro
@@ -29,7 +29,10 @@ SOURCES += \
autodiscoveryhostsdialog.cpp \
options.cpp \
newprojectwizard.cpp \
- appearanceoptionpage.cpp
+ appearanceoptionpage.cpp \
+ runtimemanager.cpp \
+ runtimeprocess.cpp \
+ runtimeoptionpage.cpp
HEADERS += \
aboutdialog.h \
@@ -52,7 +55,10 @@ HEADERS += \
autodiscoveryhostsdialog.h \
options.h \
newprojectwizard.h \
- appearanceoptionpage.h
+ appearanceoptionpage.h \
+ runtimemanager.h \
+ runtimeprocess.h \
+ runtimeoptionpage.h
FORMS += \
optionsdialog.ui \
@@ -60,6 +66,7 @@ FORMS += \
httpproxyoptionpage.ui \
importpathoptionpage.ui \
autodiscoveryhostsdialog.ui \
+ runtimeoptionpage.ui \
appearanceoptionpage.ui
include(../widgets/widgets.pri)
diff --git a/src/bench/host.cpp b/src/bench/host.cpp
index a674874..8dcc3f8 100644
--- a/src/bench/host.cpp
+++ b/src/bench/host.cpp
@@ -31,12 +31,12 @@
****************************************************************************/
#include "host.h"
-#include <QDebug>
+#include "constants.h"
#include <QSettings>
Host::Host(Type type, QObject *parent) :
QObject(parent),
- m_port(10234),
+ m_port(Constants::DEFAULT_PORT()),
m_xOffset(0),
m_yOffset(0),
m_rotation(0),
diff --git a/src/bench/hostmodel.cpp b/src/bench/hostmodel.cpp
index 4195aaa..d3895a4 100644
--- a/src/bench/hostmodel.cpp
+++ b/src/bench/hostmodel.cpp
@@ -31,7 +31,6 @@
****************************************************************************/
#include "hostmodel.h"
-#include <QDebug>
#include <QIcon>
#include <QSettings>
#include <QMimeData>
diff --git a/src/bench/mainwindow.cpp b/src/bench/mainwindow.cpp
index 15fcdac..0d0bf2e 100644
--- a/src/bench/mainwindow.cpp
+++ b/src/bench/mainwindow.cpp
@@ -51,6 +51,7 @@
#include "options.h"
#include "newprojectwizard.h"
#include "projectmanager.h"
+#include "runtimemanager.h"
class ErrorBar : public QFrame
{
@@ -96,7 +97,7 @@ private:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, m_initialized(false)
- , m_workspace(new WorkspaceView())
+ , m_workspaceView(new WorkspaceView())
, m_log(new LogView(true, this))
, m_hostManager(new HostManager(this))
, m_hostModel(new HostModel(this))
@@ -107,6 +108,7 @@ MainWindow::MainWindow(QWidget *parent)
, m_newProjectWizard(new NewProjectWizard(this))
, m_projectManager(new ProjectManager(this))
, m_imports (nullptr)
+ , m_runtimeManager(new RuntimeManager(this))
{
setupContent();
setupMenuBar();
@@ -121,10 +123,12 @@ MainWindow::MainWindow(QWidget *parent)
setWindowIcon(QIcon("://images/favicon.png"));
m_hub->setFilePublishingActive(true);
- m_node->setWorkspaceView(m_workspace);
+ m_node->setWorkspaceView(m_workspaceView);
- connect(m_workspace, &WorkspaceView::pathActivated, m_hub, &LiveHubEngine::setActivePath);
- connect(m_workspace, &WorkspaceView::pathActivated, m_hostManager, &HostManager::followTreeSelection);
+ m_runtimeManager->setLiveHubEngine(m_hub);
+
+ connect(m_workspaceView, &WorkspaceView::pathActivated, m_hub, &LiveHubEngine::setActivePath);
+ connect(m_workspaceView, &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);
@@ -135,12 +139,19 @@ MainWindow::MainWindow(QWidget *parent)
connect(m_hostManager, &HostManager::logWidgetAdded, this, &MainWindow::onLogWidgetAdded);
connect(m_hostManager, &HostManager::openHostConfig, this, &MainWindow::openPreferences);
connect(m_newProjectWizard, &NewProjectWizard::accepted, this, &MainWindow::newProject);
+ connect(m_workspaceView, &WorkspaceView::pathActivated, m_runtimeManager, &RuntimeManager::setPrimeCurrentFile);
+ connect(m_workspaceView, &WorkspaceView::newRuntimeWindow, m_runtimeManager, &RuntimeManager::newRuntimeWindow);
+ connect(m_workspaceView, &WorkspaceView::initConnectToServer, m_runtimeManager, &RuntimeManager::initConnectToServer);
+ connect(m_runtimeManager, &RuntimeManager::logWidgetAdded, this, &MainWindow::onLogWidgetAdded);
+ connect(m_runtimeManager, &RuntimeManager::logWidgetRemoved, this, &MainWindow::onLogWidgetRemoved);
m_qmlDefaultimportList = m_node->qmlEngine()->importPathList();
}
MainWindow::~MainWindow()
{
+ m_runtimeManager->finishProcesses();
+ delete m_runtimeManager;
}
@@ -155,8 +166,10 @@ void MainWindow::setupContent()
m_ww->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
m_ww->setBackgroundRole(QPalette::Dark);
m_node->setWindowWidget(m_ww);
+ m_ww->setHidden(true);
- setCentralWidget(m_ww);
+ m_workspaceView->setWindowTitle("Workspace");
+ setCentralWidget(m_workspaceView);
}
void MainWindow::onActiveWindowChanged(QQuickWindow *activeWindow)
@@ -177,11 +190,6 @@ void MainWindow::onLogWidgetAdded(QDockWidget *logDock)
void MainWindow::setupWorkspaceView()
{
- m_workspaceDock = new QDockWidget("Workspace", this);
- m_workspaceDock->setObjectName("workspace");
- m_workspaceDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
- m_workspaceDock->setFeatures(QDockWidget::AllDockWidgetFeatures);
-
auto contents = new QWidget;
auto layout = new QVBoxLayout(contents);
layout->setContentsMargins(1, 1, 1, 1);
@@ -212,10 +220,7 @@ void MainWindow::setupWorkspaceView()
m_hub->setWorkspace(m_hub->workspace());
});
- layout->addWidget(m_workspace);
-
- m_workspaceDock->setWidget(contents);
- addDockWidget(Qt::LeftDockWidgetArea, m_workspaceDock);
+ layout->addWidget(m_workspaceView);
}
void MainWindow::setupHostView()
@@ -318,15 +323,9 @@ void MainWindow::setupMenuBar()
#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,
+ view->addAction(tr("Show Containing Folder"), m_workspaceView, &WorkspaceView::goUp,
QKeySequence("Ctrl+Esc"));
#endif
#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
@@ -337,7 +336,6 @@ void MainWindow::setupMenuBar()
m_stayOnTop->setCheckable(true);
view->addSeparator();
- view->addAction(m_workspaceDock->toggleViewAction());
view->addAction(m_hostDock->toggleViewAction());
m_logDockMenu = view->addMenu("Logs");
m_logDockMenu->addAction(m_logDock->toggleViewAction());
@@ -386,7 +384,7 @@ void MainWindow::init()
if (!last.isNull())
activateDocument(last);
else
- m_workspace->activateRootPath();
+ m_workspaceView->activateRootPath();
}
restoreImportPathsFromSettings();
@@ -394,7 +392,9 @@ void MainWindow::init()
m_hostModel->restoreFromSettings(&s);
restoreState(s.value("windowState").toByteArray());
- m_workspace->restoreFromSettings(&s);
+ m_workspaceView->restoreFromSettings(&s);
+ m_runtimeManager->setWorkspace(m_workspacePath);
+ m_runtimeManager->startPrimeRuntime();
m_initialized = true;
}
@@ -454,19 +454,12 @@ void MainWindow::setupToolBar()
m_toolBar->addAction(m_openWorkspace);
m_toolBar->addSeparator();
m_toolBar->addAction(m_refresh);
- m_toolBar->addAction(m_resizeFit);
}
void MainWindow::activateDocument(const LiveDocument &path)
{
- m_workspace->activateDocument(path);
-}
-
-void MainWindow::resizeToFit()
-{
- QSize diff = m_ww->sizeHint() - m_ww->rect().size();
- resize(rect().size() + diff);
- updateWindowTitle();
+ m_workspaceView->activateDocument(path);
+ m_runtimeManager->setPrimeCurrentFile(path);
}
void MainWindow::takeSnapshot()
@@ -498,18 +491,20 @@ void MainWindow::slowDownAnimations(bool enable)
void MainWindow::setWorkspace(const QString& path, bool activateRootPath)
{
m_workspacePath = path;
- m_workspace->setRootPath(path);
+ m_workspaceView->setRootPath(path);
m_node->setWorkspace(path);
m_hub->setWorkspace(path);
m_allHosts->setWorkspace(path);
if (activateRootPath)
- m_workspace->activateRootPath();
+ m_workspaceView->activateRootPath();
+ m_runtimeManager->setWorkspace(path);
updateRecentFolder(path);
}
void MainWindow::setPluginPath(const QString &path)
{
m_node->setPluginPath(path);
+ m_runtimeManager->setPluginPath(path);
}
void MainWindow::setImportPaths(const QStringList &pathList)
@@ -519,6 +514,7 @@ void MainWindow::setImportPaths(const QStringList &pathList)
*m_imports = QSet<QString>::fromList(pathList);
m_node->qmlEngine()->setImportPathList(pathList + m_qmlDefaultimportList);
+ m_runtimeManager->setImportPathList(pathList + m_qmlDefaultimportList);
}
void MainWindow::setStaysOnTop(bool enabled)
@@ -535,6 +531,7 @@ void MainWindow::setProject(const QString &projectFile)
void MainWindow::closeEvent(QCloseEvent *event)
{
writeSettings();
+ m_runtimeManager->finishProcesses();
QMainWindow::closeEvent(event);
}
@@ -551,6 +548,7 @@ void MainWindow::openWorkspace()
return;
}
setWorkspace(path);
+ m_runtimeManager->restartAll();
}
void MainWindow::logQuitEvent()
@@ -572,8 +570,9 @@ void MainWindow::updateWindowTitle()
void MainWindow::openPreferences(Host *host)
{
OptionsDialog dialog;
- connect(&dialog, &OptionsDialog::hideNonQMLFiles, m_workspace, &WorkspaceView::hideNonQMLFiles);
+ connect(&dialog, &OptionsDialog::hideNonQMLFiles, m_workspaceView, &WorkspaceView::hideNonQMLFiles);
connect(&dialog, &OptionsDialog::updateImportPaths, this, &MainWindow::setImportPaths);
+ connect(&dialog, &OptionsDialog::updateRuntimePath, m_runtimeManager, &RuntimeManager::updateRuntimePath);
dialog.setHostModel(m_hostModel);
dialog.setDiscoveredHostsModel(m_discoveryManager->discoveredHostsModel());
dialog.setImports(m_imports->toList());
@@ -674,8 +673,9 @@ void MainWindow::openProjectFile(const QString &path)
setImportPaths(paths);
QString path = QDir(m_projectManager->projectLocation()).absoluteFilePath(m_projectManager->workspace());
- setWorkspace(path);
+ setWorkspace(m_projectManager->workspace());
activateDocument(LiveDocument(m_projectManager->mainDocument()));
+ m_runtimeManager->restartAll();
}
else {
qWarning() << "Unable to read project document: "<<path;
@@ -703,6 +703,12 @@ void MainWindow::newProject()
QString path = QDir(m_projectManager->projectLocation()).absoluteFilePath(m_newProjectWizard->workspace());
setWorkspace(path);
activateDocument(LiveDocument(m_newProjectWizard->mainDocument()));
+ m_runtimeManager->restartAll();
+}
+
+void MainWindow::onLogWidgetRemoved(QDockWidget* logDock)
+{
+ removeDockWidget(logDock);
}
#include "mainwindow.moc"
diff --git a/src/bench/mainwindow.h b/src/bench/mainwindow.h
index 833b53d..9360306 100644
--- a/src/bench/mainwindow.h
+++ b/src/bench/mainwindow.h
@@ -53,6 +53,7 @@ class HostDiscoveryManager;
class Options;
class NewProjectWizard;
class ProjectManager;
+class RuntimeManager;
QT_FORWARD_DECLARE_CLASS(QToolBar);
@@ -93,7 +94,6 @@ private:
void saveImportPathToSettings(const QString& path);
private slots:
- void resizeToFit();
void takeSnapshot();
void slowDownAnimations(bool enable);
void openWorkspace();
@@ -108,6 +108,7 @@ private slots:
void newProject();
void onActiveWindowChanged(QQuickWindow *activeWindow);
void onLogWidgetAdded(QDockWidget* logDock);
+ void onLogWidgetRemoved(QDockWidget* logDock);
private:
void updateRecentFolder(const QString &path = QString());
@@ -115,12 +116,11 @@ private:
private:
bool m_initialized;
WindowWidget *m_ww;
- WorkspaceView *m_workspace;
+ WorkspaceView *m_workspaceView;
QString m_workspacePath;
LogView *m_log;
QUrl m_currentSource;
QDockWidget *m_logDock;
- QDockWidget *m_workspaceDock;
QDockWidget *m_hostDock;
HostManager *m_hostManager;
HostModel *m_hostModel;
@@ -134,7 +134,6 @@ private:
QAction *m_stayOnTop;
QAction *m_openWorkspace;
QAction *m_refresh;
- QAction *m_resizeFit;
QAction *m_clipRootObject;
QToolBar* m_toolBar;
QStringList m_qmlDefaultimportList;
@@ -143,4 +142,5 @@ private:
NewProjectWizard *m_newProjectWizard;
ProjectManager *m_projectManager;
QSet<QString> *m_imports;
+ RuntimeManager *m_runtimeManager;
};
diff --git a/src/bench/options.h b/src/bench/options.h
index 410d6a6..b1e790f 100644
--- a/src/bench/options.h
+++ b/src/bench/options.h
@@ -33,6 +33,7 @@
#pragma once
#include "livedocument.h"
+#include "constants.h"
#include <QtCore>
@@ -44,7 +45,7 @@ public:
struct HostOptions {
QString name;
QString address;
- int port = 10234;
+ int port = Constants::DEFAULT_PORT();
};
public:
diff --git a/src/bench/optionsdialog.cpp b/src/bench/optionsdialog.cpp
index 82c6223..28fb5ae 100644
--- a/src/bench/optionsdialog.cpp
+++ b/src/bench/optionsdialog.cpp
@@ -35,6 +35,7 @@
#include "httpproxyoptionpage.h"
#include "importpathoptionpage.h"
#include "hostsoptionpage.h"
+#include "runtimeoptionpage.h"
#include "appearanceoptionpage.h"
OptionsDialog::OptionsDialog(QWidget *parent)
@@ -44,6 +45,7 @@ OptionsDialog::OptionsDialog(QWidget *parent)
, m_importPathsForm(new ImportPathOptionPage(this))
, m_hostsForm(new HostsOptionsPage(this))
, m_appearanceForm(new AppearanceOptionPage(this))
+ , m_runtimeForm(new RuntimeOptionPage(this))
{
ui->setupUi(this);
@@ -68,8 +70,14 @@ OptionsDialog::OptionsDialog(QWidget *parent)
item->setData(Qt::UserRole, index);
ui->optionsView->addItem(item);
+ item = new QListWidgetItem("QML Live Runtime");
+ index = ui->optionsStack->addWidget(m_runtimeForm);
+ item->setData(Qt::UserRole, index);
+ ui->optionsView->addItem(item);
+
connect(ui->optionsView, &QListWidget::currentItemChanged,
this, &OptionsDialog::optionSelected);
+ connect(m_runtimeForm, &RuntimeOptionPage::updateRuntimePath, this, &OptionsDialog::updateRuntimePath);
connect(m_appearanceForm, &AppearanceOptionPage::hideNonQMLFiles, this, &OptionsDialog::hideNonQMLFiles);
connect(m_importPathsForm, &ImportPathOptionPage::updateImportPaths, this, &OptionsDialog::updateImportPaths);
}
@@ -107,6 +115,7 @@ void OptionsDialog::accept()
m_importPathsForm->apply();
m_hostsForm->apply();
m_appearanceForm->apply();
+ m_runtimeForm->apply();
QDialog::accept();
}
@@ -120,4 +129,3 @@ void OptionsDialog::setImports(const QStringList &imports)
m_importPathsForm->setImports(imports);
}
-
diff --git a/src/bench/optionsdialog.h b/src/bench/optionsdialog.h
index 2e728ce..0016d35 100644
--- a/src/bench/optionsdialog.h
+++ b/src/bench/optionsdialog.h
@@ -47,6 +47,7 @@ class HostsOptionsPage;
class HostModel;
class Host;
class AppearanceOptionPage;
+class RuntimeOptionPage;
class OptionsDialog : public QDialog
{
@@ -65,6 +66,7 @@ public:
signals:
void hideNonQMLFiles(bool hide);
void updateImportPaths(const QStringList &imports);
+ void updateRuntimePath(const QString& path);
private slots:
void optionSelected(QListWidgetItem* current);
@@ -76,5 +78,6 @@ private:
HttpProxyOptionPage *m_httpProxyForm;
ImportPathOptionPage *m_importPathsForm;
HostsOptionsPage *m_hostsForm;
+ RuntimeOptionPage *m_runtimeForm;
AppearanceOptionPage *m_appearanceForm;
};
diff --git a/src/bench/runtimemanager.cpp b/src/bench/runtimemanager.cpp
new file mode 100644
index 0000000..5a29298
--- /dev/null
+++ b/src/bench/runtimemanager.cpp
@@ -0,0 +1,302 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Luxoft Sweden AB
+** 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 "runtimemanager.h"
+#include "widgets/logview.h"
+#include "constants.h"
+
+#include <QDockWidget>
+
+RuntimeManager::RuntimeManager(QObject *parent) : QObject(parent)
+ ,m_port(Constants::DEFAULT_BENCH_PORT())
+ ,m_engine(nullptr)
+ ,m_currentFile(nullptr)
+ ,m_imports(nullptr)
+ ,m_pluginPath(nullptr)
+{
+ m_primeRuntime = new RuntimeProcess(this, Constants::PRIMERUNTIME_PORT(), true);
+ QSettings s;
+ QString path = s.value(Constants::RUNTIME_SETTINGS_KEY()).toString();
+ if (!path.isEmpty()) {
+ m_runtimeBinaryPath = path;
+ } else {
+ // Assuming the qmlliveruntime binary located at the same folder with qmllivebench
+ m_runtimeBinaryPath = Constants::DEFAULT_RUNTIME_LOCATION();
+ }
+ connect(m_primeRuntime, &RuntimeProcess::errorOccurred, this, &RuntimeManager::onPrimeRuntimeError);
+ connect(m_primeRuntime, &RuntimeProcess::stateChanged, this, &RuntimeManager::onPrimeRuntimeChanged);
+ connect(m_primeRuntime, &RuntimeProcess::errorOccurred, this, &RuntimeManager::onError);
+}
+RuntimeManager::~RuntimeManager()
+{
+ finishProcesses();
+}
+
+void RuntimeManager::startPrimeRuntime()
+{
+ QDockWidget *dock =new QDockWidget("PrimeRuntime");
+ dock->setObjectName("PrimeRuntimeLogDock");
+ LogView *view = new LogView(false, dock);
+ connect(m_primeRuntime, &RuntimeProcess::remoteLog, view, &LogView::appendToLog);
+ connect(m_primeRuntime, &RuntimeProcess::clearLog, view, &LogView::clear);
+ connect(m_primeRuntime, &RuntimeProcess::connected, view, &LogView::clear);
+ dock->setWidget(view);
+ emit logWidgetAdded(dock);
+
+ QStringList arguments = argumentsList(Constants::PRIMERUNTIME_PORT(), "Prime QML Live Runtime", true);
+
+ if (m_engine == nullptr) {
+ qWarning() << "Failed to start Prime QML Live Runtime: nullptr QML engine object";
+ return;
+ }
+ m_primeRuntime->setLiveHubEngine(m_engine);
+ m_primeRuntime->start(m_runtimeBinaryPath, arguments);
+}
+
+void RuntimeManager::setRuntimeBinaryPath(const QString &path)
+{
+ m_runtimeBinaryPath = path;
+}
+
+void RuntimeManager::setLiveHubEngine(LiveHubEngine *engine)
+{
+ m_engine = engine;
+}
+
+void RuntimeManager::onPrimeRuntimeError(QProcess::ProcessError error)
+{
+ qWarning()<<"RuntimeManager::onPrimeRuntimeError: "<<error;
+}
+
+void RuntimeManager::setWorkspace(const QString &workspace)
+{
+ m_workspace = workspace;
+ m_primeRuntime->setWorkspace(workspace);
+}
+
+void RuntimeManager::onPrimeRuntimeChanged()
+{
+ switch (m_primeRuntime->state()) {
+ case QProcess::Running:
+ qInfo() << "Prime QML Live Runtime RUNNING";
+ m_primeRuntime->connectToServer();
+ break;
+ case QProcess::Starting:
+ qInfo() << "Prime QML Live Runtime STARTING";
+ break;
+ case QProcess::NotRunning:
+ if (QFileInfo(m_runtimeBinaryPath).exists()) {
+ qWarning() << "Prime QML Live Runtime NOT RUNNING: failed to start qmlliveruntime at: "<<m_runtimeBinaryPath<<" - you may have insufficient permissions to invoke it.";
+ }
+ else {
+ qWarning() << "Prime QML Live Runtime NOT RUNNING: qmlliveruntime is missing at: "<<m_runtimeBinaryPath;
+ qWarning() << "Please specify qmlliveruntime binary location at 'Preferences->QML Live Runtime'";
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void RuntimeManager::setPrimeCurrentFile(const LiveDocument &currentFile)
+{
+ if (!currentFile.isFileIn(m_engine->workspace()) || m_primeRuntime->state() != QProcess::Running)
+ return;
+ m_primeRuntime->setCurrentFile(currentFile);
+}
+
+void RuntimeManager::initConnectToServer(const QString &document)
+{
+ if (m_curproc->state() == QProcess::Running) {
+ m_curproc->connectToServer();
+ }
+}
+
+void RuntimeManager::newRuntimeWindow(const QString &document)
+{
+ m_currentFile = new LiveDocument(document);
+
+ if (m_engine == nullptr) {
+ qWarning() << "Unable to start runtime: QML engine is null";
+ return;
+ }
+
+ m_curproc = new RuntimeProcess(this, m_port);
+
+ QStringList arguments = argumentsList(m_port, m_currentFile->relativeFilePath());
+
+ LiveHubEngine *engine = new LiveHubEngine(this);
+ engine->setMaximumWatches(m_engine->maximumWatches());
+ engine->setWorkspace(m_workspace);
+ engine->setActivePath(*m_currentFile);
+
+ qInfo()<<"ENGINE workspace= "<<engine->workspace()<<" doc = "<<engine->activePath().relativeFilePath()<<" abspath = "<<engine->activePath().absoluteFilePathIn(engine->workspace());
+
+ m_curproc->setLiveHubEngine(engine);
+
+ QDockWidget *dock = new QDockWidget(document);
+ dock->setObjectName(document + "LogDock");
+ m_logDocks.append(dock);
+ LogView *view = new LogView(false, dock);
+
+ connect(m_curproc, &RuntimeProcess::remoteLog, view, &LogView::appendToLog);
+ connect(m_curproc, &RuntimeProcess::clearLog, view, &LogView::clear);
+ connect(m_curproc, &RuntimeProcess::connected, view, &LogView::clear);
+ dock->setWidget(view);
+ emit logWidgetAdded(dock);
+
+ connect(m_curproc, &RuntimeProcess::started, this, &RuntimeManager::onRuntimeStarted);
+ connect(m_curproc, &RuntimeProcess::connected, this, &RuntimeManager::onConnected);
+ connect(m_curproc, &RuntimeProcess::errorOccurred, this, &RuntimeManager::onError);
+
+ m_curproc->start(m_runtimeBinaryPath, arguments);
+}
+
+void RuntimeManager::onConnected()
+{
+ m_curproc->setCurrentFile(*m_currentFile);
+ m_runtimes.append(m_curproc);
+ m_port++;
+}
+
+void RuntimeManager::onRuntimeStarted()
+{
+ m_curproc->connectToServer(1500);
+}
+
+void RuntimeManager::finishProcesses()
+{
+ qInfo() << "RuntimeManager::finishProcesses ---------KILL ALL CHILD PROCESSES__________";
+
+ for (int i = 0; i < m_runtimes.count(); i++) {
+ m_runtimes.at(i)->terminate();
+ if (!m_runtimes.at(i)->waitForFinished(500)) {
+ m_runtimes.at(i)->kill();
+ }
+ }
+
+ if (m_primeRuntime->state() == QProcess::Running || m_primeRuntime->state() == QProcess::Starting){
+ m_primeRuntime->terminate();
+ if (!m_primeRuntime->waitForFinished(100)) {
+ m_primeRuntime->kill();
+ }
+ }
+ delete m_primeRuntime;
+}
+
+QStringList RuntimeManager::argumentsList(const int& port, const QString& title, const bool hideButtons)
+{
+ QStringList arguments;
+ arguments << "--ipcport" << QString::number(port);
+ if (!title.isEmpty()) {
+ arguments << "--title" << title;
+ }
+ if (hideButtons) {
+ arguments << "--hidebuttons";
+ }
+ if (m_pluginPath) {
+ arguments << "--pluginpath" << *m_pluginPath;
+ }
+ if (m_imports) {
+ for (int i = 0; i < m_imports->count(); i++) {
+ arguments << "--importpath" << m_imports->at(i);
+ }
+ }
+ arguments << m_workspace;
+ qInfo() << "ARGUMENTS: " << arguments;
+
+ return arguments;
+}
+
+void RuntimeManager::updateRuntimePath(const QString& path)
+{
+ m_runtimeBinaryPath = path;
+ if (m_primeRuntime->state() == QProcess::NotRunning){
+ restartPrimeRuntime();
+ }
+}
+
+void RuntimeManager::restartPrimeRuntime()
+{
+ QStringList arguments = argumentsList(Constants::PRIMERUNTIME_PORT(), "Prime QML Live Runtime", true);
+
+ if (m_engine == nullptr) {
+ qWarning()<<"Failed to start Prime QML Live Runtime: nullptr QML engine object";
+ return;
+ }
+ if (m_primeRuntime->state() == QProcess::Running) {
+ m_primeRuntime->terminate();
+ }
+ if (!m_primeRuntime->waitForFinished(1000)) {
+ m_primeRuntime->kill();
+ }
+
+ m_primeRuntime->setLiveHubEngine(m_engine);
+ m_primeRuntime->start(m_runtimeBinaryPath, arguments);
+}
+
+void RuntimeManager::onError(QProcess::ProcessError error)
+{
+ qWarning() << "RuntimeManager::onError ProcessError = " << error;
+}
+
+void RuntimeManager::setPluginPath(const QString& path)
+{
+ if (!m_pluginPath) {
+ m_pluginPath = new QString(path);
+ } else {
+ *m_pluginPath = path;
+ }
+}
+
+void RuntimeManager::setImportPathList(const QStringList& paths)
+{
+ if (!m_imports) {
+ m_imports = new QStringList(paths);
+ } else {
+ *m_imports = paths;
+ }
+}
+
+void RuntimeManager::restartAll()
+{
+ for (int i = 0; i < m_runtimes.count(); i++) {
+ m_runtimes.at(i)->terminate();
+ if (!m_runtimes.at(i)->waitForFinished(500)) {
+ m_runtimes.at(i)->kill();
+ }
+ }
+ for (int i = 0; i < m_logDocks.count(); i++) {
+ emit logWidgetRemoved(m_logDocks.at(i));
+ }
+
+ restartPrimeRuntime();
+}
diff --git a/src/bench/runtimemanager.h b/src/bench/runtimemanager.h
new file mode 100644
index 0000000..d0cf393
--- /dev/null
+++ b/src/bench/runtimemanager.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Luxoft Sweden AB
+** 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
+**
+****************************************************************************/
+
+#ifndef RUNTIMEMANAGER_H
+#define RUNTIMEMANAGER_H
+
+#include <QObject>
+#include <QProcess>
+#include "livehubengine.h"
+#include "runtimeprocess.h"
+
+QT_FORWARD_DECLARE_CLASS(QDockWidget);
+
+class RuntimeManager : public QObject
+{
+ Q_OBJECT
+public:
+ explicit RuntimeManager(QObject *parent = nullptr);
+ ~RuntimeManager();
+
+ void startPrimeRuntime();
+ void setRuntimeBinaryPath(const QString &path);
+ void setLiveHubEngine(LiveHubEngine *engine);
+ void setWorkspace(const QString &workspace);
+ void finishProcesses();
+ void setPluginPath(const QString& path);
+ void setImportPathList(const QStringList& paths);
+ void restartAll();
+
+private:
+ QStringList argumentsList(const int& port, const QString& titles, const bool hideButtons = false);
+
+signals:
+ void logWidgetAdded(QDockWidget* log);
+ void logWidgetRemoved(QDockWidget* log);
+
+public slots:
+ void onPrimeRuntimeError(QProcess::ProcessError error);
+ void onPrimeRuntimeChanged();
+ void setPrimeCurrentFile(const LiveDocument &currentFile);
+ void newRuntimeWindow(const QString &document);
+ void initConnectToServer(const QString &document);
+ void onConnected();
+ void onRuntimeStarted();
+ void updateRuntimePath(const QString& path);
+ void restartPrimeRuntime();
+ void onError(QProcess::ProcessError error);
+
+private:
+ int m_port;
+ QString m_runtimeBinaryPath;
+ QString m_workspace;
+ RuntimeProcess *m_primeRuntime; //this prime runtime supposed to be QML Live runtime which follows the activeDocumetChanged Slot
+ LiveHubEngine *m_engine;
+ LiveDocument* m_currentFile;
+ RuntimeProcess* m_curproc;
+ QStringList* m_imports;
+ QString* m_pluginPath;
+ QList<QDockWidget*> m_logDocks;
+ QList<RuntimeProcess*> m_runtimes;
+};
+
+#endif // RUNTIMEMANAGER_H
diff --git a/src/bench/runtimeoptionpage.cpp b/src/bench/runtimeoptionpage.cpp
new file mode 100644
index 0000000..9e9b5a1
--- /dev/null
+++ b/src/bench/runtimeoptionpage.cpp
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Luxoft Sweden AB
+** 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 "runtimeoptionpage.h"
+#include "ui_runtimeoptionpage.h"
+#include "constants.h"
+
+#include <QFileDialog>
+#include <QPushButton>
+
+RuntimeOptionPage::RuntimeOptionPage(QWidget *parent) :
+ QWidget(parent),
+ ui(new Ui::RuntimeOptionPage)
+{
+ ui->setupUi(this);
+
+ QSettings s;
+ if (s.value(Constants::RUNTIME_SETTINGS_KEY()).toString().isEmpty()) {
+ QDir(QCoreApplication::applicationDirPath()).absoluteFilePath("qmlliveruntime");
+ } else {
+ ui->runtimePathText->setText(s.value(Constants::RUNTIME_SETTINGS_KEY()).toString());
+ }
+
+ ui->warningLabel->setText("");
+ QPalette palette = ui->warningLabel->palette();
+ palette.setColor(ui->warningLabel->backgroundRole(), Qt::yellow);
+ palette.setColor(ui->warningLabel->foregroundRole(), Qt::yellow);
+ ui->warningLabel->setPalette(palette);
+
+ connect(ui->select, &QPushButton::clicked, this, &RuntimeOptionPage::selectRuntimePath);
+}
+
+RuntimeOptionPage::~RuntimeOptionPage()
+{
+ delete ui;
+}
+
+void RuntimeOptionPage::selectRuntimePath()
+{
+ ui->warningLabel->setText("");
+ QString runtimePath = QFileDialog::getOpenFileName(this, "Select QML Live runtime");
+ if (!runtimePath.isEmpty() && ui->runtimePathText) {
+ ui->runtimePathText->setText(runtimePath);
+ }
+}
+
+bool RuntimeOptionPage::apply()
+{
+ QString path = ui->runtimePathText->text();
+
+ if (QFileInfo(path).exists()) {
+ ui->warningLabel->setText("");
+ QSettings s;
+ s.setValue(Constants::RUNTIME_SETTINGS_KEY(), path);
+ emit updateRuntimePath(path);
+ return true;
+ } else {
+ ui->warningLabel->setText("File doesn't exist.");
+ return false;
+ }
+}
diff --git a/src/bench/runtimeoptionpage.h b/src/bench/runtimeoptionpage.h
new file mode 100644
index 0000000..b412a11
--- /dev/null
+++ b/src/bench/runtimeoptionpage.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Luxoft Sweden AB
+** 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
+**
+****************************************************************************/
+
+#ifndef RUNTIMEOPTIONPAGE_H
+#define RUNTIMEOPTIONPAGE_H
+
+#include <QtCore>
+#include <QtGui>
+#include <QtWidgets>
+
+QT_BEGIN_NAMESPACE
+namespace Ui {
+class RuntimeOptionPage;
+}
+QT_END_NAMESPACE
+
+class RuntimeOptionPage : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit RuntimeOptionPage(QWidget *parent = nullptr);
+ ~RuntimeOptionPage();
+
+ bool apply();
+
+Q_SIGNALS:
+ void updateRuntimePath(const QString& path);
+
+private Q_SLOTS:
+ void selectRuntimePath();
+
+private:
+ Ui::RuntimeOptionPage *ui;
+};
+
+#endif // RUNTIMEOPTIONPAGE_H
diff --git a/src/bench/runtimeoptionpage.ui b/src/bench/runtimeoptionpage.ui
new file mode 100644
index 0000000..040aa82
--- /dev/null
+++ b/src/bench/runtimeoptionpage.ui
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>RuntimeOptionPage</class>
+ <widget class="QWidget" name="RuntimeOptionPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>643</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <widget class="QPushButton" name="select">
+ <property name="geometry">
+ <rect>
+ <x>420</x>
+ <y>10</y>
+ <width>114</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Select</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" name="runtimePathText">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>10</y>
+ <width>400</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="placeholderText">
+ <string extracomment="/opt/Qt/"/>
+ </property>
+ </widget>
+ <widget class="QLabel" name="warningLabel">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>40</y>
+ <width>381</width>
+ <height>16</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/bench/runtimeprocess.cpp b/src/bench/runtimeprocess.cpp
new file mode 100644
index 0000000..7c762c6
--- /dev/null
+++ b/src/bench/runtimeprocess.cpp
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Luxoft Sweden AB
+** 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 "runtimeprocess.h"
+#include "livehubengine.h"
+
+RuntimeProcess::RuntimeProcess(QObject *parent, int port, bool ismaster) :
+ QProcess(parent)
+ ,m_ismaster(ismaster)
+ ,m_port(port)
+ ,m_engine(nullptr)
+ ,m_document(nullptr)
+{
+ connect(&m_publisher, &RemotePublisher::connected, this, &RuntimeProcess::connected);
+ connect(&m_publisher, &RemotePublisher::connected, this, &RuntimeProcess::onConnected);
+ connect(&m_publisher, &RemotePublisher::disconnected, this, &RuntimeProcess::onDisconnected);
+ connect(&m_publisher, &RemotePublisher::connectionError, this, &RuntimeProcess::onConnectionError);
+ connect(&m_publisher, &RemotePublisher::remoteLog, this, &RuntimeProcess::remoteLog);
+ connect(&m_publisher, &RemotePublisher::clearLog, this, &RuntimeProcess::clearLog);
+
+ //transmit log messages to appropriate LogView
+ connect(this, &RuntimeProcess::readyReadStandardError, this, &RuntimeProcess::updateErrors);
+ connect(this, &RuntimeProcess::readyReadStandardOutput, this, &RuntimeProcess::updateOutput);
+}
+
+RuntimeProcess::~RuntimeProcess()
+{
+ exit(QProcess::NormalExit);
+}
+
+void RuntimeProcess::setCurrentFile(const LiveDocument &currentFile)
+{
+ if (m_document == nullptr) {
+ m_document = new LiveDocument(currentFile);
+ } else {
+ *m_document = currentFile;
+ }
+ if (m_publisher.state() != QAbstractSocket::ConnectedState) {
+ qWarning()<<"RuntimeProcess::setCurrentFile failed: RemotePublisher is not connected";
+ return;
+ }
+
+ m_publisher.activateDocument(currentFile);
+}
+
+void RuntimeProcess::setWorkspace(const QString &workspace)
+{
+ m_publisher.setWorkspace(workspace);
+}
+
+void RuntimeProcess::setLiveHubEngine(LiveHubEngine *engine)
+{
+ m_engine = engine;
+
+ m_publisher.setWorkspace(m_engine->workspace());
+
+ connect(m_engine.data(), &LiveHubEngine::workspaceChanged, &m_publisher, &RemotePublisher::setWorkspace);
+ if (m_ismaster) {
+ connect(m_engine.data(), &LiveHubEngine::fileChanged, &m_publisher, &RemotePublisher::activateDocument);
+ }
+
+ connect(m_engine.data(), &LiveHubEngine::activateDocument, &m_publisher, &RemotePublisher::activateDocument);
+ connect(m_engine.data(), &LiveHubEngine::beginPublishWorkspace, &m_publisher, &RemotePublisher::beginBulkSend);
+ connect(m_engine.data(), &LiveHubEngine::endPublishWorkspace, &m_publisher, &RemotePublisher::endBulkSend);
+}
+
+void RuntimeProcess::connectToServer()
+{
+ qInfo()<<"RuntimeProcess::connectToServer()"<< Constants::LOCAL_HOST() <<
+ " port=" << m_port << m_publisher.state();
+
+ if (m_publisher.state() != QAbstractSocket::UnconnectedState)
+ return;
+
+ m_publisher.connectToServer(Constants::LOCAL_HOST(), m_port);
+}
+
+void RuntimeProcess::connectToServer(int msecs)
+{
+ qInfo()<<"RuntimeProcess::connectToServer(msecs)"<< Constants::LOCAL_HOST() <<
+ " port=" << m_port << m_publisher.state();
+ QThread::msleep(msecs);
+
+ if (m_publisher.state() != QAbstractSocket::UnconnectedState)
+ return;
+
+ m_publisher.connectToServer(Constants::LOCAL_HOST(), m_port, msecs);
+}
+
+void RuntimeProcess::onConnected()
+{
+ if (m_publisher.state() == QAbstractSocket::ConnectedState) {
+ m_publisher.activateDocument(m_engine->activePath());
+ }
+}
+
+void RuntimeProcess::onDisconnected()
+{
+ qInfo()<<"RuntimeProcess::onDisconnected ismater="<<m_ismaster;
+ if (m_ismaster){
+ connectToServer();
+ }
+}
+void RuntimeProcess::onConnectionError(QAbstractSocket::SocketError error)
+{
+ qWarning()<<"RuntimeProcess::onConnectionError: Host connection error: "<<error;
+
+ if (m_publisher.state() != QAbstractSocket::ConnectedState)
+ onDisconnected();
+}
+
+void RuntimeProcess::sendDocument(const LiveDocument &document)
+{
+ if (m_document == nullptr) {
+ m_document = new LiveDocument(document);
+ } else {
+ *m_document = document;
+ }
+
+ if (m_publisher.state() != QAbstractSocket::ConnectedState)
+ return;
+}
+
+void RuntimeProcess::updateErrors()
+{
+ QByteArray log = readAllStandardError();
+ qWarning() << "RuntimeProcess::updateErrors --> " << log.data();
+ emit remoteLog(QtCriticalMsg, log.data());
+}
+
+void RuntimeProcess::updateOutput()
+{
+ QByteArray log = readAllStandardOutput();
+ emit remoteLog(QtInfoMsg, log.data());
+}
diff --git a/src/bench/runtimeprocess.h b/src/bench/runtimeprocess.h
new file mode 100644
index 0000000..5e1a01b
--- /dev/null
+++ b/src/bench/runtimeprocess.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Luxoft Sweden AB
+** 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
+**
+****************************************************************************/
+
+#ifndef RUNTIMEPROCESS_H
+#define RUNTIMEPROCESS_H
+
+#include "constants.h"
+#include <QProcess>
+#include <remotepublisher.h>
+
+class RuntimeProcess : public QProcess
+{
+ Q_OBJECT
+public:
+ explicit RuntimeProcess(QObject *parent = nullptr, int port = Constants::DEFAULT_BENCH_PORT(), bool ismaster = false);
+ ~RuntimeProcess();
+
+ void setCurrentFile(const LiveDocument &currentFile);
+ void setWorkspace(const QString &workspace);
+ void setLiveHubEngine(LiveHubEngine *engine);
+ void connectToServer();
+ void connectToServer(int msecs);
+
+Q_SIGNALS:
+ void connected();
+ void remoteLog(int type, const QString &msg, const QUrl &url = QUrl(), int line = -1, int column = -1);
+ void clearLog();
+
+private Q_SLOTS:
+ void onConnected();
+ void onDisconnected();
+ void onConnectionError(QAbstractSocket::SocketError error);
+ void sendDocument(const LiveDocument &document);
+ void updateOutput();
+ void updateErrors();
+
+private:
+ bool m_ismaster;
+ int m_port;
+ int m_waitToConnect;
+ RemotePublisher m_publisher;
+ QPointer<LiveHubEngine> m_engine;
+ LiveDocument *m_document;
+};
+
+#endif // RUNTIMEPROCESS_H
diff --git a/src/constants.cpp b/src/constants.cpp
new file mode 100644
index 0000000..efbd15e
--- /dev/null
+++ b/src/constants.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QML Live 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 "constants.h"
+
+int Constants::PRIMERUNTIME_PORT()
+{
+ return 49155;
+}
+
+int Constants::DEFAULT_PORT()
+{
+ return 49156;
+}
+
+int Constants::DEFAULT_BENCH_PORT()
+{
+ return 49355;
+}
+
+QString Constants::RUNTIME_SETTINGS_KEY()
+{
+ return "runtime/path";
+}
+
+QString Constants::DEFAULT_RUNTIME_LOCATION()
+{
+ return QDir(QDir(QCoreApplication::applicationDirPath()).canonicalPath()).absoluteFilePath("qmlliveruntime");
+}
+
+QString Constants::LOCAL_HOST()
+{
+ return "127.0.0.1";
+}
diff --git a/src/constants.h b/src/constants.h
new file mode 100644
index 0000000..b9ae0fb
--- /dev/null
+++ b/src/constants.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QML Live 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 Constants
+{
+public:
+ static int PRIMERUNTIME_PORT();
+ static int DEFAULT_PORT();
+ static int DEFAULT_BENCH_PORT();
+ static QString RUNTIME_SETTINGS_KEY();
+ static QString DEFAULT_RUNTIME_LOCATION();
+ static QString LOCAL_HOST();
+};
+
diff --git a/src/ipc/ipcclient.cpp b/src/ipc/ipcclient.cpp
index dfc632b..6fc58e3 100644
--- a/src/ipc/ipcclient.cpp
+++ b/src/ipc/ipcclient.cpp
@@ -61,7 +61,7 @@ public:
* Here is a simple example:
* \code
* IpcClient *client = new IpcClient(this);
- * client->connectToServer("127.0.0.1", 10234);
+ * client->connectToServer("127.0.0.1", Constants.DEFAULT_PORT());
* QString text = "Hello";
* QByteArray content;
* QDataStream out(&bytes, QIODevice::WriteOnly);
@@ -102,6 +102,7 @@ IpcClient::IpcClient(QTcpSocket *socket, QObject *parent)
, m_written(0)
, m_connection(0)
{
+ qInfo() << "IpcClient socket: " << socket;
connect(m_socket, &QAbstractSocket::connected, this, &IpcClient::connected);
connect(m_socket, &QAbstractSocket::disconnected, this, &IpcClient::disconnected);
void (QAbstractSocket::*QAbstractSocket__error)(QAbstractSocket::SocketError) = &QAbstractSocket::error;
@@ -122,10 +123,22 @@ QAbstractSocket::SocketState IpcClient::state() const
*/
void IpcClient::connectToServer(const QString &hostName, int port)
{
+ qInfo() << "IpcClient::connectToServer: hostName = " << hostName << " port = " << port;
m_socket->connectToHost(hostName, port);
}
/*!
+ * Sets the Ip address to \a hostName and port to \a port to use for an IPC call and
+ * waits until the socket is connected, up to \a msecs milliseconds.
+ */
+void IpcClient::connectToServer(const QString &hostName, int port, int msecs)
+{
+ qInfo() << "IpcClient::connectToServer: hostName = " << hostName << " port = " << port <<" msecs = " << msecs;
+ m_socket->connectToHost(hostName, port);
+ if (m_socket->waitForConnected(msecs)) qInfo() <<"Connected after waiting for: "<<msecs;
+}
+
+/*!
* Send call to server given by destination
*
* Expects the \a method to be in the form of "echo(QString)" and uses \a data as the content of the arguments
diff --git a/src/ipc/ipcclient.h b/src/ipc/ipcclient.h
index f12fd9b..7ab3d1f 100644
--- a/src/ipc/ipcclient.h
+++ b/src/ipc/ipcclient.h
@@ -48,6 +48,7 @@ public:
QAbstractSocket::SocketState state() const;
void connectToServer(const QString& hostName, int port);
+ void connectToServer(const QString &hostName, int port, int msecs);
QUuid send(const QString& method, const QByteArray& data);
bool waitForConnected(int msecs = 30000);
diff --git a/src/ipc/ipcserver.cpp b/src/ipc/ipcserver.cpp
index c54a70e..fed2c8a 100644
--- a/src/ipc/ipcserver.cpp
+++ b/src/ipc/ipcserver.cpp
@@ -51,7 +51,7 @@
* \code{.cpp}
* m_server = new IpcServer(this);
* connect(m_server, &IpcServer::received, this, &MyHandler::handleCall);
- * m_server->listen(10234);
+ * m_server->listen(Constants.DEFAULT_PORT());
*
* ...
*
diff --git a/src/livedocument.cpp b/src/livedocument.cpp
index 6c42711..39a2f39 100644
--- a/src/livedocument.cpp
+++ b/src/livedocument.cpp
@@ -63,6 +63,7 @@ LiveDocument::LiveDocument(const QString &relativeFilePath)
LIVE_ASSERT(QDir::isRelativePath(relativeFilePath), return);
LIVE_ASSERT(!QDir::cleanPath(relativeFilePath).startsWith(QLatin1String("../")), return);
+ qInfo() << "LiveDocument::LiveDocument: relativeFilePath= " << relativeFilePath;
m_relativeFilePath = relativeFilePath;
}
diff --git a/src/livenodeengine.cpp b/src/livenodeengine.cpp
index 6426fb2..bff1f9c 100644
--- a/src/livenodeengine.cpp
+++ b/src/livenodeengine.cpp
@@ -330,7 +330,6 @@ void LiveNodeEngine::usePreloadedDocument(const QString &document, QQuickWindow
void LiveNodeEngine::loadDocument(const LiveDocument& document)
{
DEBUG << "LiveNodeEngine::loadDocument: " << document;
-
LiveDocument oldActiveFile = m_activeFile;
m_activeFile = document;
diff --git a/src/remotepublisher.cpp b/src/remotepublisher.cpp
index f4f37eb..577dfbc 100644
--- a/src/remotepublisher.cpp
+++ b/src/remotepublisher.cpp
@@ -117,6 +117,15 @@ void RemotePublisher::connectToServer(const QString &hostName, int port)
}
/*!
+ * Set IPC destination to use \a hostName and \a port, waits until the socket is connected, up to \a msecs milliseconds
+ * \sa IpcClient::connectToServer
+ */
+void RemotePublisher::connectToServer(const QString &hostName, int port, int msecs)
+{
+ m_ipc->connectToServer(hostName, port, msecs);
+}
+
+/*!
Converts the socket error \a error into a string
*/
QString RemotePublisher::errorToString(QAbstractSocket::SocketError error)
diff --git a/src/remotepublisher.h b/src/remotepublisher.h
index 11c8460..f80606a 100644
--- a/src/remotepublisher.h
+++ b/src/remotepublisher.h
@@ -47,6 +47,7 @@ class QMLLIVESHARED_EXPORT RemotePublisher : public QObject
public:
explicit RemotePublisher(QObject *parent = 0);
void connectToServer(const QString& hostName, int port);
+ void connectToServer(const QString &hostName, int port, int msecs);
QString errorToString(QAbstractSocket::SocketError error);
QAbstractSocket::SocketState state() const;
diff --git a/src/remotereceiver.cpp b/src/remotereceiver.cpp
index 7ab7457..5bfb3a7 100644
--- a/src/remotereceiver.cpp
+++ b/src/remotereceiver.cpp
@@ -103,6 +103,7 @@ RemoteReceiver::RemoteReceiver(QObject *parent)
*/
bool RemoteReceiver::listen(int port, ConnectionOptions options)
{
+ qInfo() << "RemoteReceiver::listen: port = " << port << " options = " << options;
m_connectionOptions = options;
m_server->listen(port);
diff --git a/src/runtime/main.cpp b/src/runtime/main.cpp
index a102e28..fdda1e1 100644
--- a/src/runtime/main.cpp
+++ b/src/runtime/main.cpp
@@ -39,29 +39,36 @@
#include "logger.h"
#include "qmlhelper.h"
#include "qmllive_version.h"
+#include "constants.h"
struct Options
{
Options()
- : ipcPort(10234)
- , updatesAsOverlay(false)
+ : updatesAsOverlay(false)
, updateOnConnect(false)
, fullscreen(false)
, transparent(false)
, frameless(false)
, stayontop(false)
- {}
- int ipcPort;
+ , hideButtons(false)
+ , windowTitle("QML Live Runtime")
+ {
+ ipcPort = Constants::DEFAULT_PORT();
+ }
+
bool updatesAsOverlay;
bool updateOnConnect;
- QString activeDocument;
- QString workspace;
- QString pluginPath;
- QStringList importPaths;
bool fullscreen;
bool transparent;
bool frameless;
bool stayontop;
+ bool hideButtons;
+ QString windowTitle;
+ QString activeDocument;
+ QString workspace;
+ QString pluginPath;
+ QStringList importPaths;
+ int ipcPort;
};
static Options options;
@@ -76,7 +83,7 @@ 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", QString("the port the IPC shall listen on, default is %1").arg(Constants::DEFAULT_PORT()), "ipcport");
parser.addOption(ipcPortOption);
QCommandLineOption pluginPathOption("pluginpath", "path to QML Live plugins", "pluginpath");
@@ -104,6 +111,12 @@ static void parseArguments(const QStringList &arguments)
QCommandLineOption framelessOption("frameless", "run with no window frame");
parser.addOption(framelessOption);
+ QCommandLineOption windowTitleOption("title", "set window title");
+ parser.addOption(windowTitleOption);
+
+ QCommandLineOption hideButtonsOption("hidebuttons", "hide window control buttons (close, minimize, maximize)");
+ parser.addOption(hideButtonsOption);
+
parser.process(arguments);
if (parser.isSet(ipcPortOption)) {
@@ -117,10 +130,14 @@ static void parseArguments(const QStringList &arguments)
options.fullscreen = parser.isSet(fullScreenOption);
options.transparent = parser.isSet(transparentOption);
options.frameless = parser.isSet(framelessOption);
+ options.windowTitle = parser.isSet(windowTitleOption);
+ options.hideButtons = parser.isSet(hideButtonsOption);
QStringList positionalArguments = parser.positionalArguments();
if (positionalArguments.count() == 1)
options.workspace = positionalArguments.value(0);
+ if (positionalArguments.count() == 2)
+ options.workspace = positionalArguments.value(1);
}
class RuntimeLiveNodeEngine : public LiveNodeEngine
@@ -160,6 +177,10 @@ private slots:
if (options.fullscreen) {
activeWindow->setWindowState(Qt::WindowFullScreen);
}
+
+ if (options.hideButtons) {
+ activeWindow->setFlags(activeWindow->flags() | Qt::WindowMinMaxButtonsHint);
+ }
}
};
@@ -172,6 +193,8 @@ int main(int argc, char** argv)
parseArguments(app.arguments());
+ app.setApplicationName(options.windowTitle);
+
QQmlEngine qmlEngine;
qmlEngine.setImportPathList(options.importPaths + qmlEngine.importPathList());
diff --git a/src/src.pri b/src/src.pri
index 2a4c648..e730078 100644
--- a/src/src.pri
+++ b/src/src.pri
@@ -7,6 +7,7 @@ INCLUDEPATH += $${PWD}
DEFINES += NO_LIBRSYNC
SOURCES += \
+ $$PWD/constants.cpp \
$$PWD/overlay.cpp \
$$PWD/watcher.cpp \
$$PWD/livedocument.cpp \
@@ -39,6 +40,7 @@ public_headers += \
$$PWD/projectmanager.h
HEADERS += \
+ $$PWD/constants.h \
$$PWD/overlay.h \
$$public_headers \
$$PWD/qmllive_version.h \
diff --git a/src/widgets/workspaceview.cpp b/src/widgets/workspaceview.cpp
index e147a78..93b26ea 100644
--- a/src/widgets/workspaceview.cpp
+++ b/src/widgets/workspaceview.cpp
@@ -79,6 +79,11 @@ WorkspaceView::WorkspaceView(QWidget *parent)
m_view->setDragEnabled(true);
m_view->setDragDropMode(QAbstractItemView::DragOnly);
+
+ m_view->setContextMenuPolicy(Qt::ActionsContextMenu);
+ m_newWindow = new QAction(tr("Open in New Window"), this);
+ connect(m_newWindow, &QAction::triggered, this, &WorkspaceView::onNewRuntimeWindow);
+ m_view->addAction(m_newWindow);
}
/*!
@@ -95,7 +100,6 @@ void WorkspaceView::setRootPath(const QString &dirPath)
*/
void WorkspaceView::activateDocument(const LiveDocument &path)
{
- //qDebug() << "WorkspaceView::activateDocument" << path;
QModelIndex index = m_model->index(path.absoluteFilePathIn(rootPath()));
selectIndex(index);
}
@@ -170,6 +174,17 @@ void WorkspaceView::selectIndex(const QModelIndex &index)
//m_view->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
}
+void WorkspaceView::onNewRuntimeWindow()
+{
+ QString path = m_model->rootDirectory().relativeFilePath(m_model->filePath(m_view->currentIndex()));
+ qInfo() << "Opening new QML Live Runtime with file path: " << path;
+ emit newRuntimeWindow(path);
+}
+void WorkspaceView::onConnectToServer()
+{
+ emit initConnectToServer(m_view->model()->data(m_view->currentIndex()).toString());
+}
+
void WorkspaceView::restoreFromSettings(QSettings *s)
{
hideNonQMLFiles(s->value("only_qml_files/enabled").toBool());
diff --git a/src/widgets/workspaceview.h b/src/widgets/workspaceview.h
index dd2df34..3360bb5 100644
--- a/src/widgets/workspaceview.h
+++ b/src/widgets/workspaceview.h
@@ -56,10 +56,14 @@ public Q_SLOTS:
void activateDocument(const LiveDocument& path);
void activateRootPath();
void goUp();
+ void onNewRuntimeWindow();
+ void onConnectToServer();
void hideNonQMLFiles(bool hide);
Q_SIGNALS:
void pathActivated(const LiveDocument& path);
+ void newRuntimeWindow(const QString &document);
+ void initConnectToServer(const QString &document);
private Q_SLOTS:
void indexActivated(const QModelIndex& index);
@@ -70,4 +74,6 @@ private:
FileSystemModel *m_model;
QModelIndex m_rootIndex;
LiveDocument m_currentDocument;
+ QAction *m_newWindow;
+ QAction *m_connect;
};