Merge PR #465: Add support for autosaving in the script editor
This commit is contained in:
commit
4a6f52271e
@ -107,6 +107,7 @@
|
|||||||
#include "scriptmanager.h"
|
#include "scriptmanager.h"
|
||||||
#include "scripting/codecompletion.h"
|
#include "scripting/codecompletion.h"
|
||||||
#include "scripting/completionmodel.h"
|
#include "scripting/completionmodel.h"
|
||||||
|
#include "scripting/scriptautosaver.h"
|
||||||
#include "types/script.h"
|
#include "types/script.h"
|
||||||
#include "types/scripts.h"
|
#include "types/scripts.h"
|
||||||
#include "types/types.h"
|
#include "types/types.h"
|
||||||
@ -310,6 +311,7 @@ void registerQmlTypes() {
|
|||||||
qmlRegisterType<ScriptSyntaxHighlighter>(uri, 1, 0, "ScriptSyntaxHighlighter");
|
qmlRegisterType<ScriptSyntaxHighlighter>(uri, 1, 0, "ScriptSyntaxHighlighter");
|
||||||
qmlRegisterType<CodeCompletion>(uri, 1, 0, "CodeCompletion");
|
qmlRegisterType<CodeCompletion>(uri, 1, 0, "CodeCompletion");
|
||||||
qmlRegisterUncreatableType<CompletionProxyModel>(uri, 1, 0, "CompletionModel", "Get it from ScriptSyntaxHighlighter");
|
qmlRegisterUncreatableType<CompletionProxyModel>(uri, 1, 0, "CompletionModel", "Get it from ScriptSyntaxHighlighter");
|
||||||
|
qmlRegisterType<ScriptAutoSaver>(uri, 1, 0, "ScriptAutoSaver");
|
||||||
|
|
||||||
qmlRegisterType<UserManager>(uri, 1, 0, "UserManager");
|
qmlRegisterType<UserManager>(uri, 1, 0, "UserManager");
|
||||||
qmlRegisterUncreatableType<UserInfo>(uri, 1, 0, "UserInfo", "Get it from UserManager");
|
qmlRegisterUncreatableType<UserInfo>(uri, 1, 0, "UserInfo", "Get it from UserManager");
|
||||||
|
|||||||
@ -33,6 +33,7 @@ SOURCES += \
|
|||||||
ruletemplates/calendaritemtemplate.cpp \
|
ruletemplates/calendaritemtemplate.cpp \
|
||||||
ruletemplates/timedescriptortemplate.cpp \
|
ruletemplates/timedescriptortemplate.cpp \
|
||||||
ruletemplates/timeeventitemtemplate.cpp \
|
ruletemplates/timeeventitemtemplate.cpp \
|
||||||
|
scripting/scriptautosaver.cpp \
|
||||||
types/browseritem.cpp \
|
types/browseritem.cpp \
|
||||||
types/browseritems.cpp \
|
types/browseritems.cpp \
|
||||||
types/networkdevice.cpp \
|
types/networkdevice.cpp \
|
||||||
@ -170,6 +171,7 @@ HEADERS += \
|
|||||||
ruletemplates/calendaritemtemplate.h \
|
ruletemplates/calendaritemtemplate.h \
|
||||||
ruletemplates/timedescriptortemplate.h \
|
ruletemplates/timedescriptortemplate.h \
|
||||||
ruletemplates/timeeventitemtemplate.h \
|
ruletemplates/timeeventitemtemplate.h \
|
||||||
|
scripting/scriptautosaver.h \
|
||||||
types/browseritem.h \
|
types/browseritem.h \
|
||||||
types/browseritems.h \
|
types/browseritems.h \
|
||||||
types/networkdevice.h \
|
types/networkdevice.h \
|
||||||
|
|||||||
@ -530,7 +530,7 @@ void CodeCompletion::update()
|
|||||||
BlockInfo blockInfo = getBlockInfo(m_cursor.position());
|
BlockInfo blockInfo = getBlockInfo(m_cursor.position());
|
||||||
|
|
||||||
// If we're inside a class, add properties
|
// If we're inside a class, add properties
|
||||||
qDebug() << "Block name" << blockInfo.name;
|
// qDebug() << "Block name" << blockInfo.name;
|
||||||
|
|
||||||
if (!blockInfo.name.isEmpty()) {
|
if (!blockInfo.name.isEmpty()) {
|
||||||
foreach (const QString &s, m_classes.value(blockInfo.name).properties) {
|
foreach (const QString &s, m_classes.value(blockInfo.name).properties) {
|
||||||
@ -561,7 +561,7 @@ void CodeCompletion::update()
|
|||||||
m_model->update(entries);
|
m_model->update(entries);
|
||||||
blockText.remove(QRegExp(".* "));
|
blockText.remove(QRegExp(".* "));
|
||||||
m_proxy->setFilter(blockText);
|
m_proxy->setFilter(blockText);
|
||||||
qDebug() << "Model has" << m_model->rowCount() << "Filtered:" << m_proxy->rowCount() << "filter:" << blockText;
|
// qDebug() << "Model has" << m_model->rowCount() << "Filtered:" << m_proxy->rowCount() << "filter:" << blockText;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
114
libnymea-app/scripting/scriptautosaver.cpp
Normal file
114
libnymea-app/scripting/scriptautosaver.cpp
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#include "scriptautosaver.h"
|
||||||
|
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
ScriptAutoSaver::ScriptAutoSaver(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptAutoSaver::~ScriptAutoSaver()
|
||||||
|
{
|
||||||
|
storeContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptAutoSaver::classBegin()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptAutoSaver::componentComplete()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScriptAutoSaver::available() const
|
||||||
|
{
|
||||||
|
return m_cacheFile.isOpen();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScriptAutoSaver::active() const
|
||||||
|
{
|
||||||
|
return m_active;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptAutoSaver::setActive(bool active)
|
||||||
|
{
|
||||||
|
if (m_active != active) {
|
||||||
|
m_active = active;
|
||||||
|
emit activeChanged();
|
||||||
|
|
||||||
|
storeContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QUuid ScriptAutoSaver::scriptId() const
|
||||||
|
{
|
||||||
|
return m_scriptId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptAutoSaver::setScriptId(const QUuid &scriptId)
|
||||||
|
{
|
||||||
|
if (m_scriptId != scriptId) {
|
||||||
|
m_scriptId = scriptId;
|
||||||
|
emit scriptIdChanged();
|
||||||
|
|
||||||
|
if (m_cacheFile.isOpen()) {
|
||||||
|
m_cacheFile.close();
|
||||||
|
emit availableChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString path = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/scripts/";
|
||||||
|
QDir dir(path);
|
||||||
|
if (!dir.exists() && !dir.mkpath(path)) {
|
||||||
|
qWarning() << "Cannot create cache directory. Autosaving will not work...";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString fileName = path + m_scriptId.toString().remove(QRegExp("[{}]")) + ".qml.autosave";
|
||||||
|
m_cacheFile.setFileName(fileName);
|
||||||
|
if (!m_cacheFile.open(QFile::ReadWrite)) {
|
||||||
|
qWarning() << "Cannot open cache file. Autosaving will not work...";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_cachedContent = QString::fromUtf8(m_cacheFile.readAll());
|
||||||
|
emit cachedContentChanged();
|
||||||
|
emit availableChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ScriptAutoSaver::liveContent() const
|
||||||
|
{
|
||||||
|
return m_liveContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptAutoSaver::setLiveContent(const QString &liveContent)
|
||||||
|
{
|
||||||
|
if (m_liveContent != liveContent) {
|
||||||
|
m_liveContent = liveContent;
|
||||||
|
emit liveContentChanged();
|
||||||
|
|
||||||
|
storeContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ScriptAutoSaver::cachedContent() const
|
||||||
|
{
|
||||||
|
return m_cachedContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptAutoSaver::storeContent()
|
||||||
|
{
|
||||||
|
if (m_cacheFile.isOpen() && m_active && m_liveContent != m_cachedContent) {
|
||||||
|
qDebug() << "autosaving...";
|
||||||
|
m_cacheFile.seek(0);
|
||||||
|
m_cacheFile.resize(0);
|
||||||
|
m_cacheFile.write(m_liveContent.toUtf8());
|
||||||
|
m_cacheFile.flush();
|
||||||
|
|
||||||
|
m_cachedContent = m_liveContent;
|
||||||
|
emit cachedContentChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
58
libnymea-app/scripting/scriptautosaver.h
Normal file
58
libnymea-app/scripting/scriptautosaver.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#ifndef SCRIPTAUTOSAVER_H
|
||||||
|
#define SCRIPTAUTOSAVER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QUuid>
|
||||||
|
#include <QQmlParserStatus>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
class ScriptAutoSaver : public QObject, public QQmlParserStatus
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QUuid scriptId READ scriptId WRITE setScriptId NOTIFY scriptIdChanged)
|
||||||
|
Q_PROPERTY(bool available READ available NOTIFY availableChanged)
|
||||||
|
Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged)
|
||||||
|
Q_PROPERTY(QString liveContent READ liveContent WRITE setLiveContent NOTIFY liveContentChanged)
|
||||||
|
Q_PROPERTY(QString cachedContent READ cachedContent NOTIFY cachedContentChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ScriptAutoSaver(QObject *parent = nullptr);
|
||||||
|
~ScriptAutoSaver();
|
||||||
|
|
||||||
|
void classBegin() override;
|
||||||
|
void componentComplete() override;
|
||||||
|
|
||||||
|
bool available() const;
|
||||||
|
|
||||||
|
bool active() const;
|
||||||
|
void setActive(bool active);
|
||||||
|
|
||||||
|
QUuid scriptId() const;
|
||||||
|
void setScriptId(const QUuid &scriptId);
|
||||||
|
|
||||||
|
QString liveContent() const;
|
||||||
|
void setLiveContent(const QString &liveContent);
|
||||||
|
|
||||||
|
QString cachedContent() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void scriptIdChanged();
|
||||||
|
void availableChanged();
|
||||||
|
void activeChanged();
|
||||||
|
void liveContentChanged();
|
||||||
|
void cachedContentChanged();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void storeContent();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QUuid m_scriptId;
|
||||||
|
QString m_cachedContent;
|
||||||
|
QString m_liveContent;
|
||||||
|
|
||||||
|
QFile m_cacheFile;
|
||||||
|
|
||||||
|
bool m_active = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SCRIPTAUTOSAVER_H
|
||||||
@ -222,5 +222,6 @@
|
|||||||
<file>ui/components/UpdateStatusIcon.qml</file>
|
<file>ui/components/UpdateStatusIcon.qml</file>
|
||||||
<file>ui/magic/WriteNfcTagPage.qml</file>
|
<file>ui/magic/WriteNfcTagPage.qml</file>
|
||||||
<file>ui/components/MediaPlayer.qml</file>
|
<file>ui/components/MediaPlayer.qml</file>
|
||||||
|
<file>ui/components/InfoPane.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@ -196,55 +196,70 @@ Page {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
Pane {
|
InfoPane {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: shownHeight
|
shown: updatesModel.count > 0 || engine.systemController.updateRunning
|
||||||
property int shownHeight: shown ? contentRow.implicitHeight : 0
|
text: engine.systemController.updateRunning ? qsTr("System update in progress...") : qsTr("%n system update(s) available", "", updatesModel.count)
|
||||||
property bool shown: updatesModel.count > 0 || engine.systemController.updateRunning
|
imageSource: "../images/system-update.svg"
|
||||||
visible: shownHeight > 0
|
rotatingIcon: engine.systemController.updateRunning
|
||||||
Behavior on shownHeight { NumberAnimation { easing.type: Easing.InOutQuad; duration: 150 } }
|
onPaneClicked: pageStack.push(Qt.resolvedUrl("system/SystemUpdatePage.qml"))
|
||||||
Material.elevation: 2
|
|
||||||
padding: 0
|
|
||||||
|
|
||||||
MouseArea {
|
PackagesFilterModel {
|
||||||
anchors.fill: parent
|
id: updatesModel
|
||||||
onClicked: pageStack.push(Qt.resolvedUrl("system/SystemUpdatePage.qml"))
|
packages: engine.systemController.packages
|
||||||
}
|
updatesOnly: true
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
color: app.accentColor
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
PackagesFilterModel {
|
|
||||||
id: updatesModel
|
|
||||||
packages: engine.systemController.packages
|
|
||||||
updatesOnly: true
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: contentRow
|
|
||||||
anchors { left: parent.left; top: parent.top; right: parent.right; leftMargin: app.margins; rightMargin: app.margins }
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
height: app.iconSize
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
|
||||||
text: engine.systemController.updateRunning ? qsTr("System update in progress...") : qsTr("%n system update(s) available", "", updatesModel.count)
|
|
||||||
color: "white"
|
|
||||||
font.pixelSize: app.smallFont
|
|
||||||
}
|
|
||||||
ColorIcon {
|
|
||||||
height: app.iconSize / 2
|
|
||||||
width: height
|
|
||||||
color: "white"
|
|
||||||
name: "../images/system-update.svg"
|
|
||||||
RotationAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; running: engine.systemController.updateRunning }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pane {
|
||||||
|
// Layout.fillWidth: true
|
||||||
|
// Layout.preferredHeight: shownHeight
|
||||||
|
// property int shownHeight: shown ? contentRow.implicitHeight : 0
|
||||||
|
// property bool shown: updatesModel.count > 0 || engine.systemController.updateRunning
|
||||||
|
// visible: shownHeight > 0
|
||||||
|
// Behavior on shownHeight { NumberAnimation { easing.type: Easing.InOutQuad; duration: 150 } }
|
||||||
|
// Material.elevation: 2
|
||||||
|
// padding: 0
|
||||||
|
|
||||||
|
// MouseArea {
|
||||||
|
// anchors.fill: parent
|
||||||
|
// onClicked: pageStack.push(Qt.resolvedUrl("system/SystemUpdatePage.qml"))
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Rectangle {
|
||||||
|
// color: app.accentColor
|
||||||
|
// anchors.fill: parent
|
||||||
|
|
||||||
|
// PackagesFilterModel {
|
||||||
|
// id: updatesModel
|
||||||
|
// packages: engine.systemController.packages
|
||||||
|
// updatesOnly: true
|
||||||
|
// }
|
||||||
|
|
||||||
|
// RowLayout {
|
||||||
|
// id: contentRow
|
||||||
|
// anchors { left: parent.left; top: parent.top; right: parent.right; leftMargin: app.margins; rightMargin: app.margins }
|
||||||
|
// Item {
|
||||||
|
// Layout.fillWidth: true
|
||||||
|
// height: app.iconSize
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Label {
|
||||||
|
// text: engine.systemController.updateRunning ? qsTr("System update in progress...") : qsTr("%n system update(s) available", "", updatesModel.count)
|
||||||
|
// color: "white"
|
||||||
|
// font.pixelSize: app.smallFont
|
||||||
|
// }
|
||||||
|
// ColorIcon {
|
||||||
|
// height: app.iconSize / 2
|
||||||
|
// width: height
|
||||||
|
// color: "white"
|
||||||
|
// name: "../images/system-update.svg"
|
||||||
|
// RotationAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; running: engine.systemController.updateRunning }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: contentContainer
|
id: contentContainer
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|||||||
@ -59,7 +59,12 @@ ApplicationWindow {
|
|||||||
property int smallFont: 13
|
property int smallFont: 13
|
||||||
property int mediumFont: 16
|
property int mediumFont: 16
|
||||||
property int largeFont: 20
|
property int largeFont: 20
|
||||||
|
|
||||||
|
property int smallIconSize: 16
|
||||||
property int iconSize: 24
|
property int iconSize: 24
|
||||||
|
property int largeIconSize: 32
|
||||||
|
property int hugeIconSize: 40
|
||||||
|
|
||||||
property int delegateHeight: 60
|
property int delegateHeight: 60
|
||||||
property color backgroundColor: Material.background
|
property color backgroundColor: Material.background
|
||||||
|
|
||||||
|
|||||||
93
nymea-app/ui/components/InfoPane.qml
Normal file
93
nymea-app/ui/components/InfoPane.qml
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import QtQuick 2.0
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Controls.Material 2.2
|
||||||
|
import QtQuick.Layouts 1.2
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
implicitHeight: d.shownHeight
|
||||||
|
visible: d.shownHeight > 0
|
||||||
|
|
||||||
|
property alias text: textLabel.text
|
||||||
|
property alias imageSource: icon.name
|
||||||
|
property alias buttonText: button.text
|
||||||
|
|
||||||
|
property alias color: background.color
|
||||||
|
property alias textColor: textLabel.color
|
||||||
|
|
||||||
|
property bool rotatingIcon: false
|
||||||
|
|
||||||
|
property bool shown: false
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
shown = true;
|
||||||
|
}
|
||||||
|
function hide() {
|
||||||
|
shown = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
signal paneClicked();
|
||||||
|
signal buttonClicked();
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
property int shownHeight: shown ? contentRow.implicitHeight : 0
|
||||||
|
Behavior on shownHeight { NumberAnimation { easing.type: Easing.InOutQuad; duration: 150 } }
|
||||||
|
}
|
||||||
|
|
||||||
|
Pane {
|
||||||
|
anchors { left: parent.left; bottom: parent.bottom; right: parent.right }
|
||||||
|
Material.elevation: 2
|
||||||
|
padding: 0
|
||||||
|
height: contentRow.implicitHeight
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: root.paneClicked()
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: background
|
||||||
|
color: app.accentColor
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: contentRow
|
||||||
|
anchors { left: parent.left; top: parent.top; right: parent.right; leftMargin: app.margins; rightMargin: app.margins }
|
||||||
|
Label {
|
||||||
|
id: textLabel
|
||||||
|
color: "white"
|
||||||
|
font.pixelSize: app.smallFont
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.margins: app.margins * .4
|
||||||
|
horizontalAlignment: Text.AlignRight
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
ColorIcon {
|
||||||
|
id: icon
|
||||||
|
height: app.smallIconSize
|
||||||
|
width: height
|
||||||
|
color: "white"
|
||||||
|
visible: name.length > 0
|
||||||
|
|
||||||
|
RotationAnimation on rotation {
|
||||||
|
from: 0
|
||||||
|
to: 360
|
||||||
|
duration: 2000
|
||||||
|
loops: Animation.Infinite
|
||||||
|
running: root.rotatingIcon
|
||||||
|
onStopped: icon.rotation = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: button
|
||||||
|
visible: text.length > 0
|
||||||
|
onClicked: root.buttonClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ Item {
|
|||||||
ColorIcon {
|
ColorIcon {
|
||||||
id: colorIcon
|
id: colorIcon
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
height: app.iconSize * 1.5
|
height: app.hugeIconSize //* 1.5
|
||||||
width: height
|
width: height
|
||||||
ColorIcon {
|
ColorIcon {
|
||||||
id: fallbackIcon
|
id: fallbackIcon
|
||||||
@ -149,21 +149,21 @@ Item {
|
|||||||
anchors { top: parent.top; right: parent.right; margins: app.margins }
|
anchors { top: parent.top; right: parent.right; margins: app.margins }
|
||||||
spacing: app.margins / 2
|
spacing: app.margins / 2
|
||||||
ColorIcon {
|
ColorIcon {
|
||||||
height: app.iconSize / 2
|
height: app.smallIconSize
|
||||||
width: height
|
width: height
|
||||||
name: root.isWireless ? "../images/connections/nm-signal-00.svg" : "../images/connections/network-wired-offline.svg"
|
name: root.isWireless ? "../images/connections/nm-signal-00.svg" : "../images/connections/network-wired-offline.svg"
|
||||||
color: root.disconnected ? "red" : "orange"
|
color: root.disconnected ? "red" : "orange"
|
||||||
visible: root.setupStatus == Thing.ThingSetupStatusComplete && (root.disconnected || (root.isWireless && root.signalStrength < 20))
|
visible: root.setupStatus == Thing.ThingSetupStatusComplete && (root.disconnected || (root.isWireless && root.signalStrength < 20))
|
||||||
}
|
}
|
||||||
ColorIcon {
|
ColorIcon {
|
||||||
height: app.iconSize / 2
|
height: app.smallIconSize
|
||||||
width: height
|
width: height
|
||||||
name: root.setupStatus === Thing.ThingSetupStatusFailed ? "../images/dialog-warning-symbolic.svg" : "../images/settings.svg"
|
name: root.setupStatus === Thing.ThingSetupStatusFailed ? "../images/dialog-warning-symbolic.svg" : "../images/settings.svg"
|
||||||
color: root.setupStatus === Thing.ThingSetupStatusFailed ? "red" : keyColor
|
color: root.setupStatus === Thing.ThingSetupStatusFailed ? "red" : keyColor
|
||||||
visible: root.setupStatus === Thing.ThingSetupStatusFailed || root.setupStatus === Thing.ThingSetupStatusInProgress
|
visible: root.setupStatus === Thing.ThingSetupStatusFailed || root.setupStatus === Thing.ThingSetupStatusInProgress
|
||||||
}
|
}
|
||||||
ColorIcon {
|
ColorIcon {
|
||||||
height: app.iconSize / 2
|
height: app.smallIconSize
|
||||||
width: height
|
width: height
|
||||||
name: "../images/battery/battery-010.svg"
|
name: "../images/battery/battery-010.svg"
|
||||||
visible: root.setupStatus == Thing.ThingSetupStatusComplete && root.batteryCritical
|
visible: root.setupStatus == Thing.ThingSetupStatusComplete && root.batteryCritical
|
||||||
|
|||||||
@ -139,38 +139,43 @@ Page {
|
|||||||
font: scriptEdit.font
|
font: scriptEdit.font
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScriptAutoSaver {
|
||||||
|
id: autoSaver
|
||||||
|
scriptId: d.scriptId
|
||||||
|
liveContent: scriptEdit.text
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: engine.scriptManager
|
target: engine.scriptManager
|
||||||
onAddScriptReply: {
|
onAddScriptReply: deployReply(id, scriptError, errors)
|
||||||
if (id == d.callId) {
|
onEditScriptReply: deployReply(id, scriptError, errors)
|
||||||
|
function deployReply(id, scriptError, errors) {
|
||||||
|
if (id === d.callId) {
|
||||||
d.callId = -1;
|
d.callId = -1;
|
||||||
if (scriptError == "ScriptErrorNoError") {
|
if (scriptError === "ScriptErrorNoError") {
|
||||||
d.scriptId = scriptId;
|
|
||||||
d.oldContent = scriptEdit.text;
|
d.oldContent = scriptEdit.text;
|
||||||
} else if (scriptError == "ScriptErrorInvalidScript") {
|
infoPane.hide();
|
||||||
content.ToolTip.show(qsTr("The script has not been deployed because it contains errors."))
|
errorPane.hide();
|
||||||
}
|
} else if (scriptError === "ScriptErrorInvalidScript") {
|
||||||
|
errorPane.show();
|
||||||
errorModel.update(errors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onEditScriptReply: {
|
|
||||||
print("edit reply", id, d.callId)
|
|
||||||
if (id == d.callId) {
|
|
||||||
d.callId = -1;
|
|
||||||
if (scriptError == "ScriptErrorNoError") {
|
|
||||||
d.oldContent = scriptEdit.text;
|
|
||||||
} else if (scriptError == "ScriptErrorInvalidScript") {
|
|
||||||
content.ToolTip.show(qsTr("The script has not been deployed because it contains errors."))
|
|
||||||
}
|
}
|
||||||
errorModel.update(errors)
|
errorModel.update(errors)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onFetchScriptReply: {
|
onFetchScriptReply: {
|
||||||
if (id == d.callId && scriptError == "ScriptErrorNoError") {
|
if (id == d.callId && scriptError == "ScriptErrorNoError") {
|
||||||
d.callId = -1;
|
d.callId = -1;
|
||||||
scriptEdit.text = content;
|
|
||||||
d.oldContent = content;
|
d.oldContent = content;
|
||||||
|
|
||||||
|
if (autoSaver.cachedContent.length > 0 && autoSaver.cachedContent !== content) {
|
||||||
|
console.log("autosaved version available!");
|
||||||
|
scriptEdit.text = autoSaver.cachedContent;
|
||||||
|
infoPane.show();
|
||||||
|
} else {
|
||||||
|
scriptEdit.text = content;
|
||||||
|
}
|
||||||
|
autoSaver.active = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onRenameScriptReply: {
|
onRenameScriptReply: {
|
||||||
@ -191,8 +196,30 @@ Page {
|
|||||||
// TODO: Make this a SplitView when we can use Qt 5.13
|
// TODO: Make this a SplitView when we can use Qt 5.13
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: content
|
id: content
|
||||||
|
spacing: 0
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
InfoPane {
|
||||||
|
id: infoPane
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: qsTr("An autosaved version of this script has been loaded. Deploy to store this version or reload to restore the deployed version.")
|
||||||
|
buttonText: qsTr("Reload")
|
||||||
|
z: 1
|
||||||
|
onButtonClicked: {
|
||||||
|
scriptEdit.text = d.oldContent
|
||||||
|
infoPane.hide();
|
||||||
|
errorPane.hide();
|
||||||
|
errorModel.update([])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoPane {
|
||||||
|
id: errorPane
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: "red"
|
||||||
|
text: qsTr("The script has not been deployed because it contains errors.")
|
||||||
|
}
|
||||||
|
|
||||||
Flickable {
|
Flickable {
|
||||||
id: scriptFlickable
|
id: scriptFlickable
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
@ -236,7 +263,7 @@ Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Keys.onPressed: {
|
Keys.onPressed: {
|
||||||
print("key", event.key, "Completion box visible:", completionBox.visible)
|
// print("key", event.key, "Completion box visible:", completionBox.visible)
|
||||||
// Things to happen only when we're not autocompleting
|
// Things to happen only when we're not autocompleting
|
||||||
if (!completionBox.visible) {
|
if (!completionBox.visible) {
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
|
|||||||
Reference in New Issue
Block a user