aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Pisa <pisa@cmp.felk.cvut.cz>2019-07-01 14:18:45 +0200
committerPavel Pisa <pisa@cmp.felk.cvut.cz>2019-07-01 14:18:45 +0200
commit215b6b79c3ecc9ca0954710c0dd2a218d4c015fb (patch)
tree9a03ab1a89413d69dd3c81002afa7639a2689912
parent5c89e53ffa28a57970b960732ccb5a7d7f1e33dd (diff)
downloadqtmips-215b6b79c3ecc9ca0954710c0dd2a218d4c015fb.tar.gz
qtmips-215b6b79c3ecc9ca0954710c0dd2a218d4c015fb.tar.bz2
qtmips-215b6b79c3ecc9ca0954710c0dd2a218d4c015fb.zip
Include simple text editor in QtMips emulator.
Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
-rw-r--r--qtmips_gui/MainWindow.ui104
-rw-r--r--qtmips_gui/icons.qrc4
-rw-r--r--qtmips_gui/mainwindow.cpp112
-rw-r--r--qtmips_gui/mainwindow.h12
-rw-r--r--qtmips_gui/qtmips_gui.pro6
-rw-r--r--qtmips_gui/srceditor.cpp89
-rw-r--r--qtmips_gui/srceditor.h59
7 files changed, 370 insertions, 16 deletions
diff --git a/qtmips_gui/MainWindow.ui b/qtmips_gui/MainWindow.ui
index 9e00c9a..3202726 100644
--- a/qtmips_gui/MainWindow.ui
+++ b/qtmips_gui/MainWindow.ui
@@ -58,9 +58,14 @@
<property name="title">
<string>File</string>
</property>
- <addaction name="actionNew"/>
+ <addaction name="actionNewMachine"/>
<addaction name="actionReload"/>
<addaction name="actionPrint"/>
+ <addaction name="actionNew"/>
+ <addaction name="actionOpen"/>
+ <addaction name="actionSave"/>
+ <addaction name="actionSaveAs"/>
+ <addaction name="actionClose"/>
<addaction name="separator"/>
<addaction name="actionExit"/>
</widget>
@@ -126,7 +131,7 @@
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
- <addaction name="actionNew"/>
+ <addaction name="actionNewMachine"/>
<addaction name="actionReload"/>
<addaction name="separator"/>
<addaction name="actionRun"/>
@@ -140,7 +145,7 @@
<addaction name="ipsUnlimited"/>
<addaction name="ipsMax"/>
</widget>
- <action name="actionNew">
+ <action name="actionNewMachine">
<property name="icon">
<iconset resource="icons.qrc">
<normaloff>:/icons/document-import.png</normaloff>:/icons/document-import.png</iconset>
@@ -149,9 +154,91 @@
<string>New simulation...</string>
</property>
<property name="shortcut">
+ <string>Ctrl+N</string>
+ </property>
+ </action>
+ <action name="actionRestart">
+ <property name="text">
+ <string>Restart</string>
+ </property>
+ </action>
+ <action name="actionNew">
+ <property name="icon">
+ <iconset resource="icons.qrc">
+ <normaloff>:/icons/new.png</normaloff>:/icons/new.png</iconset>
+ </property>
+ <property name="text">
+ <string>New source</string>
+ </property>
+ <property name="toolTip">
+ <string>New source</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+N</string>
+ </property>
+ </action>
+ <action name="actionOpen">
+ <property name="icon">
+ <iconset resource="icons.qrc">
+ <normaloff>:/icons/open.png</normaloff>:/icons/open.png</iconset>
+ </property>
+ <property name="text">
+ <string>Open source</string>
+ </property>
+ <property name="toolTip">
+ <string>Open source</string>
+ </property>
+ <property name="shortcut">
<string>Ctrl+O</string>
</property>
</action>
+ <action name="actionSave">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="icon">
+ <iconset resource="icons.qrc">
+ <normaloff>:/icons/save.png</normaloff>:/icons/save.png</iconset>
+ </property>
+ <property name="text">
+ <string>Save source</string>
+ </property>
+ <property name="toolTip">
+ <string>Save source</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+S</string>
+ </property>
+ </action>
+ <action name="actionSaveAs">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Save source as</string>
+ </property>
+ <property name="toolTip">
+ <string>Save source as</string>
+ </property>
+ </action>
+ <action name="actionClose">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="icon">
+ <iconset resource="icons.qrc">
+ <normaloff>:/icons/closetab.png</normaloff>:/icons/closetab.png</iconset>
+ </property>
+ <property name="text">
+ <string>Close source</string>
+ </property>
+ <property name="toolTip">
+ <string>Close source</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+C</string>
+ </property>
+ </action>
<action name="actionExit">
<property name="icon">
<iconset resource="icons.qrc">
@@ -167,11 +254,6 @@
<string>Ctrl+Q</string>
</property>
</action>
- <action name="actionRestart">
- <property name="text">
- <string>Restart</string>
- </property>
- </action>
<action name="actionRun">
<property name="icon">
<iconset resource="icons.qrc">
@@ -193,7 +275,7 @@
<string>Step</string>
</property>
<property name="shortcut">
- <string>Ctrl+S</string>
+ <string>Ctrl+T</string>
</property>
</action>
<action name="actionPause">
@@ -366,7 +448,7 @@
</action>
<action name="actionAbout">
<property name="text">
- <string>&amp;About Qt Mips</string>
+ <string>About Qt Mips</string>
</property>
</action>
<action name="ipsMax">
@@ -374,7 +456,7 @@
<bool>true</bool>
</property>
<property name="text">
- <string>&amp;Max</string>
+ <string>Max</string>
</property>
<property name="toolTip">
<string>Run at maximal speed, skip visualization for 100 msec</string>
diff --git a/qtmips_gui/icons.qrc b/qtmips_gui/icons.qrc
index ca3300d..0cee7e9 100644
--- a/qtmips_gui/icons.qrc
+++ b/qtmips_gui/icons.qrc
@@ -11,5 +11,9 @@
<file>icons/refresh.png</file>
<file>icons/play.png</file>
<file>icons/stop.png</file>
+ <file>icons/new.png</file>
+ <file>icons/open.png</file>
+ <file>icons/save.png</file>
+ <file>icons/closetab.png</file>
</qresource>
</RCC>
diff --git a/qtmips_gui/mainwindow.cpp b/qtmips_gui/mainwindow.cpp
index 597b286..4ad3b0f 100644
--- a/qtmips_gui/mainwindow.cpp
+++ b/qtmips_gui/mainwindow.cpp
@@ -38,6 +38,9 @@
#include <QPrinter>
#include <QPrintDialog>
#endif
+#include <QFile>
+#include <QFileInfo>
+#include <QMessageBox>
#include "mainwindow.h"
#include "aboutdialog.h"
@@ -48,6 +51,7 @@
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
machine = nullptr;
corescene = nullptr;
+ current_srceditor = nullptr;
coreview_shown = true;
settings = new QSettings("CTU", "QtMips");
@@ -55,9 +59,12 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
ui->setupUi(this);
setWindowTitle("QtMips");
+ central_window = new QTabWidget(this);
+ this->setCentralWidget(central_window);
+
// Prepare empty core view
coreview = new GraphicsView(this);
- this->setCentralWidget(coreview);
+ central_window->addTab(coreview, "Core");
// Create/prepare other widgets
ndialog = new NewDialog(this, settings);
registers = new RegistersDock(this);
@@ -92,9 +99,14 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
// Connect signals from menu
connect(ui->actionExit, SIGNAL(triggered(bool)), this, SLOT(close()));
- connect(ui->actionNew, SIGNAL(triggered(bool)), this, SLOT(new_machine()));
+ connect(ui->actionNewMachine, SIGNAL(triggered(bool)), this, SLOT(new_machine()));
connect(ui->actionReload, SIGNAL(triggered(bool)), this, SLOT(machine_reload()));
connect(ui->actionPrint, SIGNAL(triggered(bool)), this, SLOT(print_action()));
+ connect(ui->actionNew, SIGNAL(triggered(bool)), this, SLOT(new_source()));
+ connect(ui->actionOpen, SIGNAL(triggered(bool)), this, SLOT(open_source()));
+ connect(ui->actionSave, SIGNAL(triggered(bool)), this, SLOT(save_source()));
+ connect(ui->actionSaveAs, SIGNAL(triggered(bool)), this, SLOT(save_source_as()));
+ connect(ui->actionClose, SIGNAL(triggered(bool)), this, SLOT(close_source()));
connect(ui->actionShow_Symbol, SIGNAL(triggered(bool)), this, SLOT(show_symbol_dialog()));
connect(ui->actionRegisters, SIGNAL(triggered(bool)), this, SLOT(show_registers()));
connect(ui->actionProgram_memory, SIGNAL(triggered(bool)), this, SLOT(show_program()));
@@ -118,6 +130,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
// Restore application state from settings
restoreState(settings->value("windowState").toByteArray());
restoreGeometry(settings->value("windowGeometry").toByteArray());
+
+ // Source editor related actions
+ connect(central_window, SIGNAL(currentChanged(int)), this, SLOT(central_tab_changed(int)));
}
MainWindow::~MainWindow() {
@@ -125,6 +140,7 @@ MainWindow::~MainWindow() {
delete corescene;
if (coreview != nullptr)
delete coreview;
+ delete central_window;
delete ndialog;
delete registers;
delete program;
@@ -150,7 +166,7 @@ void MainWindow::show_hide_coreview(bool show) {
coreview_shown = show;
if (!show && (corescene == nullptr))
return;
- if (((machine == nullptr) || !show) && (corescene != nullptr)) {
+ if ((machine == nullptr) || !show) {
delete corescene;
corescene = nullptr;
if (coreview != nullptr)
@@ -263,6 +279,8 @@ void MainWindow::new_machine() {
}
void MainWindow::machine_reload() {
+ if (machine == nullptr)
+ return new_machine();
bool load_executable = machine->executable_loaded();
machine::MachineConfig cnf(&machine->config()); // We have to make local copy as create_core will delete current machine
try {
@@ -433,3 +451,91 @@ void MainWindow::machine_trap(machine::QtMipsException &e) {
msg.setWindowTitle("Machine trapped");
msg.exec();
}
+
+void MainWindow::setCurrentSrcEditor(SrcEditor *srceditor) {
+ current_srceditor = srceditor;
+ if (srceditor == nullptr) {
+ ui->actionSave->setEnabled(false);
+ ui->actionSaveAs->setEnabled(false);
+ ui->actionClose->setEnabled(false);
+ } else {
+ ui->actionSave->setEnabled(true);
+ ui->actionSaveAs->setEnabled(true);
+ ui->actionClose->setEnabled(true);
+ }
+}
+
+void MainWindow::tab_widget_destroyed(QObject *obj) {
+ if (obj == current_srceditor)
+ setCurrentSrcEditor(nullptr);
+}
+
+void MainWindow::central_tab_changed(int index) {
+ QWidget *widget = central_window->widget(index);
+ SrcEditor *srceditor = dynamic_cast<SrcEditor *>(widget);
+ if (srceditor != nullptr)
+ setCurrentSrcEditor(srceditor);
+}
+
+void MainWindow::new_source() {
+ SrcEditor *editor = new SrcEditor();
+ central_window->addTab(editor, editor->title());
+ central_window->setCurrentWidget(editor);
+ connect(editor, SIGNAL(destroyed(QObject*)), this, SLOT(tab_widget_destroyed(QObject*)));
+}
+
+void MainWindow::open_source() {
+ QString file_name = "";
+
+ file_name = QFileDialog::getOpenFileName(this, tr("Open File"), "", "Source Files (*.asm *.S *.s)");
+
+ if (!file_name.isEmpty()) {
+ SrcEditor *editor = new SrcEditor();
+ if (editor->loadFile(file_name)) {
+ central_window->addTab(editor, editor->title());
+ central_window->setCurrentWidget(editor);
+ connect(editor, SIGNAL(destroyed(QObject*)), this, SLOT(tab_widget_destroyed(QObject*)));
+ } else {
+ QMessageBox::critical(this, "QtMips Error", tr("Cannot open file '%1' for reading.").arg(file_name));
+ delete(editor);
+ }
+ }
+}
+
+void MainWindow::save_source_as() {
+ if (current_srceditor == nullptr)
+ return;
+ QFileDialog fileDialog(this, tr("Save as..."));
+ fileDialog.setAcceptMode(QFileDialog::AcceptSave);
+ fileDialog.setDefaultSuffix("s");
+ if (fileDialog.exec() != QDialog::Accepted)
+ return;
+ const QString fn = fileDialog.selectedFiles().first();
+ if (current_srceditor->saveFile(fn)) {
+ int idx = central_window->indexOf(current_srceditor);
+ if (idx >= 0)
+ central_window->setTabText(idx, current_srceditor->title());
+ } else {
+ QMessageBox::critical(this, "QtMips Error", tr("Cannot save file '%1'.").arg(fn));
+ }
+}
+
+void MainWindow::save_source() {
+ if (current_srceditor == nullptr)
+ return;
+ if (current_srceditor->filename().isEmpty())
+ return save_source_as();
+ if (!current_srceditor->saveFile()) {
+ QMessageBox::critical(this, "QtMips Error", tr("Cannot save file '%1'.").arg(current_srceditor->filename()));
+ }
+}
+
+void MainWindow::close_source() {
+ if (current_srceditor == nullptr)
+ return;
+ int idx = central_window->indexOf(current_srceditor);
+ if (idx >= 0)
+ central_window->removeTab(idx);
+ delete current_srceditor;
+ current_srceditor = nullptr;
+}
diff --git a/qtmips_gui/mainwindow.h b/qtmips_gui/mainwindow.h
index 0762e8b..b051309 100644
--- a/qtmips_gui/mainwindow.h
+++ b/qtmips_gui/mainwindow.h
@@ -38,6 +38,7 @@
#include <QMainWindow>
#include <QSettings>
+#include <QTabWidget>
#include "ui_MainWindow.h"
#include "newdialog.h"
#include "coreview.h"
@@ -52,6 +53,7 @@
#include "qtmipsmachine.h"
#include "machineconfig.h"
+#include "srceditor.h"
class MainWindow : public QMainWindow {
Q_OBJECT
@@ -70,6 +72,11 @@ public slots:
void new_machine();
void machine_reload();
void print_action();
+ void new_source();
+ void open_source();
+ void save_source();
+ void save_source_as();
+ void close_source();
void show_registers();
void show_program();
void show_memory();
@@ -90,14 +97,18 @@ public slots:
void machine_status(enum machine::QtMipsMachine::Status st);
void machine_exit();
void machine_trap(machine::QtMipsException &e);
+ void central_tab_changed(int index);
+ void tab_widget_destroyed(QObject *obj);
protected:
void closeEvent(QCloseEvent *event);
+ void setCurrentSrcEditor(SrcEditor *srceditor);
private:
Ui::MainWindow *ui;
NewDialog *ndialog;
+ QTabWidget *central_window;
GraphicsView *coreview;
CoreViewScene *corescene;
@@ -111,6 +122,7 @@ private:
LcdDisplayDock *lcd_display;
Cop0Dock *cop0dock;
bool coreview_shown;
+ SrcEditor *current_srceditor;
QActionGroup *speed_group;
diff --git a/qtmips_gui/qtmips_gui.pro b/qtmips_gui/qtmips_gui.pro
index 2e6287d..109503b 100644
--- a/qtmips_gui/qtmips_gui.pro
+++ b/qtmips_gui/qtmips_gui.pro
@@ -72,7 +72,8 @@ SOURCES += \
gotosymboldialog.cpp \
cop0dock.cpp \
hinttabledelegate.cpp \
- coreview/minimux.cpp
+ coreview/minimux.cpp \
+ srceditor.cpp
HEADERS += \
mainwindow.h \
@@ -115,7 +116,8 @@ HEADERS += \
gotosymboldialog.h \
cop0dock.h \
hinttabledelegate.h \
- coreview/minimux.h
+ coreview/minimux.h \
+ srceditor.h
wasm: SOURCES += \
qhtml5file_html5.cpp
diff --git a/qtmips_gui/srceditor.cpp b/qtmips_gui/srceditor.cpp
new file mode 100644
index 0000000..79e16e9
--- /dev/null
+++ b/qtmips_gui/srceditor.cpp
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*******************************************************************************
+ * QtMips - MIPS 32-bit Architecture Subset Simulator
+ *
+ * Implemented to support following courses:
+ *
+ * B35APO - Computer Architectures
+ * https://cw.fel.cvut.cz/wiki/courses/b35apo
+ *
+ * B4M35PAP - Advanced Computer Architectures
+ * https://cw.fel.cvut.cz/wiki/courses/b4m35pap/start
+ *
+ * Copyright (c) 2017-2019 Karel Koci<cynerd@email.cz>
+ * Copyright (c) 2019 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ *
+ * Faculty of Electrical Engineering (http://www.fel.cvut.cz)
+ * Czech Technical University (http://www.cvut.cz/)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ ******************************************************************************/
+
+#include <QFile>
+#include <QFileInfo>
+#include <QTextDocumentWriter>
+
+#include "srceditor.h"
+
+SrcEditor::SrcEditor(QWidget *parent) : Super(parent) {
+ tname = "Unknown";
+}
+
+SrcEditor::SrcEditor(const QString &text, QWidget *parent) : Super(text, parent) {
+ tname = "Unknown";
+}
+
+SrcEditor::~SrcEditor() {
+
+}
+
+QString SrcEditor::filename() {
+ return fname;
+}
+
+QString SrcEditor::title() {
+ return tname;
+}
+
+bool SrcEditor::loadFile(QString filename) {
+ QFile file(filename);
+ QFileInfo fi(filename);
+ if (file.open(QFile::ReadOnly | QFile::Text)) {
+ setPlainText(file.readAll());
+ fname = filename;
+ tname = fi.fileName();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool SrcEditor::saveFile(QString filename) {
+ if (filename.isEmpty())
+ filename = this->filename();
+ if (filename.isEmpty())
+ return false;
+ QFileInfo fi(filename);
+ QTextDocumentWriter writer(filename);
+ writer.setFormat("plaintext");
+ bool success = writer.write(document());
+ if (success) {
+ fname = filename;
+ tname = fi.fileName();
+ }
+ return success;
+}
diff --git a/qtmips_gui/srceditor.h b/qtmips_gui/srceditor.h
new file mode 100644
index 0000000..4deeb5f
--- /dev/null
+++ b/qtmips_gui/srceditor.h
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*******************************************************************************
+ * QtMips - MIPS 32-bit Architecture Subset Simulator
+ *
+ * Implemented to support following courses:
+ *
+ * B35APO - Computer Architectures
+ * https://cw.fel.cvut.cz/wiki/courses/b35apo
+ *
+ * B4M35PAP - Advanced Computer Architectures
+ * https://cw.fel.cvut.cz/wiki/courses/b4m35pap/start
+ *
+ * Copyright (c) 2017-2019 Karel Koci<cynerd@email.cz>
+ * Copyright (c) 2019 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ *
+ * Faculty of Electrical Engineering (http://www.fel.cvut.cz)
+ * Czech Technical University (http://www.cvut.cz/)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ ******************************************************************************/
+
+#ifndef SRCEDITOR_H
+#define SRCEDITOR_H
+
+#include <QTextEdit>
+#include <QString>
+#include "qtmipsmachine.h"
+
+class SrcEditor : public QTextEdit {
+ Q_OBJECT
+ using Super = QTextEdit;
+public:
+ SrcEditor(const QString &text, QWidget *parent = nullptr);
+ SrcEditor(QWidget *parent = nullptr);
+ ~SrcEditor();
+ QString filename();
+ QString title();
+ bool loadFile(QString filename);
+ bool saveFile(QString filename = "");
+private:
+ QString fname;
+ QString tname;
+};
+
+#endif // SRCEDITOR_H