Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.clangd
build/
media/
.vscode/
Expand All @@ -8,4 +9,28 @@ Dockerfile
Makefile
.qmake.stash
SyntaxTutor
SyntaxTutor.app
.cache

# Qt generated sources and headers
moc_*.cpp
moc_predefs.h
qrc_*.cpp
ui_*.h

# qmake/Qt generated build helpers
target_wrapper.sh
.objects/
.moc/
.rcc/
.ui/
.bin/

# Test build outputs
tests/target_wrapper.sh
tests/tutor_tests
tests/.objects/
tests/.moc/
tests/.rcc/
tests/.ui/
tests/.bin/
6 changes: 6 additions & 0 deletions SyntaxTutor.pro
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ TRANSLATIONS += translations/st_es.ts \

CONFIG += c++20

OBJECTS_DIR = $$OUT_PWD/.objects
MOC_DIR = $$OUT_PWD/.moc
RCC_DIR = $$OUT_PWD/.rcc
UI_DIR = $$OUT_PWD/.ui
DESTDIR = $$OUT_PWD/.bin

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
Expand Down
11 changes: 5 additions & 6 deletions resources/styles/app.qss
Original file line number Diff line number Diff line change
Expand Up @@ -533,16 +533,15 @@ QWizard[wizardTheme="slr"] QWizard::title {
font-size: 18px;
}

QWizard[wizardTheme="slr"] QWizard::subTitle {
color: #CCCCCC;
font-size: 14px;
margin-bottom: 12px;
}

QWizard[wizardTheme="slr"] QLabel {
color: #E0E0E0;
}

QWizard[wizardTheme="slr"] QLabel#slrWizardFeedbackLabel {
color: #CCCCCC;
min-height: 20px;
}

