From 215b6b79c3ecc9ca0954710c0dd2a218d4c015fb Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Mon, 1 Jul 2019 14:18:45 +0200 Subject: Include simple text editor in QtMips emulator. Signed-off-by: Pavel Pisa --- qtmips_gui/MainWindow.ui | 104 +++++++++++++++++++++++++++++++++++++----- qtmips_gui/icons.qrc | 4 ++ qtmips_gui/mainwindow.cpp | 112 ++++++++++++++++++++++++++++++++++++++++++++-- qtmips_gui/mainwindow.h | 12 +++++ qtmips_gui/qtmips_gui.pro | 6 ++- qtmips_gui/srceditor.cpp | 89 ++++++++++++++++++++++++++++++++++++ qtmips_gui/srceditor.h | 59 ++++++++++++++++++++++++ 7 files changed, 370 insertions(+), 16 deletions(-) create mode 100644 qtmips_gui/srceditor.cpp create mode 100644 qtmips_gui/srceditor.h 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 @@ File - + + + + + + @@ -126,7 +131,7 @@ false - + @@ -140,7 +145,7 @@ - + :/icons/document-import.png:/icons/document-import.png @@ -148,10 +153,92 @@ New simulation... + + Ctrl+N + + + + + Restart + + + + + + :/icons/new.png:/icons/new.png + + + New source + + + New source + + + Ctrl+N + + + + + + :/icons/open.png:/icons/open.png + + + Open source + + + Open source + Ctrl+O + + + false + + + + :/icons/save.png:/icons/save.png + + + Save source + + + Save source + + + Ctrl+S + + + + + false + + + Save source as + + + Save source as + + + + + false + + + + :/icons/closetab.png:/icons/closetab.png + + + Close source + + + Close source + + + Ctrl+C + + @@ -167,11 +254,6 @@ Ctrl+Q - - - Restart - - @@ -193,7 +275,7 @@ Step - Ctrl+S + Ctrl+T @@ -366,7 +448,7 @@ - &About Qt Mips + About Qt Mips @@ -374,7 +456,7 @@ true - &Max + Max Run at maximal speed, skip visualization for 100 msec 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 @@ icons/refresh.png icons/play.png icons/stop.png + icons/new.png + icons/open.png + icons/save.png + icons/closetab.png 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 #include #endif +#include +#include +#include #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(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 #include +#include #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 + * Copyright (c) 2019 Pavel Pisa + * + * 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 +#include +#include + +#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 + * Copyright (c) 2019 Pavel Pisa + * + * 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 +#include +#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 -- cgit v1.2.3