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 @@ - - - + + + +