[WIP] Add LoadDialog for loading different file types
ADD
src/loaddialog.cpp
+#include "loaddialog.h"
+#include "ui_loaddialog.h"
+
+#include "processorhandler.h"
+#include "program.h"
+#include "radix.h"
+
+#include <QButtonGroup>
+#include <QFile>
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QRegExpValidator>
+
+namespace Ripes {
+
+LoadDialog::LoadDialog(QWidget* parent) : QDialog(parent), m_ui(new Ui::LoadDialog) {
+ m_ui->setupUi(this);
+
+ setWindowTitle("Load program...");
+
+ m_fileTypeButtons = new QButtonGroup(this);
+ m_fileTypeButtons->addButton(m_ui->assemblyRadioButton);
+ m_fileTypeButtons->addButton(m_ui->binaryRadioButton);
+ m_fileTypeButtons->addButton(m_ui->elfRadioButton);
+
+ connect(m_fileTypeButtons, QOverload<int, bool>::of(&QButtonGroup::buttonToggled), this,
+ &LoadDialog::inputTypeChanged);
+ connect(m_ui->openFile, &QPushButton::clicked, this, &LoadDialog::openFileButtonTriggered);
+ connect(m_ui->filePath, &QLineEdit::textChanged, this, &LoadDialog::validateCurrentFile);
+
+ // ===================== Page setups =====================
+
+ // Assembly page
+
+ // Binary page
+ QRegExpValidator* validator = new QRegExpValidator(this);
+ validator->setRegExp(hexRegex32);
+ m_ui->binaryLoadAt->setValidator(validator);
+ m_ui->binaryLoadAt->setText("0x00000000");
+ m_ui->binaryEntryPoint->setValidator(validator);
+ m_ui->binaryEntryPoint->setText("0x00000000");
+ connect(m_ui->binaryLoadAt, &QLineEdit::textChanged, [=] { this->validateCurrentFile(); });
+ connect(m_ui->binaryEntryPoint, &QLineEdit::textChanged, [=] { this->validateCurrentFile(); });
+
+ // ELF page
+
+ // default selection
+ m_ui->assemblyRadioButton->toggle();
+ validateCurrentFile();
+}
+
+void LoadDialog::inputTypeChanged() {
+ auto* button = m_fileTypeButtons->checkedButton();
+ if (button == m_ui->assemblyRadioButton) {
+ m_currentFileType = FileType::Assembly;
+ updateAssemblyPageState();
+ } else if (button == m_ui->binaryRadioButton) {
+ m_currentFileType = FileType::FlatBinary;
+ updateBinaryPageState();
+ } else if (button == m_ui->elfRadioButton) {
+ m_currentFileType = FileType::Executable;
+ updateELFPageState();
+ }
+ validateCurrentFile();
+}
+
+void LoadDialog::openFileButtonTriggered() {
+ QString title;
+ QString filter = "*";
+ switch (m_currentFileType) {
+ case FileType::Assembly: {
+ title = "Open assembly file";
+ filter = "Assembly file (*.s *.as *.asm)";
+ break;
+ }
+ case FileType::FlatBinary: {
+ title = "Open binary file";
+ break;
+ }
+ case FileType::Executable: {
+ title = "Open executable (ELF) file";
+ break;
+ }
+ }
+
+ const auto filename = QFileDialog::getOpenFileName(this, title, "", filter);
+ m_ui->filePath->setText(filename);
+}
+
+void LoadDialog::paletteValidate(QWidget* w, bool valid) {
+ QPalette palette = this->palette();
+ if (!valid) {
+ palette.setColor(QPalette::Base, QColor("#eb8383"));
+ }
+ w->setPalette(palette);
+}
+
+bool LoadDialog::validateAssemblyFile(const QFile& file) {
+ return true;
+}
+bool LoadDialog::validateBinaryFile(const QFile& file) {
+ bool loadAtValid, entryPointValid;
+ m_ui->binaryLoadAt->text().toUInt(&loadAtValid, 16);
+ paletteValidate(m_ui->binaryLoadAt, loadAtValid);
+
+ m_ui->binaryEntryPoint->text().toUInt(&entryPointValid, 16);
+ paletteValidate(m_ui->binaryEntryPoint, entryPointValid);
+
+ return loadAtValid && entryPointValid;
+}
+bool LoadDialog::validateELFFile(const QFile& file) {
+ return true;
+}
+
+bool LoadDialog::fileTypeValidate(const QFile& file) {
+ switch (m_currentFileType) {
+ case FileType::Assembly:
+ return validateAssemblyFile(file);
+ case FileType::FlatBinary:
+ return validateBinaryFile(file);
+ case FileType::Executable:
+ return validateELFFile(file);
+ }
+}
+
+void LoadDialog::validateCurrentFile() {
+ const QString& filename = m_ui->filePath->text();
+ QFile file(filename);
+ const bool filePathValid = file.exists();
+ const bool fileTypeValid = fileTypeValidate(file);
+
+ paletteValidate(m_ui->filePath, filePathValid);
+ m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(filePathValid & fileTypeValid);
+}
+
+void LoadDialog::loadFileError(const QString& filename) {
+ QMessageBox::warning(this, "Load file error", "Error: Could not load file \"" + filename + "\"");
+ QDialog::reject();
+}
+
+void LoadDialog::accept() {
+ switch (m_currentFileType) {
+ case FileType::Assembly:
+ case FileType::FlatBinary:
+ case FileType::Executable:
+ break;
+ }
+
+ QDialog::accept();
+}
+
+void LoadDialog::updateAssemblyPageState() {
+ m_ui->fileTypePages->setCurrentIndex(0);
+}
+
+void LoadDialog::updateBinaryPageState() {
+ m_ui->fileTypePages->setCurrentIndex(1);
+}
+void LoadDialog::updateELFPageState() {
+ m_ui->fileTypePages->setCurrentIndex(2);
+}
+
+LoadDialog::~LoadDialog() {
+ delete m_ui;
+}
+
+} // namespace Ripes

