From 24a30881f3a9fbb879fc02704d094168edadb021 Mon Sep 17 00:00:00 2001 From: Sebastian Hedtrich Date: Thu, 8 Oct 2026 08:55:10 +0200 Subject: [PATCH] Klausur-Deckblatt: Titel im Dialog je Druck anpassbar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Der interne Klausurtitel passt nicht immer aufs Deckblatt. Das neue Feld ist mit ihm vorbelegt, ändert nur Exam.Title für diesen Druck und fällt leer gelassen auf den internen Titel zurück. Co-Authored-By: Claude Opus 5.5 --- .../ExamCoverSheetTests.cs | 29 +++++++++++++++++++ .../Services/ExamCoverPlaceholderBuilder.cs | 7 +++-- .../Groups/ExamCoverSheetDialogViewModel.cs | 7 ++++- .../Views/Groups/ExamCoverSheetDialog.axaml | 11 ++++--- TODO.md | 6 ++++ 5 files changed, 53 insertions(+), 7 deletions(-) diff --git a/LehrerApp.Desktop.Tests/ExamCoverSheetTests.cs b/LehrerApp.Desktop.Tests/ExamCoverSheetTests.cs index 51c62be..aa97caf 100644 --- a/LehrerApp.Desktop.Tests/ExamCoverSheetTests.cs +++ b/LehrerApp.Desktop.Tests/ExamCoverSheetTests.cs @@ -204,6 +204,35 @@ public sealed class ExamCoverSheetTests : IDisposable Assert.Equal(new TextValue("G-Kurs"), Values(Niveau.E)["Exam.Course"]); } + [Fact] + public void Platzhalter_TitelAusDemDialog_LeerNimmtDenKlausurtitel() + { + var store = Store(); + Import(store, "deckblatt", "Deckblatt", TemplateReportTypes.ExamCover); + var template = store.Load(store.GetTemplates().Single()); + + Dictionary Values(string? title) => ExamCoverPlaceholderBuilder.Build( + _exam, _group, "Chemie", _anna, null, false, new GradingService(), template, new DateOnly(2026, 1, 1), + title: title); + + Assert.Equal(new TextValue("Klassenarbeit Nr. 1"), Values(" Klassenarbeit Nr. 1 ")["Exam.Title"]); + Assert.Equal(new TextValue("Atombau und PSE"), Values(" ")["Exam.Title"]); + Assert.Equal(new TextValue("Atombau und PSE"), Values(null)["Exam.Title"]); + } + + [Fact] + public void Dialog_TitelIstMitDemKlausurtitelVorbelegt() + { + var store = Store(); + Import(store, "deckblatt", "Deckblatt", TemplateReportTypes.ExamCover); + + var vm = Build([store]); + + Assert.Equal("Atombau und PSE", vm.CoverTitle); + vm.CoverTitle = "Klassenarbeit Nr. 1"; + Assert.Equal("Atombau und PSE", _exam.Title); + } + // Der Vorlagen-Designer bietet genau diesen Katalog an - liefert die Hauptapp einen Namen // nicht oder mit anderem Typ, scheitert die Vorlage erst beim Drucken. [Fact] diff --git a/LehrerApp.Desktop/Services/ExamCoverPlaceholderBuilder.cs b/LehrerApp.Desktop/Services/ExamCoverPlaceholderBuilder.cs index a0f12ce..aa6f7d6 100644 --- a/LehrerApp.Desktop/Services/ExamCoverPlaceholderBuilder.cs +++ b/LehrerApp.Desktop/Services/ExamCoverPlaceholderBuilder.cs @@ -22,9 +22,12 @@ public static class ExamCoverPlaceholderBuilder /// eingetragen, wenn gesetzt und das Ergebnis korrigiert ist. /// Niveau des Schülers in dieser Lerngruppe, falls die Arbeit /// selbst keinem Niveau zugeordnet ist. + /// Titel für das Deckblatt, falls er vom internen Klausurtitel abweichen + /// soll; null oder leer nimmt den Klausurtitel. public static Dictionary Build(Exam exam, LearningGroup group, string subjectName, Student student, ExamResult? result, bool fillResults, GradingService grading, LoadedTemplate template, - DateOnly today, Niveau? studentNiveau = null, string teacherAbbreviation = "") + DateOnly today, Niveau? studentNiveau = null, string teacherAbbreviation = "", + string? title = null) { var tasks = exam.Tasks.OrderBy(t => t.Nr).ToList(); var variant = result?.Variant ?? ExamVariant.A; @@ -34,7 +37,7 @@ public static class ExamCoverPlaceholderBuilder var values = LetterPlaceholderBuilder.BuildStandardValues(student, contact: null, group, today, "", ""); values["Group.GradeLevel"] = new TextValue(group.GradeLevel > 0 ? group.GradeLevel.ToString() : ""); values["Subject.Name"] = new TextValue(subjectName); - values["Exam.Title"] = new TextValue(exam.Title); + values["Exam.Title"] = new TextValue(string.IsNullOrWhiteSpace(title) ? exam.Title : title.Trim()); values["Exam.Date"] = new DateValue(exam.Date); values["Exam.Number"] = new TextValue(exam.ExamNumber?.ToString() ?? ""); values["Exam.Kind"] = new TextValue(exam.Kind.Label()); diff --git a/LehrerApp.Desktop/ViewModels/Groups/ExamCoverSheetDialogViewModel.cs b/LehrerApp.Desktop/ViewModels/Groups/ExamCoverSheetDialogViewModel.cs index 00f7e2b..02df108 100644 --- a/LehrerApp.Desktop/ViewModels/Groups/ExamCoverSheetDialogViewModel.cs +++ b/LehrerApp.Desktop/ViewModels/Groups/ExamCoverSheetDialogViewModel.cs @@ -28,7 +28,11 @@ public partial class ExamCoverSheetDialogViewModel : ObservableObject /// Vorbelegt aus den Einstellungen, hier nur für diesen Druck änderbar (z. B. zwei /// Kürzel bei einem gemeinsam unterrichteten Kurs) — die Einstellung bleibt unberührt. [ObservableProperty] private string _teacherAbbreviation; + /// Vorbelegt mit dem internen Klausurtitel, hier nur für diesen Druck änderbar — der + /// Titel der Klausur bleibt unberührt. Leer gelassen gilt wieder der interne Titel. + [ObservableProperty] private string _coverTitle; + public string ExamTitle => _exam.Title; public string ExamLabel => $"{_exam.Title} · {_group.Name} · {_exam.Date:dd.MM.yyyy}"; public ObservableCollection Templates { get; } = []; public ObservableCollection Students { get; } = []; @@ -41,6 +45,7 @@ public partial class ExamCoverSheetDialogViewModel : ObservableObject string teacherAbbreviation = "") { _teacherAbbreviation = teacherAbbreviation; + _coverTitle = exam.Title; _exam = exam; _group = group; _subjectName = subjectName; _grading = grading; _renderer = renderer; _loader = templateStores[0]; foreach (var template in templateStores.SelectMany(x => x.GetTemplates()).Where(x => x.IsExamCover) @@ -76,7 +81,7 @@ public partial class ExamCoverSheetDialogViewModel : ObservableObject var today = DateOnly.FromDateTime(DateTime.Now); var data = included.Select(s => (ITemplateDataProvider)new LetterDataProvider( ExamCoverPlaceholderBuilder.Build(_exam, _group, _subjectName, s.Model, s.Result, FillResults, - _grading, loaded, today, s.Niveau, TeacherAbbreviation))).ToList(); + _grading, loaded, today, s.Niveau, TeacherAbbreviation, CoverTitle))).ToList(); var result = _renderer.RenderBatchToPdf(loaded, data); File.WriteAllBytes(outputPath, result.Pdf); diff --git a/LehrerApp.Desktop/Views/Groups/ExamCoverSheetDialog.axaml b/LehrerApp.Desktop/Views/Groups/ExamCoverSheetDialog.axaml index 1859825..1dd47de 100644 --- a/LehrerApp.Desktop/Views/Groups/ExamCoverSheetDialog.axaml +++ b/LehrerApp.Desktop/Views/Groups/ExamCoverSheetDialog.axaml @@ -4,7 +4,7 @@ x:Class="LehrerApp.Desktop.Views.Groups.ExamCoverSheetDialog" x:DataType="vm:ExamCoverSheetDialogViewModel" Title="Deckblätter drucken" - Width="460" Height="640" + Width="460" Height="680" CanResize="False" WindowStartupLocation="CenterOwner"> @@ -21,9 +21,12 @@ - - - + + + +