Add recent file view, implement runtime options
diff --git a/ide/IDE.pri b/ide/IDE.pri
index 69856d7..d086a61 100644
--- a/ide/IDE.pri
+++ b/ide/IDE.pri
@@ -18,14 +18,16 @@
$$PWD/CellModel.cpp \
$$PWD/IdeMain.cpp \
$$PWD/NbRuntime.cpp \
- $$PWD/Notebook.cpp
+ $$PWD/Notebook.cpp \
+ $$PWD/RecentModel.cpp
HEADERS += \
$$PWD/Cell.h \
$$PWD/CellModel.h \
$$PWD/IdeMain.h \
$$PWD/NbRuntime.h \
- $$PWD/Notebook.h
+ $$PWD/Notebook.h \
+ $$PWD/RecentModel.h
RESOURCES += \
$$PWD/resources.qrc
diff --git a/ide/IdeMain.cpp b/ide/IdeMain.cpp
index ff8025f..7efe5fa 100644
--- a/ide/IdeMain.cpp
+++ b/ide/IdeMain.cpp
@@ -5,6 +5,7 @@
#include <QTranslator>
#include "CellModel.h"
+#include "RecentModel.h"
int ideMain(Application *app)
{
@@ -14,11 +15,17 @@
qRegisterMetaType<CellModel>();
qRegisterMetaType<CellModel *>();
+ qRegisterMetaType<RecentModel>();
+ qRegisterMetaType<RecentModel *>();
QTranslator translator;
qInfo() << "loading translations" << translator.load(QLocale(), "refal", "_", ":/ts/", ".qm");
app->installTranslator(&translator);
+ app->setOrganizationName("swissChili");
+ app->setOrganizationDomain("swisschili.sh");
+ app->setApplicationName("REFAL Studio");
+
const QUrl url(QStringLiteral("qrc:/qml/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
app, [url](QObject *obj, const QUrl &objUrl)
diff --git a/ide/NbRuntime.cpp b/ide/NbRuntime.cpp
index a2111a7..debda5b 100644
--- a/ide/NbRuntime.cpp
+++ b/ide/NbRuntime.cpp
@@ -10,6 +10,12 @@
StdLib().load(_eval);
}
+void NbRuntime::reset()
+{
+ _eval.reset();
+ _ctx = {};
+}
+
void NbRuntime::queueCell(Cell *cell)
{
if (!_cells.contains(cell))
diff --git a/ide/NbRuntime.h b/ide/NbRuntime.h
index e7a4b3d..d98daa3 100644
--- a/ide/NbRuntime.h
+++ b/ide/NbRuntime.h
@@ -16,6 +16,8 @@
public:
explicit NbRuntime(QObject *parent = nullptr);
+ void reset();
+
public slots:
void queueCell(Cell *cell);
void unqueueCell(Cell *cell);
diff --git a/ide/Notebook.cpp b/ide/Notebook.cpp
index 36cc0a3..a5baa0c 100644
--- a/ide/Notebook.cpp
+++ b/ide/Notebook.cpp
@@ -56,6 +56,21 @@
void Notebook::quitCell(QUuid uuid)
{
_rt->unqueueCell(Cell::cellFromUuid(uuid));
+ _runningAll = false;
+}
+
+void Notebook::runAll()
+{
+ if (_cells.size() > 0)
+ {
+ _rt->queueCell(_cells.first());
+ _runningAll = true;
+ }
+}
+
+void Notebook::reset()
+{
+ _rt->reset();
}
void Notebook::fromJson(QJsonDocument doc)
@@ -118,7 +133,7 @@
{
if (_savePath == "")
{
- setSavePath(QFileDialog::getSaveFileName(nullptr, "Open Refal Notebook", "", "Refal Notebooks (*.refnb)"));
+ setSavePath(QFileDialog::getSaveFileName(nullptr, "Open REFAL Notebook", "", "REFAL Notebook (*.refnb)"));
}
QJsonDocument doc = toJson();
@@ -133,6 +148,8 @@
save.write(doc.toJson(QJsonDocument::Indented));
save.close();
+
+ emit saved();
}
bool Notebook::savePathSet()
@@ -157,6 +174,21 @@
cell->setResult(pprint(result));
cell->setStatus(Cell::IDLE);
cell->setResultType(Cell::EXPRESSION);
+
+ if (_runningAll)
+ {
+ int index = _cells.indexOf(cell);
+
+ // not last
+ if (index < _cells.size() - 1)
+ {
+ _rt->queueCell(_cells[index + 1]);
+ }
+ else
+ {
+ _runningAll = false;
+ }
+ }
}
void Notebook::cellFailedToParse(Cell *cell, ParseResult result, Parser parser)
@@ -165,6 +197,8 @@
cell->setResult(pprint(result, parser, PPrint::HTML));
cell->setStatus(Cell::IDLE);
cell->setResultType(Cell::DIAGNOSTIC);
+
+ _runningAll = false;
}
void Notebook::cellWaiting(Cell *cell)
@@ -184,4 +218,6 @@
qInfo() << "cellQuit" << cell->uuid();
cell->setResult("");
cell->setStatus(Cell::IDLE);
+
+ _runningAll = false;
}
diff --git a/ide/Notebook.h b/ide/Notebook.h
index 6a6541d..83f9fc7 100644
--- a/ide/Notebook.h
+++ b/ide/Notebook.h
@@ -25,6 +25,8 @@
Q_INVOKABLE void runCell(QUuid uuid);
Q_INVOKABLE void quitCell(QUuid uuid);
+ Q_INVOKABLE void runAll();
+ Q_INVOKABLE void reset();
Q_INVOKABLE void fromJson(QJsonDocument doc);
Q_INVOKABLE void open(QString path);
@@ -41,6 +43,7 @@
void cellModelChanged();
void saveError(QString message);
void savePathChanged(QString savePath);
+ void saved();
protected slots:
void cellFinishedRunning(Cell *cell, RuntimeResult result);
@@ -57,6 +60,7 @@
QThread *_rtThread;
NbRuntime *_rt;
QString _savePath = "";
+ bool _runningAll = false;
};
Q_DECLARE_METATYPE(Notebook)
diff --git a/ide/RecentModel.cpp b/ide/RecentModel.cpp
new file mode 100644
index 0000000..30824ed
--- /dev/null
+++ b/ide/RecentModel.cpp
@@ -0,0 +1,62 @@
+#include "RecentModel.h"
+#include <QSettings>
+
+RecentModel::RecentModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+ _recents = _settings.value("recents").toStringList();
+}
+
+RecentModel::RecentModel(const RecentModel &other, QObject *parent)
+ : RecentModel(parent)
+{
+ _recents = other._recents;
+}
+
+int RecentModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+
+ return _recents.size();
+}
+
+QVariant RecentModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (role == PathRole)
+ return _recents[index.row()];
+
+ return QVariant();
+}
+
+QHash<int, QByteArray> RecentModel::roleNames() const
+{
+ return {{PathRole, "path"}};
+}
+
+void RecentModel::add(QString path)
+{
+ remove(path);
+
+ beginInsertRows(QModelIndex(), 0, 0);
+ _recents.prepend(path);
+ endInsertRows();
+
+ _settings.setValue("recents", _recents);
+}
+
+void RecentModel::remove(QString path)
+{
+ if (_recents.contains(path))
+ {
+ int index = _recents.indexOf(path);
+ beginRemoveRows(QModelIndex(), index, index);
+ _recents.removeAt(index);
+ endRemoveRows();
+
+ _settings.setValue("recents", _recents);
+ }
+}
diff --git a/ide/RecentModel.h b/ide/RecentModel.h
new file mode 100644
index 0000000..76cd461
--- /dev/null
+++ b/ide/RecentModel.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <QAbstractListModel>
+#include <qqml.h>
+#include <QSettings>
+
+class RecentModel : public QAbstractListModel
+{
+ Q_OBJECT
+ QML_ELEMENT
+
+public:
+ explicit RecentModel(QObject *parent = nullptr);
+ RecentModel(const RecentModel &other, QObject *parent = nullptr);
+
+ enum
+ {
+ PathRole = Qt::UserRole + 1
+ };
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+
+ QHash<int, QByteArray> roleNames() const override;
+
+ Q_INVOKABLE void add(QString path);
+ Q_INVOKABLE void remove(QString path);
+
+private:
+ QStringList _recents;
+ QSettings _settings;
+};
+
+Q_DECLARE_METATYPE(RecentModel)
+Q_DECLARE_METATYPE(RecentModel *)
diff --git a/ide/qml/NbWindow.qml b/ide/qml/NbWindow.qml
index 5710c9e..858fb5e 100644
--- a/ide/qml/NbWindow.qml
+++ b/ide/qml/NbWindow.qml
@@ -15,7 +15,8 @@
Material.theme: Material.Light
Material.accent: Material.Orange
- minimumWidth: column.implicitWidth
+ minimumWidth: 600
+ minimumHeight: 400
required property ApplicationWindow welcomeWindow
@@ -92,10 +93,14 @@
Action {
text: qsTr("Run &All")
+
+ onTriggered: notebook.runAll();
}
Action {
text: qsTr("&Reset Runtime State")
+
+ onTriggered: notebook.reset();
}
}
}
@@ -107,6 +112,8 @@
{
console.error(message)
}
+
+ onSaved: welcomeWindow.recentModel.add(notebook.savePath)
}
ColumnLayout {
@@ -137,7 +144,7 @@
ColumnLayout {
Label {
font.pointSize: 18
- text: qsTr("Notebook")
+ text: notebook.savePath != "" ? notebook.savePath.split("/").pop().split(".").slice(0,-1).join('.') : qsTr("Notebook")
}
Label {
diff --git a/ide/qml/RecentNotebook.qml b/ide/qml/RecentNotebook.qml
index d0b1120..194424c 100644
--- a/ide/qml/RecentNotebook.qml
+++ b/ide/qml/RecentNotebook.qml
@@ -8,6 +8,7 @@
property string name: "Hello.refnb"
property alias containsMouse: mouseArea.containsMouse
signal clicked()
+ signal removeClicked()
Image {
id: nbIcon
@@ -27,7 +28,24 @@
anchors.fill: parent
hoverEnabled: true
- onClicked: root.clicked()
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+
+ onClicked: {
+ if (mouse.button == Qt.LeftButton)
+ root.clicked();
+ else if (mouse.button == Qt.RightButton)
+ contextMenu.popup();
+ }
+ }
+
+ Menu {
+ id: contextMenu
+
+ MenuItem {
+ text: qsTr("Remove")
+
+ onClicked: root.removeClicked()
+ }
}
}
}
diff --git a/ide/qml/main.qml b/ide/qml/main.qml
index 23f8926..210640c 100644
--- a/ide/qml/main.qml
+++ b/ide/qml/main.qml
@@ -2,6 +2,9 @@
import QtQuick.Controls 2.15
import QtQuick.Controls.Material 2.0
import QtQuick.Layouts 1.11
+import Qt.labs.settings 1.0
+
+import sh.swisschili.REFAL 1.0
ApplicationWindow {
id: root
@@ -19,6 +22,8 @@
visible: true
+ property alias recentModel: recents
+
function openNotebook(path=null) {
let NbWindow = Qt.createComponent("qrc:///qml/NbWindow.qml");
let window = NbWindow.createObject(null, {welcomeWindow: root});
@@ -36,6 +41,10 @@
show();
}
+ RecentModel {
+ id: recents
+ }
+
Label {
id: textRefal
text: qsTr("REFAL")
@@ -125,21 +134,20 @@
Layout.fillWidth: true
Layout.fillHeight: false
- model: [
- // "~/Documents/Hello.refnb", "~/Downloads/stuff/Goodbye.refnb", "/home/ch/dev/REFAL/build/test.refnb"
- ]
+ model: recents
delegate: RecentNotebook {
Layout.leftMargin: 8
Layout.rightMargin: 8
- name: modelData.split("/").pop()
+ name: path.split("/").pop()
- ToolTip.text: modelData
+ ToolTip.text: path
ToolTip.visible: containsMouse
ToolTip.delay: 1000
- onClicked: root.openNotebook(modelData)
+ onClicked: root.openNotebook(path)
+ onRemoveClicked: recents.remove(path)
}
}