QWizard[wizardTheme="slr"] QLineEdit {
background-color: #3C3F41;
color: #E0E0E0;
Expand Down
14 changes: 14 additions & 0 deletions src/gui/slrwizard.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include "slr1_parser.hpp"
#include "slrwizardpage.h"
#include <QAbstractButton>
#include <QLabel>
#include <QLineEdit>
#include <QVBoxLayout>
Expand Down Expand Up @@ -61,6 +62,19 @@ class SLRWizard : public QWizard {
const QVector<QPair<QString, QVector<QString>>>& sortedGrammar,
QWidget* parent = nullptr)
: QWizard(parent) {
setWizardStyle(QWizard::ModernStyle);
setWindowFlag(Qt::WindowCloseButtonHint, true);
setButtonText(QWizard::CancelButton, tr("Salir"));
setButtonText(QWizard::NextButton, tr("Continuar"));
setButtonText(QWizard::FinishButton, tr("Finalizar"));
setButtonLayout({QWizard::Stretch, QWizard::CancelButton,
QWizard::NextButton, QWizard::FinishButton});

if (auto* backButton = button(QWizard::BackButton)) {
backButton->hide();
backButton->setEnabled(false);
}

setWindowTitle(tr("Ayuda interactiva: Tabla SLR(1)"));

const int nTerm = parser.gr_.st_.terminals_.size();
Expand Down
27 changes: 22 additions & 5 deletions src/gui/slrwizardpage.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,24 @@ class SLRWizardPage : public QWizardPage {
: QWizardPage(parent), m_state(state), m_symbol(symbol),
m_expected(expected) {
setTitle(tr("Estado %1, símbolo '%2'").arg(state).arg(symbol));
setSubTitle(QString());

QLabel* lbl = new QLabel(explanation, this);
lbl->setWordWrap(true);

m_feedback = new QLabel(this);
m_feedback->setObjectName("slrWizardFeedbackLabel");
m_feedback->setWordWrap(true);
m_feedback->hide();

m_edit = new QLineEdit(this);
m_edit->setObjectName("slrWizardAnswerEdit");
m_edit->setPlaceholderText(
tr("Escribe tu respuesta (p.ej. s3, r2, acc, 5)"));

QVBoxLayout* layout = new QVBoxLayout(this);
layout->addWidget(lbl);
layout->addWidget(m_feedback);
layout->addWidget(m_edit);
setLayout(layout);

Expand All @@ -83,15 +90,24 @@ class SLRWizardPage : public QWizardPage {
* @param text The current user input.
*/
void onTextChanged(const QString& text) {
bool correct = (text.trimmed() == m_expected);
const QString trimmed = text.trimmed();
bool correct = (trimmed == m_expected);
setComplete(correct);
if (correct) {
setSubTitle(

if (trimmed.isEmpty()) {
m_feedback->clear();
m_feedback->hide();
} else if (correct) {
m_feedback->setText(
tr("✔ Respuesta correcta, pasa a la siguiente pregunta"));
m_feedback->show();
} else {
setSubTitle(tr("✘ Incorrecto, revisa el enunciado. Consulta los "
"estados que has construido."));
m_feedback->setText(tr("✘ Incorrecto, revisa el enunciado. "
"Consulta los estados que has "
"construido."));
m_feedback->show();
}

wizard()->button(QWizard::NextButton)->setEnabled(correct);
}

Expand All @@ -115,6 +131,7 @@ class SLRWizardPage : public QWizardPage {
int m_state; ///< The state index of the cell.
QString m_symbol; ///< The symbol (terminal or non-terminal).
QString m_expected; ///< The expected user response.
QLabel* m_feedback; ///< Inline feedback label for answer validation.
QLineEdit* m_edit; ///< Input field for the user's answer.
bool m_isComplete =
false; ///< Whether the user has entered the correct response.
Expand Down
9 changes: 5 additions & 4 deletions tests/tests.pro
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ INCLUDEPATH += \
$$PWD/helpers \
$$PWD/fixtures/grammars

OBJECTS_DIR = .objects
MOC_DIR = .moc
RCC_DIR = .rcc
UI_DIR = .ui
OBJECTS_DIR = $$OUT_PWD/.objects
MOC_DIR = $$OUT_PWD/.moc
RCC_DIR = $$OUT_PWD/.rcc
UI_DIR = $$OUT_PWD/.ui
DESTDIR = $$OUT_PWD/.bin

SOURCES += \
../src/backend/grammar.cpp \
Expand Down
69 changes: 69 additions & 0 deletions tests/tutor/slr_tutor_window_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <QCoreApplication>
#include <QDebug>
#include <QFileInfo>
#include <QLabel>
#include <QPointer>
#include <QPushButton>
#include <QSignalSpy>
Expand Down Expand Up @@ -680,6 +681,74 @@ void TutorWindowTest::slrStateHIncorrectTableKeepsDialogOpen() {
QVERIFY(dialog->isVisible());
}

// -----------------------------------------------------------------------------
// Case: SLR1-TC-17A
// Summary:
// Verifies that guided mode uses the custom wizard navigation and can be
// exited without going backwards.
//
// Situation:
// SLR(1) tutor in H with the table dialog visible.
//
// Action:
// The user opens guided mode and then exits through the wizard cancel button.
//
// Expected:
// The wizard uses the configured non-native style, does not expose a back
// button, and closes back to the table dialog.
// -----------------------------------------------------------------------------
void TutorWindowTest::slrGuidedModeWizardUsesCustomNavigationAndAllowsExit() {
const Grammar grammar = TutorGrammarFixtures::makeSlrSimpleGrammar();

SLRTutorWindow tutor(grammar, nullptr);
SlrTutorTestUtils::submitCorrectAnswerForCurrentState(tutor);
driveSlrTutorToH(tutor);

SLRTableDialog* dialog = waitForSlrTableDialog();
auto* table = dialog->findChild<QTableWidget*>("slrTableWidget");
QVERIFY(table != nullptr);

QtModalTestUtils::requestSlrGuidedMode(
dialog, QVector<QVector<QString>>(table->rowCount(),
QVector<QString>(table->columnCount())));
QWizard* wizard = waitForWizard();
QVERIFY(wizard != nullptr);
QPointer<QWizard> wizardGuard(wizard);
auto* page = qobject_cast<SLRWizardPage*>(wizard->currentPage());
QVERIFY(page != nullptr);

QCOMPARE(wizard->wizardStyle(), QWizard::ModernStyle);
QCOMPARE(page->subTitle(), QString());

auto* backButton = wizard->button(QWizard::BackButton);
QVERIFY(backButton != nullptr);
QVERIFY(!backButton->isVisibleTo(wizard));
QVERIFY(!backButton->isEnabled());

auto* feedbackLabel = page->findChild<QLabel*>("slrWizardFeedbackLabel");
QVERIFY(feedbackLabel != nullptr);
QVERIFY(!feedbackLabel->isVisible());

auto* edit = page->findChild<QLineEdit*>("slrWizardAnswerEdit");
QVERIFY(edit != nullptr);
edit->setText(QStringLiteral("s"));
QApplication::processEvents();

QCOMPARE(page->subTitle(), QString());
QVERIFY(feedbackLabel->isVisible());
QVERIFY(!feedbackLabel->text().isEmpty());

auto* cancelButton = qobject_cast<QPushButton*>(
wizard->button(QWizard::CancelButton));
QVERIFY(cancelButton != nullptr);
QVERIFY(cancelButton->isVisibleTo(wizard));

QTest::mouseClick(cancelButton, Qt::LeftButton);
QTRY_VERIFY(wizardGuard == nullptr || !wizardGuard->isVisible());
QVERIFY(dialog->isVisible());
QCOMPARE(tutor.currentStateForTest(), QString("H"));
}

// -----------------------------------------------------------------------------
// Case: SLR1-TC-18
// Summary:
Expand Down
1 change: 1 addition & 0 deletions tests/tutor/tutor_window_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class TutorWindowTest : public QObject {
void slrStateFConflictBranchAdvancesToFAAndThenG();
void slrStateGWrongThenCorrectReachesH();
void slrStateHIncorrectTableKeepsDialogOpen();
void slrGuidedModeWizardUsesCustomNavigationAndAllowsExit();
void slrGuidedModeWizardCompletesAndReturnsToTable();
void slrTableDialogCancelNoReopensAndYesRequestsExit();
void slrFinalTableCorrectPathExportsAndExits();
Expand Down
Loading