Qt: Refactor the script buffer list into a model (#2566)

This commit is contained in:
ahigerd 2022-06-24 01:15:35 -05:00 committed by GitHub
parent c1b1f72005
commit 1bda318531
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 160 additions and 44 deletions

View File

@ -252,6 +252,7 @@ if(ENABLE_SCRIPTING)
list(APPEND SOURCE_FILES
ScriptingController.cpp
ScriptingTextBuffer.cpp
ScriptingTextBufferModel.cpp
ScriptingView.cpp)
list(APPEND UI_FILES

View File

@ -7,6 +7,7 @@
#include "CoreController.h"
#include "ScriptingTextBuffer.h"
#include "ScriptingTextBufferModel.h"
using namespace QGBA;
@ -33,6 +34,9 @@ ScriptingController::ScriptingController(QObject* parent)
}
};
m_bufferModel = new ScriptingTextBufferModel(this);
QObject::connect(m_bufferModel, &ScriptingTextBufferModel::textBufferCreated, this, &ScriptingController::textBufferCreated);
init();
}
@ -87,10 +91,7 @@ void ScriptingController::clearController() {
void ScriptingController::reset() {
CoreController::Interrupter interrupter(m_controller);
for (ScriptingTextBuffer* buffer : m_buffers) {
delete buffer;
}
m_buffers.clear();
m_bufferModel->reset();
mScriptContextDetachCore(&m_scriptContext);
mScriptContextDeinit(&m_scriptContext);
m_engines.clear();
@ -106,21 +107,13 @@ void ScriptingController::runCode(const QString& code) {
load(vf, "*prompt");
}
mScriptTextBuffer* ScriptingController::createTextBuffer(void* context) {
ScriptingController* self = static_cast<ScriptingController*>(context);
ScriptingTextBuffer* buffer = new ScriptingTextBuffer(self);
self->m_buffers.append(buffer);
emit self->textBufferCreated(buffer);
return buffer->textBuffer();
}
void ScriptingController::init() {
mScriptContextInit(&m_scriptContext);
mScriptContextAttachStdlib(&m_scriptContext);
mScriptContextRegisterEngines(&m_scriptContext);
mScriptContextAttachLogger(&m_scriptContext, &m_logger);
mScriptContextSetTextBufferFactory(&m_scriptContext, &ScriptingController::createTextBuffer, this);
m_bufferModel->attachToContext(&m_scriptContext);
HashTableEnumerate(&m_scriptContext.engines, [](const char* key, void* engine, void* context) {
ScriptingController* self = static_cast<ScriptingController*>(context);

View File

@ -15,10 +15,13 @@
#include <memory>
class QTextDocument;
namespace QGBA {
class CoreController;
class ScriptingTextBuffer;
class ScriptingTextBufferModel;
class ScriptingController : public QObject {
Q_OBJECT
@ -33,7 +36,7 @@ public:
bool load(VFileDevice& vf, const QString& name);
mScriptContext* context() { return &m_scriptContext; }
QList<ScriptingTextBuffer*> textBuffers() { return m_buffers; }
ScriptingTextBufferModel* textBufferModel() const { return m_bufferModel; }
signals:
void log(const QString&);
@ -59,7 +62,7 @@ private:
mScriptEngineContext* m_activeEngine = nullptr;
QHash<QString, mScriptEngineContext*> m_engines;
QList<ScriptingTextBuffer*> m_buffers;
ScriptingTextBufferModel* m_bufferModel;
std::shared_ptr<CoreController> m_controller;
};

View File

@ -47,12 +47,12 @@ private:
static void deinit(struct mScriptTextBuffer*);
static void setName(struct mScriptTextBuffer*, const char* name);
static uint32_t getX(const struct mScriptTextBuffer*);
static uint32_t getY(const struct mScriptTextBuffer*);
static uint32_t cols(const struct mScriptTextBuffer*);
static uint32_t rows(const struct mScriptTextBuffer*);
static void print(struct mScriptTextBuffer*, const char* text);
static void clear(struct mScriptTextBuffer*);
static void setSize(struct mScriptTextBuffer*, uint32_t cols, uint32_t rows);

View File

@ -0,0 +1,73 @@
/* Copyright (c) 2013-2022 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ScriptingTextBufferModel.h"
#include "ScriptingTextBuffer.h"
#include <QTextDocument>
using namespace QGBA;
ScriptingTextBufferModel::ScriptingTextBufferModel(QObject* parent)
: QAbstractListModel(parent)
{
// initializers only
}
void ScriptingTextBufferModel::attachToContext(mScriptContext* context)
{
mScriptContextSetTextBufferFactory(context, &ScriptingTextBufferModel::createTextBuffer, this);
}
void ScriptingTextBufferModel::reset() {
beginResetModel();
QList<ScriptingTextBuffer*> toDelete = m_buffers;
m_buffers.clear();
endResetModel();
for (ScriptingTextBuffer* buffer : toDelete) {
delete buffer;
}
}
mScriptTextBuffer* ScriptingTextBufferModel::createTextBuffer(void* context) {
ScriptingTextBufferModel* self = static_cast<ScriptingTextBufferModel*>(context);
self->beginInsertRows(QModelIndex(), self->m_buffers.size(), self->m_buffers.size() + 1);
ScriptingTextBuffer* buffer = new ScriptingTextBuffer(self);
QObject::connect(buffer, &ScriptingTextBuffer::bufferNameChanged, self, &ScriptingTextBufferModel::bufferNameChanged);
self->m_buffers.append(buffer);
emit self->textBufferCreated(buffer);
self->endInsertRows();
return buffer->textBuffer();
}
void ScriptingTextBufferModel::bufferNameChanged(const QString&) {
ScriptingTextBuffer* buffer = qobject_cast<ScriptingTextBuffer*>(sender());
int row = m_buffers.indexOf(buffer);
if (row < 0) {
return;
}
QModelIndex idx = index(row, 0);
emit dataChanged(idx, idx, { Qt::DisplayRole });
}
int ScriptingTextBufferModel::rowCount(const QModelIndex& parent) const {
if (parent.isValid()) {
return 0;
}
return m_buffers.size();
}
QVariant ScriptingTextBufferModel::data(const QModelIndex& index, int role) const {
if (index.parent().isValid() || index.row() < 0 || index.row() >= m_buffers.size() || index.column() != 0) {
return QVariant();
}
if (role == Qt::DisplayRole) {
return m_buffers[index.row()]->document()->metaInformation(QTextDocument::DocumentTitle);
} else if (role == ScriptingTextBufferModel::DocumentRole) {
return QVariant::fromValue<QTextDocument*>(m_buffers[index.row()]->document());
}
return QVariant();
}

View File

@ -0,0 +1,48 @@
/* Copyright (c) 2013-2022 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#pragma once
#include <QAbstractListModel>
#include <mgba/script/context.h>
class mScriptTextBuffer;
namespace QGBA {
class ScriptingTextBuffer;
class ScriptingTextBufferModel : public QAbstractListModel {
Q_OBJECT
public:
enum ItemDataRole {
DocumentRole = Qt::UserRole + 1,
};
ScriptingTextBufferModel(QObject* parent = nullptr);
void attachToContext(mScriptContext* context);
int rowCount(const QModelIndex& parent = QModelIndex()) const;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
signals:
void textBufferCreated(ScriptingTextBuffer*);
public slots:
void reset();
private slots:
void bufferNameChanged(const QString&);
private:
static mScriptTextBuffer* createTextBuffer(void* context);
QList<ScriptingTextBuffer*> m_buffers;
};
}

View File

@ -9,6 +9,7 @@
#include "ConfigController.h"
#include "ScriptingController.h"
#include "ScriptingTextBuffer.h"
#include "ScriptingTextBufferModel.h"
using namespace QGBA;
@ -19,26 +20,34 @@ ScriptingView::ScriptingView(ScriptingController* controller, ConfigController*
{
m_ui.setupUi(this);
ScriptingTextBufferModel* bufferModel = controller->textBufferModel();
m_ui.prompt->setFont(GBAApp::app()->monospaceFont());
m_ui.log->setNewlineTerminated(true);
m_ui.buffers->setModel(bufferModel);
connect(m_ui.prompt, &QLineEdit::returnPressed, this, &ScriptingView::submitRepl);
connect(m_ui.runButton, &QAbstractButton::clicked, this, &ScriptingView::submitRepl);
connect(bufferModel, &QAbstractItemModel::modelAboutToBeReset, this, &ScriptingView::controllerReset);
connect(bufferModel, &QAbstractItemModel::rowsInserted, this, [this, bufferModel](const QModelIndex&, int row, int) {
m_ui.buffers->setCurrentIndex(bufferModel->index(row, 0));
});
connect(m_controller, &ScriptingController::log, m_ui.log, &LogWidget::log);
connect(m_controller, &ScriptingController::warn, m_ui.log, &LogWidget::warn);
connect(m_controller, &ScriptingController::error, m_ui.log, &LogWidget::error);
connect(m_controller, &ScriptingController::textBufferCreated, this, &ScriptingView::addTextBuffer);
connect(m_ui.buffers, &QListWidget::currentRowChanged, this, &ScriptingView::selectBuffer);
connect(m_ui.buffers->selectionModel(), &QItemSelectionModel::currentChanged, this, &ScriptingView::selectBuffer);
connect(m_ui.load, &QAction::triggered, this, &ScriptingView::load);
connect(m_ui.reset, &QAction::triggered, controller, &ScriptingController::reset);
m_mruFiles = m_config->getMRU(ConfigController::MRU::Script);
updateMRU();
for (ScriptingTextBuffer* buffer : controller->textBuffers()) {
addTextBuffer(buffer);
}
m_blankDocument = new QTextDocument(this);
m_blankDocument->setDocumentLayout(new QPlainTextDocumentLayout(m_blankDocument));
m_ui.buffers->setCurrentIndex(bufferModel->index(0, 0));
}
void ScriptingView::submitRepl() {
@ -57,27 +66,16 @@ void ScriptingView::load() {
}
}
void ScriptingView::addTextBuffer(ScriptingTextBuffer* buffer) {
QTextDocument* document = buffer->document();
m_textBuffers.append(buffer);
QListWidgetItem* item = new QListWidgetItem(document->metaInformation(QTextDocument::DocumentTitle));
connect(buffer, &ScriptingTextBuffer::bufferNameChanged, this, [item](const QString& name) {
item->setText(name);
});
connect(buffer, &QObject::destroyed, this, [this, buffer, item]() {
m_textBuffers.removeAll(buffer);
delete item;
});
m_ui.buffers->addItem(item);
m_ui.buffers->setCurrentItem(item);
void ScriptingView::controllerReset() {
selectBuffer(QModelIndex());
}
void ScriptingView::selectBuffer(int index) {
if (index < 0 || index >= m_textBuffers.size()) {
// If the selected buffer is out of bounds, clear the document.
m_ui.buffer->setDocument(nullptr);
void ScriptingView::selectBuffer(const QModelIndex& current, const QModelIndex&) {
if (current.isValid()) {
m_ui.buffer->setDocument(current.data(ScriptingTextBufferModel::DocumentRole).value<QTextDocument*>());
} else {
m_ui.buffer->setDocument(m_textBuffers[index]->document());
// If there is no selected buffer, use the blank document.
m_ui.buffer->setDocument(m_blankDocument);
}
}

View File

@ -23,8 +23,8 @@ private slots:
void submitRepl();
void load();
void addTextBuffer(ScriptingTextBuffer*);
void selectBuffer(int);
void controllerReset();
void selectBuffer(const QModelIndex& current, const QModelIndex& = QModelIndex());
private:
QString getFilters() const;
@ -36,8 +36,8 @@ private:
ConfigController* m_config;
ScriptingController* m_controller;
QList<ScriptingTextBuffer*> m_textBuffers;
QStringList m_mruFiles;
QTextDocument* m_blankDocument;
};
}

View File

@ -16,7 +16,7 @@
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0">
<item row="0" column="0" rowspan="3">
<widget class="QListWidget" name="buffers">
<widget class="QListView" name="buffers">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>