#include "mainwindow.h" #include "ui_mainwindow.h" #include "path.h" #include "step.h" #include "Undo.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "web.h" #include #include #include #include int MainWindow::indexPath = 0; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) , undoStack(new QUndoStack(this)) , Clipboard(QGuiApplication::clipboard()) { ui->setupUi(this); indexPath++; Path* p = new Path(); currentPath = p; path.append(p); loadPath(p); int pathCount = path.length(); ui->pathNumber->setMaximum(pathCount); ui->pathNumber->setSuffix("/" + QString::number(pathCount)); connect(ui->titleEdit, &QLineEdit::editingFinished, this, [this]() { static QString previousText; QString currentText = ui->titleEdit->text(); if(previousText != currentText) { undoStack->push(new LineEditCommand(ui->titleEdit, previousText, currentText)); previousText = currentText; } }); connect(ui->locEdit, &QLineEdit::editingFinished, this, [this]() { static QString previousText; QString currentText = ui->locEdit->text(); if(previousText != currentText) { undoStack->push(new LineEditCommand(ui->locEdit, previousText, currentText)); previousText = currentText; } }); connect(ui->imagePath, &QLineEdit::editingFinished, this, [this]() { static QString previousText; QString currentText = ui->imagePath->text(); if(previousText != currentText) { undoStack->push(new LineEditCommand(ui->imagePath, previousText, currentText)); previousText = currentText; } }); connect(ui->dialogEdit, &QPlainTextEdit::textChanged, this, [this]() { static QString previousText = ui->dialogEdit->toPlainText(); if (m_handlingUndoRedo) return; QString currentText = ui->dialogEdit->toPlainText(); if (currentText != previousText) { undoStack->push(new PlainTextEditCommand(ui->dialogEdit, previousText, currentText, this)); previousText = currentText; } }); connect(ui->actionEditUndo, &QAction::triggered, undoStack, &QUndoStack::undo); connect(ui->actionEditRedo, &QAction::triggered, undoStack, &QUndoStack::redo); currentPath->getStep().append(Step()); } MainWindow::~MainWindow() { delete ui; delete currentPath; for(Path* p : path) { delete p; } } void MainWindow::updatePathView() {} void MainWindow::updateStepView(size_t num) {} void MainWindow::onTextChanged() { textChanged = true; } void MainWindow::loadNewPath() { QString fileName = QFileDialog::getOpenFileName(this, "Open the file"); if(fileName.isEmpty()) return; QFile file(fileName); if(!file.open(QIODevice::ReadOnly | QFile::Text)) { QMessageBox::warning(this, "Warning", "Fichier non valide" + file.errorString()); return; } file.close(); Path* p = new Path(&file); currentPath = p; path.append(p); loadPath(p); currentFile = fileName; int pathCount = path.length(); ui->pathNumber->setMaximum(pathCount); ui->pathNumber->setSuffix("/" + QString::number(pathCount)); ui->pathNumber->setValue(path.indexOf(currentPath)+1); } void MainWindow::loadPath(Path* p) { QList steps = p->getStep(); ui->titleEdit->setText(p->getName()); ui->locEdit->setText(p->getCity()); ui->diffSpin->setValue(p->getDifficulty()); ui->lengthSpin->setValue(p->getLength()); ui->durationSpin->setValue(p->getDuration()); ui->imagePath->setText(p->getImage()); ui->depSpin->setValue(p->getDepartement()); loadImage(p->getImage()); ui->dialogEdit->clear(); if(!steps.isEmpty()) { Step firstStep = p->getStep().first(); ui->stepTitle->setText(firstStep.getTitle()); ui->LatitudeSpin->setValue(firstStep.getLatitude()); ui->longitudeSpin->setValue(firstStep.getLongitude()); for(int i = 0; i < firstStep.getTexte().length(); i++) { QString q = "[" + firstStep.getPersonnage().at(i) + "] : " + firstStep.getTexte().at(i); ui->dialogEdit->appendPlainText(q); } ui->stepNumber->setValue(1); ui->stepNumber->setSuffix("/" + QString::number(steps.length())); ui->stepNumber->setMaximum(steps.length()); } } void MainWindow::loadStep(Step s) { ui->stepTitle->setText(s.getTitle()); ui->LatitudeSpin->setValue(s.getLatitude()); ui->longitudeSpin->setValue(s.getLongitude()); ui->responseSpin->setValue(s.getResponse()); for(int i = 0; i < s.getTexte().length(); i++) { QString q = "[" + s.getPersonnage().at(i) + "] : " + s.getTexte().at(i); ui->dialogEdit->appendPlainText(q); } } void MainWindow::addNewPath() { path.append(currentPath); } void MainWindow::addNewStep() { this->on_validateBtn_clicked(); currentPath->getStep().append(Step()); ui->stepNumber->setMaximum(currentPath->getStep().length()); ui->stepNumber->setSuffix("/" + QString::number(currentPath->getStep().length())); } void MainWindow::exportHTMLMap(int index) { if (index < 0 || index >= path.size()) { QMessageBox::warning(this, "Erreur", "Index de parcours invalide."); return; } Path* p = path[index]; if (!p) { QMessageBox::warning(this, "Erreur", "Le parcours sélectionné est nul."); return; } QDir dir; dir.mkdir("./data/HTML-exports"); dir.mkdir("./data/HTML-exports/pages"); QString safeName = p->getName().simplified().replace(" ", "_"); std::string fileName = "./data/HTML-exports/pages/parcours_" + safeName.toStdString() + ".html"; std::ofstream file(fileName); if (!file.is_open()) { QMessageBox::warning(this, "Erreur", "Impossible d'ouvrir le fichier HTML."); return; } // Début HTML file << R"( Carte du parcours
)"; // Infos du parcours file << "

