From 5e5f2b2162c4c5ec967a72580b90fa1c7ec0b4ab Mon Sep 17 00:00:00 2001 From: Inoki Date: Wed, 4 May 2022 14:42:02 +0200 Subject: [PATCH] Allow to manually add a LoadOption --- qefientryview.cpp | 110 ++++++++++++++++++++++++++++++++++- qefientryview.h | 2 + qefiloadoptioneditorview.cpp | 55 ++++++++++++++---- qefiloadoptioneditorview.h | 8 +++ 4 files changed, 161 insertions(+), 14 deletions(-) diff --git a/qefientryview.cpp b/qefientryview.cpp index dc29063..e039d56 100644 --- a/qefientryview.cpp +++ b/qefientryview.cpp @@ -15,8 +15,10 @@ #include #include #include +#include #include "qefientrydetailview.h" +#include "qefiloadoptioneditorview.h" #if QT_VERSION >= QT_VERSION_CHECK(5,14,0) // Fix namsapce change of hex and dec @@ -76,13 +78,17 @@ QEFIEntryView::QEFIEntryView(QWidget *parent) m_bootTimeoutLabel = new QLabel(QString::asprintf("Timeout: %d second(s)", QEFIEntryStaticList::instance()->timeout()), this); + m_addButton = new QPushButton(QStringLiteral("Add"), this); m_importButton = new QPushButton(QStringLiteral("Import"), this); m_saveButton = new QPushButton(QStringLiteral("Save"), this); m_resetButton = new QPushButton(QStringLiteral("Reset"), this); m_buttonLayout->addWidget(m_bootTimeoutLabel); + m_buttonLayout->addWidget(m_addButton); m_buttonLayout->addWidget(m_importButton); m_buttonLayout->addWidget(m_saveButton); m_buttonLayout->addWidget(m_resetButton); + QObject::connect(m_addButton, &QPushButton::clicked, + this, &QEFIEntryView::addClicked); QObject::connect(m_importButton, &QPushButton::clicked, this, &QEFIEntryView::importClicked); QObject::connect(m_saveButton, &QPushButton::clicked, @@ -116,6 +122,7 @@ QEFIEntryView::~QEFIEntryView() if (m_rebootTargetButton != nullptr) m_rebootTargetButton->deleteLater(); if (m_bootTimeoutLabel != nullptr) m_bootTimeoutLabel->deleteLater(); if (m_importButton != nullptr) m_importButton->deleteLater(); + if (m_addButton != nullptr) m_addButton->deleteLater(); } void QEFIEntryView::entryChanged(int currentRow) @@ -357,8 +364,8 @@ void QEFIEntryView::contextMenuEvent(QContextMenuEvent *event) menu.addSeparator(); } } - // TODO: Allow to add new one - // menu.addAction(QStringLiteral("Add")); + connect(menu.addAction(QStringLiteral("Add")), &QAction::triggered, + this, &QEFIEntryView::addClicked); connect(menu.addAction(QStringLiteral("Import")), &QAction::triggered, this, &QEFIEntryView::importClicked); @@ -445,3 +452,102 @@ void QEFIEntryView::importClicked(bool checked) m_selectedItemIndex = -1; resetClicked(false); } + +class BootEntryEditorDialog : public QDialog +{ + QEFILoadOptionEditorView *m_view; + QBoxLayout *m_topLevelLayout; + QDialogButtonBox *m_buttonBox; + + quint16 m_bootID; + QByteArray m_loadOptionData; +public: + BootEntryEditorDialog(QWidget *parent = nullptr) + : QDialog(parent) + { + m_view = new QEFILoadOptionEditorView(nullptr, this); + setWindowTitle(QStringLiteral("Add EFI Boot Entry")); + m_topLevelLayout = new QBoxLayout(QBoxLayout::Down, this); + m_topLevelLayout->addWidget(m_view); + + m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | + QDialogButtonBox::Cancel); + m_topLevelLayout->addWidget(m_buttonBox); + + connect(m_buttonBox, &QDialogButtonBox::accepted, + this, &BootEntryEditorDialog::onAccept); + connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + } + + quint16 bootID() const { return m_bootID; } + QByteArray loadOptionData() const { return m_loadOptionData; } + + ~BootEntryEditorDialog() + { + if (m_topLevelLayout) m_topLevelLayout->deleteLater(); + if (m_view) m_view->deleteLater(); + if (m_buttonBox) m_buttonBox->deleteLater(); + } + +public slots: + void onAccept() { + // Init the class from the view + if (m_view != nullptr) { + m_bootID = m_view->getBootEntryID(); + m_loadOptionData = m_view->generateLoadOption(); + qDebug() << "Will add Boot Entry " << m_bootID << m_loadOptionData; + } + accept(); + } +}; + +void QEFIEntryView::addClicked(bool checked) +{ + Q_UNUSED(checked); + BootEntryEditorDialog dialog(this); + if (dialog.exec() == QDialog::Rejected) return; + + // Get Load Option and add it + quint16 bootID = dialog.bootID(); + QByteArray data = dialog.loadOptionData(); + if (data.size() == 0) { + // Error + QMessageBox::warning(this, QStringLiteral("Add failed"), + QStringLiteral("Data might be invalidated.")); + } + + // Parse using a QEFILoadOption + QEFILoadOption loadOption(data); + if (!loadOption.isValidated()) { + // Show a warning and stop + QMessageBox::warning(this, QStringLiteral("Add failed"), + QStringLiteral("Data are invalidated.")); + return; + } + + bool orderFound = m_order.contains(bootID); + if (orderFound) { + // Override: Show a confirmation + if (QMessageBox::question(this, QStringLiteral("Add"), + QString::asprintf("Do you want to override Boot%04X?", bootID)) == + QMessageBox::No) { + // Show a warning and stop + QMessageBox::warning(this, QStringLiteral("Add failed"), + QStringLiteral("The action is cancelled.")); + return; + } + } + + if (!QEFIEntryStaticList::instance()->updateBootEntry(bootID, data)) { + // Show a warning and stop + QMessageBox::warning(this, QStringLiteral("Add failed"), + QStringLiteral("Data might be invalidated.")); + return; + } + + // Check and update the list + if (!orderFound) m_order.append(bootID); + m_entryItems = QEFIEntryStaticList::instance()->entries(); + m_selectedItemIndex = -1; + resetClicked(false); +} diff --git a/qefientryview.h b/qefientryview.h index 0d9cbdf..f821a9a 100644 --- a/qefientryview.h +++ b/qefientryview.h @@ -29,6 +29,7 @@ class QEFIEntryView: public QWidget QPushButton *m_saveButton; QPushButton *m_resetButton; QPushButton *m_rebootTargetButton; + QPushButton *m_addButton; QLabel *m_bootTimeoutLabel; @@ -57,6 +58,7 @@ public slots: void importClicked(bool checked); void exportClicked(bool checked); void deleteClicked(bool checked); + void addClicked(bool checked); void moveUpClicked(bool checked); void moveDownClicked(bool checked); diff --git a/qefiloadoptioneditorview.cpp b/qefiloadoptioneditorview.cpp index e66a773..d1d1d17 100644 --- a/qefiloadoptioneditorview.cpp +++ b/qefiloadoptioneditorview.cpp @@ -1,6 +1,7 @@ #include "qefiloadoptioneditorview.h" #include "qefidpeditorview.h" +#include #include class EditorDialog : public QDialog @@ -13,7 +14,7 @@ class EditorDialog : public QDialog { m_view = new QEFIDPEditorView(nullptr, this); setWindowTitle(QStringLiteral("Add Device Path")); - m_topLevelLayout = new QBoxLayout(QBoxLayout::LeftToRight, this); + m_topLevelLayout = new QBoxLayout(QBoxLayout::Down, this); m_topLevelLayout->addWidget(m_view); } @@ -29,17 +30,21 @@ QEFILoadOptionEditorView::QEFILoadOptionEditorView(QEFILoadOption *option, QWidg { m_topLevelLayout = new QFormLayout(this); - QSpinBox *idSpinBox = new QSpinBox(this); - idSpinBox->setMinimum(0); - idSpinBox->setMaximum(0xFFFF); - idSpinBox->setDisplayIntegerBase(16); + m_idSpinBox = new QSpinBox(this); + m_idSpinBox->setMinimum(0); + m_idSpinBox->setMaximum(0xFFFF); + m_idSpinBox->setValue(0x1000); + m_idSpinBox->setSingleStep(1); + m_idSpinBox->setDisplayIntegerBase(16); - m_topLevelLayout->addRow(QStringLiteral("ID:"), idSpinBox); - m_topLevelLayout->addRow(QStringLiteral("Name:"), new QLineEdit(option == nullptr ? - QStringLiteral("") : option->name(), this)); - m_topLevelLayout->addRow(QStringLiteral("Optional Data:"), - new QLineEdit(option == nullptr ? QStringLiteral("") : - QString(option->optionalData().toHex()), this)); + m_topLevelLayout->addRow(QStringLiteral("ID:"), m_idSpinBox); + m_nameTextEdit = new QLineEdit(option == nullptr ? QStringLiteral("") : + option->name(), this); + m_topLevelLayout->addRow(QStringLiteral("Name:"), m_nameTextEdit); + m_optionalDataTextEdit = new QLineEdit(option == nullptr ? QStringLiteral("") : + QString(option->optionalData().toHex()), this); + m_topLevelLayout->addRow(QStringLiteral("Optional Data:"), m_optionalDataTextEdit); + #define DP_BEGIN_INDEX 3 QPushButton *button = new QPushButton(QStringLiteral("Add Device Path"), this); m_topLevelLayout->addRow(QStringLiteral(""), button); connect(button, &QPushButton::clicked, @@ -54,12 +59,38 @@ QEFILoadOptionEditorView::~QEFILoadOptionEditorView() m_topLevelLayout->deleteLater(); m_topLevelLayout = nullptr; } + if (m_idSpinBox != nullptr) m_idSpinBox->deleteLater(); } void QEFILoadOptionEditorView::createDPClicked(bool checked) { Q_UNUSED(checked); EditorDialog dialog(this); - dialog.exec(); + if (dialog.exec() == QDialog::Rejected) return; // TODO: Get Device Path and add it } + +QByteArray QEFILoadOptionEditorView::generateLoadOption() +{ + QByteArray data; + if (m_nameTextEdit == nullptr) return data; + if (m_optionalDataTextEdit == nullptr) return data; + + QEFILoadOption newLoadOption(data); + newLoadOption.setIsVisible(true); + newLoadOption.setName(m_nameTextEdit->text()); + QByteArray optionalData = QByteArray::fromHex( + m_optionalDataTextEdit->text().toLatin1()); + // Check format + if (optionalData.size() * 2 != m_optionalDataTextEdit->text().length()) return data; + newLoadOption.setOptionalData(optionalData); + // TODO: Format DPs + + return newLoadOption.format(); +} + +quint16 QEFILoadOptionEditorView::getBootEntryID() +{ + if (m_idSpinBox == nullptr) return 0; + return (quint16)(m_idSpinBox->value() & 0xFFFF); +} diff --git a/qefiloadoptioneditorview.h b/qefiloadoptioneditorview.h index 1f5a101..08d898f 100644 --- a/qefiloadoptioneditorview.h +++ b/qefiloadoptioneditorview.h @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -16,11 +17,18 @@ class QEFILoadOptionEditorView: public QWidget QFormLayout *m_topLevelLayout; + QSpinBox *m_idSpinBox; + QLineEdit *m_nameTextEdit; + QLineEdit *m_optionalDataTextEdit; + public: QEFILoadOptionEditorView(QEFILoadOption *option = nullptr, QWidget *parent = nullptr); ~QEFILoadOptionEditorView(); + QByteArray generateLoadOption(); + quint16 getBootEntryID(); + public slots: void createDPClicked(bool checked); };