From 2d889568a524aefa564d9d09d6248633564d2d2d Mon Sep 17 00:00:00 2001 From: ispyisail Date: Tue, 11 Aug 2026 12:36:31 +1200 Subject: [PATCH] Fix bugtracker #251: title block template with slash in name fails silently MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Saving a new user title block template (right-click "Cartouches utilisateur" > "Nouveau modèle" > "Enregistrer sous") with a name containing a slash (or other filesystem-reserved character) silently did nothing, with no error shown. The entered name is turned directly into a filename (TitleBlockTemplatesFilesCollection::toFileName()), so e.g. "foo/bar" becomes a path "foo/bar.titleblock" -- since "foo/" essentially never exists as a directory, the underlying file write fails, but that failure was never surfaced: - TitleBlockTemplateLocation::isValid() only checked for an empty name, so an invalid name still counted as "valid" and got passed through to save. - QETTitleBlockTemplateEditor::saveAs(const TitleBlockTemplateLocation&) discarded the bool result of setTemplateXmlDescription() and unconditionally returned true, marking the undo stack clean as if the save had actually succeeded. Fix: - isValid() now also rejects names containing \ / : * ? " < > |, matching the character set that's actually unsafe once the name becomes a filename. - saveAs() (the no-arg entry point that asks the user for a location) now shows a clear error dialog when the entered name is rejected, distinguishing "user cancelled" (location.name() empty) from "name was invalid" (non-empty but rejected by isValid()). - saveAs(location) now checks setTemplateXmlDescription()'s return value and shows an error dialog instead of reporting false success on any future/other write failure, not just this one. Verified: clean rebuild, only the intended files recompiled and linked successfully. Live-tested under Xvfb: creating a new template and using "Enregistrer sous" with the name "foo/bar" now shows "Le nom « foo/bar » n'est pas valide : il ne doit pas contenir les caractères suivants : \ / : * ? " < > |" instead of silently doing nothing; reopening the save-as dialog afterward showed the name field correctly empty (nothing was partially written). Saving again with a valid name ("mytemplate_valid") completed with no error dialog, and the resulting mytemplate_valid.titleblock file was confirmed present on disk in the user's title-block collection directory. --- sources/titleblock/qettemplateeditor.cpp | 30 +++++++++++++++++++++++- sources/titleblock/templatelocation.cpp | 8 ++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/sources/titleblock/qettemplateeditor.cpp b/sources/titleblock/qettemplateeditor.cpp index 9dd025132..3a316f15b 100644 --- a/sources/titleblock/qettemplateeditor.cpp +++ b/sources/titleblock/qettemplateeditor.cpp @@ -776,7 +776,20 @@ bool QETTitleBlockTemplateEditor::saveAs(const TitleBlockTemplateLocation &locat elmt.setAttribute("name", location.name()); doc.appendChild(elmt); - collection -> setTemplateXmlDescription(location.name(), elmt); + if (!collection -> setTemplateXmlDescription(location.name(), elmt)) { + // Report the failure instead of marking the template "saved" + // regardless (bugtracker #251) -- this return value used to + // be discarded here. + QET::QetMessageBox::critical( + this, + tr("Erreur", "message box title"), + tr( + "Impossible d'enregistrer le modèle « %1 ».", + "message box content - %1 is a title block template name" + ).arg(location.name()) + ); + return(false); + } opened_from_file_ = false; location_ = location; @@ -880,6 +893,21 @@ bool QETTitleBlockTemplateEditor::saveAs() if (location.isValid()) { return(saveAs(location)); } + if (!location.name().isEmpty()) { + // The name was rejected (e.g. contains a path separator or + // other filesystem-reserved character) rather than the user + // cancelling the dialog -- say so instead of silently doing + // nothing (bugtracker #251). + QET::QetMessageBox::critical( + this, + tr("Erreur", "message box title"), + tr( + "Le nom « %1 » n'est pas valide : il ne doit pas contenir " + "les caractères suivants : \\ / : * ? \" < > |", + "message box content - %1 is the rejected template name" + ).arg(location.name()) + ); + } return(false); } diff --git a/sources/titleblock/templatelocation.cpp b/sources/titleblock/templatelocation.cpp index 4387d6412..6f01ce591 100644 --- a/sources/titleblock/templatelocation.cpp +++ b/sources/titleblock/templatelocation.cpp @@ -92,7 +92,13 @@ void TitleBlockTemplateLocation::setName(const QString &name) { */ bool TitleBlockTemplateLocation::isValid() const { - return(!name_.isEmpty()); + // The name becomes (part of) a filename on disk (see + // TitleBlockTemplatesFilesCollection::toFileName()). A name containing + // a path separator or another filesystem-reserved character silently + // fails to save instead of erroring, because it turns into an + // unintended subpath rather than a plain filename (bugtracker #251). + static const QRegularExpression invalid_chars_re(QStringLiteral("[\\\\/:*?\"<>|]")); + return(!name_.isEmpty() && !name_.contains(invalid_chars_re)); } /**