" << p->getName().toStdString() << "

\n"; file << "

Ville : " << p->getCity().toStdString() << "

\n"; file << "

Département : " << p->getDepartement() << "

\n"; file << "

Difficulté : " << p->getDifficulty() << "

\n"; file << "

Durée (heures) : " << p->getDuration() << "

\n"; file << "

Longueur (km) : " << p->getLength() << "

\n"; if (!p->getImage().isEmpty()) { QString imagePath = p->getImage(); QFileInfo fileInfo(imagePath); QString imageName = fileInfo.fileName(); QString destPath = "../data/HTML-exports/pages/images/" + imageName; // Crée le dossier images s’il n’existe pas QDir().mkpath("./data/HTML-exports/pages/images"); // Copie l’image dans le dossier pages/images QFile::copy(imagePath, destPath); // Utilisation dans le HTML file << "\n"; } int stepNum = 1; for (const Step& s : p->getStep()) { file << "

Étape " << stepNum << "

\n"; const QList persos = s.getPersonnage(); const QList textes = s.getTexte(); if (!persos.isEmpty()) { file << "

Personnages :

\n
    "; for (const QString& pers : persos) { file << "
  • " << pers.toStdString() << "
  • \n"; } file << "
\n"; } if (!textes.isEmpty()) { file << "

Dialogues :

\n
    "; for (const QString& txt : textes) { file << "
  • " << txt.toStdString() << "
  • \n"; } file << "