ADD
src/loaddialog.h
+#pragma once
+#include <QDialog>
+
+QT_FORWARD_DECLARE_CLASS(QButtonGroup);
+QT_FORWARD_DECLARE_CLASS(QFile);
+
+#include "program.h"
+
+namespace Ripes {
+
+namespace Ui {
+class LoadDialog;
+}
+
+class LoadDialog : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit LoadDialog(QWidget* parent = nullptr);
+ ~LoadDialog();
+
+ void accept() override;
+
+private slots:
+ void validateCurrentFile();
+ void openFileButtonTriggered();
+ void inputTypeChanged();
+
+ void updateAssemblyPageState();
+ void updateBinaryPageState();
+ void updateELFPageState();
+
+ void loadFileError(const QString& filename);
+
+private:
+ bool fileTypeValidate(const QFile& file);
+ bool validateAssemblyFile(const QFile& file);
+ bool validateBinaryFile(const QFile& file);
+ bool validateELFFile(const QFile& file);
+
+ void paletteValidate(QWidget* w, bool valid);
+
+ FileType m_currentFileType;
+ Ui::LoadDialog* m_ui;
+ QButtonGroup* m_fileTypeButtons = nullptr;
+};
+
+} // namespace Ripes

ADD
src/loaddialog.ui
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Ripes::LoadDialog</class>
+ <widget class="QDialog" name="Ripes::LoadDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>432</width>
+ <height>242</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="2" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLineEdit" name="filePath"/>
+ </item>
+ <item>
+ <widget class="QPushButton" name="openFile">
+ <property name="text">
+ <string>Open...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>File type:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>File:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QRadioButton" name="assemblyRadioButton">
+ <property name="text">
+ <string>Assembly</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="binaryRadioButton">
+ <property name="text">
+ <string>Flat binary</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="elfRadioButton">
+ <property name="text">
+ <string>Executable (ELF)</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <widget class="QStackedWidget" name="fileTypePages">
+ <property name="currentIndex">
+ <number>2</number>
+ </property>
+ <widget class="QWidget" name="assemblyPage">
+ <layout class="QGridLayout" name="gridLayout_4">
+ <item row="0" column="0">
+ <layout class="QGridLayout" name="gridLayout_3"/>
+ </item>
+ <item row="1" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="binaryPage">
+ <layout class="QGridLayout" name="gridLayout_8">
+ <item row="0" column="0">
+ <layout class="QGridLayout" name="gridLayout_7">
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="binaryLoadAt"/>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Load at:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="binaryEntryPoint"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Entry point:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="elfPage">
+ <layout class="QGridLayout" name="gridLayout_6">
+ <item row="2" column="0">
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="0">
+ <layout class="QGridLayout" name="gridLayout_5">
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="currentISA">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Current ISA:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Info:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="1">
+ <widget class="QPlainTextEdit" name="elfInfo">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Ripes::LoadDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>Ripes::LoadDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>

MODIFY
src/mainwindow.cpp
src/mainwindow.cpp
#include "aboutwidget.h"
#include "defines.h"
#include "edittab.h"
+#include "loaddialog.h"
#include "memorytab.h"
#include "parser.h"
#include "processorhandler.h"
@@ -95,9 +96,9 @@ void MainWindow::setupMenus() {
m_editTab->getToolbar()->addAction(newAction);
const QIcon loadIcon = QIcon(":/icons/loadfile.svg");
- auto* loadAction = new QAction(loadIcon, "Load file", this);
+ auto* loadAction = new QAction(loadIcon, "Load program", this);
loadAction->setShortcut(QKeySequence::Open);
- connect(loadAction, &QAction::triggered, [=] { this->loadAssemblyFile(); });
+ connect(loadAction, &QAction::triggered, [=] { this->loadFileTriggered(); });
m_editTab->getToolbar()->addAction(loadAction);
m_ui->menuFile->addAction(loadAction);
@@ -175,6 +176,11 @@ void MainWindow::exit() {
close();
}
+void MainWindow::loadFileTriggered() {
+ LoadDialog diag;
+ diag.exec();
+}
+
void MainWindow::loadBinaryFile(QString filename) {
m_editTab->setInputMode(false);
m_processorTab->restart();

MODIFY
src/mainwindow.h
src/mainwindow.h
#include <QMainWindow>
+#include "program.h"
+
QT_FORWARD_DECLARE_CLASS(QToolBar)
QT_FORWARD_DECLARE_CLASS(QStackedWidget)
QT_FORWARD_DECLARE_CLASS(QActionGroup)
@@ -34,6 +36,8 @@ private slots:
void about();
void wiki();
+ void loadFileTriggered();
+
void saveFilesTriggered();
void saveFilesAsTriggered();
void newProgramTriggered();
@@ -47,6 +51,8 @@ signals:
void updateMemoryTab();
private:
+ void loadFile(const QString& filename, FileType type);
+
void setupMenus();
Ui::MainWindow* m_ui;

MODIFY
src/program.h
src/program.h
namespace Ripes {
+enum class FileType { Assembly, FlatBinary, Executable };
+
/**
* @brief The Program struct
* Wrapper around a program to be loaded into simulator memory. Text section shall contain the instructions of the

[WIP] Add LoadDialog for loading different file types