diff options
Diffstat (limited to 'qtmips_gui')
-rw-r--r-- | qtmips_gui/MainWindow.ui | 104 | ||||
-rw-r--r-- | qtmips_gui/icons.qrc | 4 | ||||
-rw-r--r-- | qtmips_gui/mainwindow.cpp | 112 | ||||
-rw-r--r-- | qtmips_gui/mainwindow.h | 12 | ||||
-rw-r--r-- | qtmips_gui/qtmips_gui.pro | 6 | ||||
-rw-r--r-- | qtmips_gui/srceditor.cpp | 89 | ||||
-rw-r--r-- | qtmips_gui/srceditor.h | 59 |
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>&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>&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 |