\n"; } stepNum++; } file << R"(
)"; file.close(); } void MainWindow::loadImage(QString fileName) { QString ext[] = {"png", "jpeg", "jpg"}; QFile file(fileName); if (!file.open(QIODevice::ReadOnly | QFile::Text)) { QMessageBox::warning(this, "Warning", "Cannot open image: " + file.errorString()); }else{ QString text = file.fileName(); bool acceptedExt = false; for(QString e : ext) { if(text.endsWith(e)) acceptedExt = true; } if(!acceptedExt) { QMessageBox::warning(this, "Warning", "Format de fichier incorrect"); return; } ui->imagePath->setText(text); QPixmap px(fileName); ui->imageLbl->setPixmap(px); file.close(); } } void MainWindow::on_pushButton_clicked() { QString fileName = QFileDialog::getOpenFileName(this, "Open the file"); if (fileName.isEmpty()) return; this->loadImage(fileName); } void MainWindow::on_actionOpen_triggered() { this->loadNewPath(); } void MainWindow::on_toolButton_clicked() { QString fileName = ui->imagePath->text(); if(fileName.isEmpty()) return; loadImage(fileName); } int MainWindow::getIndexPath() const { return indexPath; } void MainWindow::setIndexPath(int newIndexPath) { indexPath = newIndexPath; } QString MainWindow::getCurrentFile() const { return currentFile; } void MainWindow::setCurrentFile(const QString &newCurrentFile) { currentFile = newCurrentFile; } QList MainWindow::getPath() const { return path; } void MainWindow::setPath(const QList &newPath) { path = newPath; } Path *MainWindow::getCurrentPath() const { return currentPath; } void MainWindow::setCurrentPath(Path *newCurrentPath) { currentPath = newCurrentPath; } void MainWindow::saveFile(){ on_validateBtn_clicked(); QString fileName; if (currentFile.isEmpty()) { fileName = QFileDialog::getSaveFileName(this, "Save"); currentFile = fileName; } else { fileName = currentFile; } QFile file(fileName); if (!file.open(QIODevice::WriteOnly | QFile::Text)) { QMessageBox::warning(this, "Warning", "Cannot save file: " + file.errorString()); return; } setWindowTitle(fileName); QJsonObject json; json["name"] = ui->titleEdit->text(); json["city"] =ui->locEdit->text(); json["departement"] = ui->depSpin->text(); json["difficulty"] = ui->diffSpin->value(); json["duration"] = ui->durationSpin->value(); json["length"] = ui->lengthSpin->value(); json["image"] = ui->imagePath->text(); QJsonArray steps; int cpt=0; for(Step step: currentPath->getStep()){ cpt++; QJsonObject stepObject; stepObject["numero"] = cpt; stepObject["title"] = step.getTitle(); stepObject["GPS"] = step.toGPSFormat(); stepObject["reponse"] = step.getResponse(); QJsonArray dialogues; for(int i=0; isaveFile(); } void MainWindow::on_actionopenFile_triggered() { this->loadNewPath(); } void MainWindow::copyText(){ QWidget *focused = QApplication::focusWidget(); QLineEdit* lineEdit = qobject_cast(focused); QPlainTextEdit* plainTextEdit = qobject_cast(focused); if (lineEdit && !lineEdit->selectedText().isEmpty()) { Clipboard->setText(lineEdit->selectedText()); } else if (plainTextEdit) { QTextCursor cursor = plainTextEdit->textCursor(); if (cursor.hasSelection()) { Clipboard->setText(cursor.selectedText()); } } } void MainWindow::on_actionEditCopy_triggered() { this->copyText(); } void MainWindow::pastText(){ QWidget *focused = QApplication::focusWidget(); QLineEdit* lineEdit = qobject_cast(focused); QPlainTextEdit* plainTextEdit = qobject_cast(focused); if (lineEdit) { lineEdit->insert(Clipboard->text()); } else if (plainTextEdit) { plainTextEdit->insertPlainText(Clipboard->text()); } } void MainWindow::on_actionEditPaste_triggered() { this->pastText(); } void MainWindow::cutText(){ QWidget *focused = QApplication::focusWidget(); QLineEdit* lineEdit = qobject_cast(focused); QPlainTextEdit* plainTextEdit = qobject_cast(focused); if (lineEdit) { QString selectedText = lineEdit->selectedText(); if (!selectedText.isEmpty()) { Clipboard->setText(selectedText); lineEdit->del(); } } else if (plainTextEdit) { QTextCursor cursor = plainTextEdit->textCursor(); if (cursor.hasSelection()) { Clipboard->setText(cursor.selectedText()); cursor.removeSelectedText(); } } } void MainWindow::on_actionEditCut_triggered() { this->cutText(); } void MainWindow::on_pathNumber_valueChanged(int arg1) { on_validateBtn_clicked(); this->loadPath(path.at(ui->pathNumber->value()-1)); currentPath = path.at(arg1-1); } void MainWindow::on_stepNumber_valueChanged(int arg1) { ui->dialogEdit->clear(); this->loadStep(currentPath->getStep().at(arg1-1)); } void MainWindow::on_validateBtn_clicked() { this->currentPath->setName(ui->titleEdit->text()); this->currentPath->setCity(ui->locEdit->text()); this->currentPath->setImage(ui->imagePath->text()); this->currentPath->setLength(ui->lengthSpin->value()); this->currentPath->setDifficulty(ui->diffSpin->value()); this->currentPath->setDuration(ui->durationSpin->value()); this->currentPath->getStep()[ui->stepNumber->value()-1].setTitle(ui->stepTitle->text()); this->currentPath->getStep()[ui->stepNumber->value()-1].setResponse(ui->responseSpin->value()); this->currentPath->getStep()[ui->stepNumber->value()-1].setLongitude(ui->longitudeSpin->value()); this->currentPath->getStep()[ui->stepNumber->value()-1].setLatitude(ui->LatitudeSpin->value()); this->currentPath->getStep()[ui->stepNumber->value()-1].clearPersonnages(); this->currentPath->getStep()[ui->stepNumber->value()-1].clearTextes(); extractDialogue(); } void MainWindow::extractDialogue() { std::string texte = ui->dialogEdit->toPlainText().toStdString(); size_t currentPosition = 0; while (currentPosition < texte.length()) { size_t startPersonnage = texte.find('[', currentPosition); if (startPersonnage == std::string::npos) break; size_t endPersonnage = texte.find(']', startPersonnage); if (endPersonnage == std::string::npos) break; std::string nomPersonnage = texte.substr(startPersonnage + 1, endPersonnage - startPersonnage - 1); size_t startDialogue = texte.find(':', endPersonnage); if (startDialogue == std::string::npos) break; startDialogue += 2; size_t endDialogue = startDialogue; while (endDialogue < texte.length()) { size_t nextNewLine = texte.find('\n', endDialogue); if (nextNewLine == std::string::npos) { endDialogue = texte.length(); break; } size_t nextPersonnageStart = texte.find('[', nextNewLine); if (nextPersonnageStart != std::string::npos && nextPersonnageStart < nextNewLine + nomPersonnage.length() + 3) { endDialogue = nextNewLine; break; } endDialogue = nextNewLine + 1; } std::string dialogue = texte.substr(startDialogue, endDialogue - startDialogue); currentPath->getStep()[ui->stepNumber->value()-1].addPersonnage(QString::fromStdString(nomPersonnage)); currentPath->getStep()[ui->stepNumber->value()-1].addTexte(QString::fromStdString(dialogue)); currentPosition = endDialogue; } } void MainWindow::loadAndExportPaths(QStringList fichiers) { for (const QString& nomFichier : fichiers) { QFile* f = new QFile(nomFichier); Path* p = new Path(f); path.append(p); } int exportIndex = 1; for (Path* p : path) { currentPath = p; exportHTMLMap(exportIndex++); } } void MainWindow::setBold(){ QWidget *focused = QApplication::focusWidget(); QPlainTextEdit* plainTextEdit = qobject_cast(focused); if (plainTextEdit) { QTextCursor cursor = plainTextEdit->textCursor(); QTextCharFormat format; QFont font = cursor.charFormat().font(); font.setBold(!font.bold()); format.setFont(font); plainTextEdit->mergeCurrentCharFormat(format); } } void MainWindow::on_actionBold_triggered() { this->setBold(); } void MainWindow::setItalic(){ QWidget *focused = QApplication::focusWidget(); QPlainTextEdit* plainTextEdit = qobject_cast(focused); if (plainTextEdit) { QTextCursor cursor = plainTextEdit->textCursor(); QTextCharFormat format; QFont font = cursor.charFormat().font(); font.setItalic(!font.italic()); format.setFont(font); plainTextEdit->mergeCurrentCharFormat(format); } } void MainWindow::on_actionItalic_triggered() { this->setItalic(); } void MainWindow::setUnderline(){ QWidget *focused = QApplication::focusWidget(); QPlainTextEdit* plainTextEdit = qobject_cast(focused); if (plainTextEdit) { QTextCursor cursor = plainTextEdit->textCursor(); QTextCharFormat format; QFont font = cursor.charFormat().font(); font.setUnderline(!font.underline()); format.setFont(font); plainTextEdit->mergeCurrentCharFormat(format); } } void MainWindow::on_actionUnderline_triggered() { this->setUnderline(); } void MainWindow::setColor(){ QWidget *focused = QApplication::focusWidget(); QPlainTextEdit* plainTextEdit = qobject_cast(focused); if (plainTextEdit) { QColor color = QColorDialog::getColor(Qt::black, this, "Choisir une couleur"); QTextCursor cursor = plainTextEdit->textCursor(); if (color.isValid()) { QTextCharFormat format; format.setForeground(color); plainTextEdit->mergeCurrentCharFormat(format); } } } void MainWindow::on_actionColor_triggered() { this->setColor(); } void MainWindow::setOverline(){ QWidget *focused = QApplication::focusWidget(); QPlainTextEdit* plainTextEdit = qobject_cast(focused); if (plainTextEdit) { QTextCursor cursor = plainTextEdit->textCursor(); QTextCharFormat format; QFont font = cursor.charFormat().font(); font.setOverline(!font.overline()); format.setFont(font); plainTextEdit->mergeCurrentCharFormat(format); } } void MainWindow::on_actionOverline_triggered() { this->setOverline(); } void MainWindow::setSize(){ QWidget *focused = QApplication::focusWidget(); QPlainTextEdit* plainTextEdit = qobject_cast(focused); if (plainTextEdit) { QTextCursor cursor = plainTextEdit->textCursor(); bool ok; int size = QInputDialog::getInt(this, "Taille de la police", "Entrez la taille de la police:", cursor.charFormat().font().pointSize(), 1, 100, 1, &ok); if (ok) { QTextCharFormat format; QFont font = cursor.charFormat().font(); font.setPointSize(size); format.setFont(font); plainTextEdit->mergeCurrentCharFormat(format); } } } void MainWindow::on_actionSize_triggered() { this->setSize(); } void MainWindow::setFont(){ QWidget *focused = QApplication::focusWidget(); QPlainTextEdit* plainTextEdit = qobject_cast(focused); if (plainTextEdit) { QTextCursor cursor = plainTextEdit->textCursor(); bool ok; QFont font = QFontDialog::getFont(&ok, cursor.charFormat().font(), this, "Choisir une police"); if (ok) { QTextCharFormat format; format.setFont(font); plainTextEdit->mergeCurrentCharFormat(format); } } } void MainWindow::on_actionFont_triggered() { this->setFont(); } void MainWindow::on_actionFont_2_triggered() { this->setFont(); } void MainWindow::on_actionBold_2_triggered() { this->setBold(); } void MainWindow::on_actionItalic_2_triggered() { this->setItalic(); } void MainWindow::on_actionUnderline_2_triggered() { this->setUnderline(); } void MainWindow::on_actionOverline_2_triggered() { this->setOverline(); } void MainWindow::on_actionFont_size_triggered() { this->setSize(); } void MainWindow::saveAsFile(){ on_validateBtn_clicked(); QString fileName = QFileDialog::getSaveFileName(this, "Save as"); QFile file(fileName); if (!file.open(QFile::WriteOnly | QFile::Text)) { QMessageBox::warning(this, "Warning", "Cannot save file: " + file.errorString()); return; } setWindowTitle(fileName); currentFile = fileName; QJsonObject json; json["name"] = ui->titleEdit->text(); json["city"] =ui->locEdit->text(); json["departement"] = ui->depSpin->text(); json["difficulty"] = ui->diffSpin->value(); json["duration"] = ui->durationSpin->value(); json["length"] = ui->lengthSpin->value(); json["image"] = ui->imagePath->text(); QJsonArray steps; int cpt=0; for(Step step: currentPath->getStep()){ cpt++; QJsonObject stepObject; stepObject["numero"] = cpt; stepObject["title"] = step.getTitle(); stepObject["GPS"] = step.toGPSFormat(); stepObject["reponse"] = step.getResponse(); QJsonArray dialogues; for(int i=0; isaveAsFile(); } void MainWindow::on_exportHTMLBtn_clicked() { on_validateBtn_clicked(); for(int i = 0; i < path.length(); i++) { this->exportHTMLMap(i); } Web w(path); w.siteHtml(); } void MainWindow::on_actionSaveFile_triggered() { this->saveFile(); } void MainWindow::on_actionSaveAsFile_triggered() { this->saveAsFile(); } void MainWindow::on_actionCopy_triggered() { this->copyText(); } void MainWindow::on_actionPast_triggered() { this->pastText(); } void MainWindow::on_actionCut_triggered() { this->cutText(); } void MainWindow::newPath(){ Path* p = new Path(); currentPath = p; path.append(p); loadPath(p); p->addStep(); int pathCount = path.length(); ui->pathNumber->setMaximum(pathCount); ui->pathNumber->setSuffix("/" + QString::number(pathCount)); ui->pathNumber->setValue(path.indexOf(currentPath)+1); } void MainWindow::on_actionNew_triggered() { this->newPath(); } void MainWindow::on_actionNewFile_triggered() { this->newPath(); } void MainWindow::on_actionFont_color_triggered() { this->setColor(); } void MainWindow::on_addStep_clicked() { this->addNewStep(); } void MainWindow::on_actionExit_triggered() { QApplication::quit(); } void MainWindow::openIndexSite() { QString filePath = "./data/HTML-exports/index.html"; QFileInfo fileInfo(filePath); if (fileInfo.exists() && fileInfo.isFile()) { QDesktopServices::openUrl(QUrl::fromLocalFile(fileInfo.absoluteFilePath())); } else { QMessageBox::warning(this, "Erreur", "Le fichier index.html n'existe pas."); } } void MainWindow::on_actionWeb_triggered() { this->openIndexSite(); }