#77: Fehlende Tooltips ergaenzt (Bestandsaufnahme + vollstaendige Umsetzung)

GuiTooltipTexts: neue Konstanten fuer Batchrun-Buttons, Verlauf-Spalten,
KI-Begruendung, Fehlerbereich, Modell-Neu-Laden, Browser-Button, Prompt-Textarea.
Spaltenkopf-Tooltips via Label-als-Graphic-Pattern in GuiHistoryTab und
GuiBatchRunTab; Buttons in allen Tabs beruecksichtigt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-05 12:15:44 +02:00
parent 5a97979585
commit e8732d749a
5 changed files with 207 additions and 16 deletions
@@ -1631,6 +1631,7 @@ public final class GuiConfigurationEditorWorkspace {
Button reloadModelsButton = new Button("Modelle neu laden"); Button reloadModelsButton = new Button("Modelle neu laden");
reloadModelsButton.setId("modelle-neu-laden-button"); reloadModelsButton.setId("modelle-neu-laden-button");
reloadModelsButton.setOnAction(event -> triggerModelRetrievalForCurrentProvider(providerComboBox)); reloadModelsButton.setOnAction(event -> triggerModelRetrievalForCurrentProvider(providerComboBox));
applyTooltip(reloadModelsButton, GuiTooltipTexts.PROVIDER_MODELLE_NEU_LADEN);
HBox comboRow = new HBox(8, providerComboBox, reloadModelsButton); HBox comboRow = new HBox(8, providerComboBox, reloadModelsButton);
comboRow.setAlignment(Pos.CENTER_LEFT); comboRow.setAlignment(Pos.CENTER_LEFT);
@@ -2156,6 +2157,7 @@ public final class GuiConfigurationEditorWorkspace {
card.getChildren().add(messagesListView); card.getChildren().add(messagesListView);
clearMessagesButton.setOnAction(e -> clearMessages()); clearMessagesButton.setOnAction(e -> clearMessages());
applyTooltip(clearMessagesButton, GuiTooltipTexts.TOOLBAR_MELDUNGEN_LEEREN);
HBox clearButtonRow = new HBox(clearMessagesButton); HBox clearButtonRow = new HBox(clearMessagesButton);
clearButtonRow.setAlignment(Pos.CENTER_LEFT); clearButtonRow.setAlignment(Pos.CENTER_LEFT);
card.getChildren().add(clearButtonRow); card.getChildren().add(clearButtonRow);
@@ -2801,6 +2803,7 @@ public final class GuiConfigurationEditorWorkspace {
Button pickButton1 = new Button(""); Button pickButton1 = new Button("");
pickButton1.setOnAction(e -> onPick1.run()); pickButton1.setOnAction(e -> onPick1.run());
pickButton1.setMinWidth(32); pickButton1.setMinWidth(32);
applyTooltip(pickButton1, GuiTooltipTexts.PFADE_BROWSER_BUTTON);
HBox fieldBox1 = new HBox(4, field1, pickButton1); HBox fieldBox1 = new HBox(4, field1, pickButton1);
HBox.setHgrow(field1, Priority.ALWAYS); HBox.setHgrow(field1, Priority.ALWAYS);
fieldBox1.setAlignment(Pos.CENTER_LEFT); fieldBox1.setAlignment(Pos.CENTER_LEFT);
@@ -2828,6 +2831,7 @@ public final class GuiConfigurationEditorWorkspace {
Button pickButton2 = new Button(""); Button pickButton2 = new Button("");
pickButton2.setOnAction(e -> onPick2.run()); pickButton2.setOnAction(e -> onPick2.run());
pickButton2.setMinWidth(32); pickButton2.setMinWidth(32);
applyTooltip(pickButton2, GuiTooltipTexts.PFADE_BROWSER_BUTTON);
HBox fieldBox2 = new HBox(4, field2, pickButton2); HBox fieldBox2 = new HBox(4, field2, pickButton2);
HBox.setHgrow(field2, Priority.ALWAYS); HBox.setHgrow(field2, Priority.ALWAYS);
fieldBox2.setAlignment(Pos.CENTER_LEFT); fieldBox2.setAlignment(Pos.CENTER_LEFT);
@@ -8,6 +8,7 @@ import java.util.function.Function;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import de.gecheckt.pdf.umbenenner.adapter.in.gui.GuiTooltipTexts;
import de.gecheckt.pdf.umbenenner.application.port.out.PromptLoadingFailure; import de.gecheckt.pdf.umbenenner.application.port.out.PromptLoadingFailure;
import de.gecheckt.pdf.umbenenner.application.port.out.PromptLoadingSuccess; import de.gecheckt.pdf.umbenenner.application.port.out.PromptLoadingSuccess;
import de.gecheckt.pdf.umbenenner.application.port.out.PromptSaveResult; import de.gecheckt.pdf.umbenenner.application.port.out.PromptSaveResult;
@@ -225,6 +226,7 @@ public class GuiPromptEditorTab {
textArea.setWrapText(true); textArea.setWrapText(true);
textArea.setFont(Font.font("Monospace", 13)); textArea.setFont(Font.font("Monospace", 13));
textArea.setPrefRowCount(20); textArea.setPrefRowCount(20);
textArea.setTooltip(new Tooltip(GuiTooltipTexts.PROMPT_TEXTAREA));
VBox.setVgrow(textArea, Priority.ALWAYS); VBox.setVgrow(textArea, Priority.ALWAYS);
// Dirty-State-Tracking // Dirty-State-Tracking
@@ -105,6 +105,134 @@ public final class GuiTooltipTexts {
public static final String DATEINAME_ZURUECKSETZEN = public static final String DATEINAME_ZURUECKSETZEN =
"Stellt den KI-generierten Namen wieder her, ohne zu speichern."; "Stellt den KI-generierten Namen wieder her, ohne zu speichern.";
// -------------------------------------------------------------------------
// Verarbeitungslauf-Tab Laufsteuerung und Tabelle
// -------------------------------------------------------------------------
/** Tooltip für den Button „Starten". */
public static final String BATCHRUN_STARTEN =
"Verarbeitungslauf starten: alle ausstehenden PDF-Dateien aus dem Quellordner verarbeiten.";
/** Tooltip für den Button „Abbrechen". */
public static final String BATCHRUN_ABBRECHEN =
"Laufenden Verarbeitungslauf abbrechen. Bereits abgeschlossene Dateien bleiben gespeichert.";
/** Tooltip für den Button „Erneut verarbeiten". */
public static final String BATCHRUN_ERNEUT_VERARBEITEN =
"Markierte Einträge erneut zur Verarbeitung freigeben (setzt Status auf READY_FOR_AI).";
/** Tooltip für den Button „Status zurücksetzen" im Verarbeitungslauf-Tab. */
public static final String BATCHRUN_STATUS_ZURUECKSETZEN =
"Status der markierten Einträge zurücksetzen, damit sie beim nächsten Lauf verarbeitet werden.";
/** Tooltip für die Master-Checkbox im Tabellenkopf des Verarbeitungslauf-Tabs. */
public static final String BATCHRUN_MASTER_CHECKBOX =
"Alle sichtbaren Einträge markieren oder Markierung aufheben.";
/** Tooltip für den Meldungsbereich im Verarbeitungslauf-Tab. */
public static final String BATCHRUN_MESSAGE_AREA =
"Statusmeldungen und Fortschrittsinformationen des aktuellen Verarbeitungslaufs.";
/** Tooltip für Spalte „Status" in der Verarbeitungslauf-Tabelle. */
public static final String BATCHRUN_COL_STATUS =
"Verarbeitungsergebnis: Erfolg, Fehler oder übersprungen.";
/** Tooltip für Spalte „Originaldateiname" in der Verarbeitungslauf-Tabelle. */
public static final String BATCHRUN_COL_ORIGINALDATEINAME =
"Ursprünglicher Dateiname der verarbeiteten PDF-Datei.";
/** Tooltip für Spalte „Neuer Dateiname" in der Verarbeitungslauf-Tabelle. */
public static final String BATCHRUN_COL_NEUER_DATEINAME =
"Von der KI vorgeschlagener, normierter Dateiname.";
/** Tooltip für Spalte „Datum" in der Verarbeitungslauf-Tabelle. */
public static final String BATCHRUN_COL_DATUM =
"Datum des Dokuments laut KI-Analyse.";
/** Tooltip für Spalte „Dauer" in der Verarbeitungslauf-Tabelle. */
public static final String BATCHRUN_COL_DAUER =
"Verarbeitungsdauer für diese Datei.";
// -------------------------------------------------------------------------
// Verlauf-Tab Detailbereich
// -------------------------------------------------------------------------
/** Tooltip für den KI-Begründungs-Bereich im Verlauf-Tab. */
public static final String VERLAUF_REASONING_AREA =
"KI-Begründung des ausgewählten Verarbeitungsversuchs.";
/** Tooltip für den Fehlerursachen-Bereich im Verlauf-Tab. */
public static final String VERLAUF_FAILURE_AREA =
"Fehlermeldung des letzten Fehler-Versuchs für dieses Dokument.";
/** Tooltip für Spalte „Status" in der Übersichtstabelle des Verlauf-Tabs. */
public static final String VERLAUF_COL_STATUS =
"Aktueller Gesamtstatus des Dokuments.";
/** Tooltip für Spalte „Quelldatei" in der Übersichtstabelle des Verlauf-Tabs. */
public static final String VERLAUF_COL_QUELLDATEI =
"Ursprünglicher Dateiname der PDF-Quelldatei.";
/** Tooltip für Spalte „Zieldatei" in der Übersichtstabelle des Verlauf-Tabs. */
public static final String VERLAUF_COL_ZIELDATEI =
"Vom System erzeugter, normierter Dateiname im Zielordner.";
/** Tooltip für Spalte „Letzter Versuch" in der Übersichtstabelle des Verlauf-Tabs. */
public static final String VERLAUF_COL_LETZTER_VERSUCH =
"Zeitpunkt des zuletzt abgeschlossenen Verarbeitungsversuchs.";
/** Tooltip für Spalte „Versuche" in der Übersichtstabelle des Verlauf-Tabs. */
public static final String VERLAUF_COL_VERSUCHE =
"Gesamtanzahl der Verarbeitungsversuche für dieses Dokument.";
/** Tooltip für Spalte „#" in der Versuche-Tabelle des Verlauf-Tabs. */
public static final String VERLAUF_VERSUCHE_COL_NR =
"Laufende Nummer des Verarbeitungsversuchs.";
/** Tooltip für Spalte „Datum" in der Versuche-Tabelle des Verlauf-Tabs. */
public static final String VERLAUF_VERSUCHE_COL_DATUM =
"Endzeitpunkt dieses Verarbeitungsversuchs.";
/** Tooltip für Spalte „Status" in der Versuche-Tabelle des Verlauf-Tabs. */
public static final String VERLAUF_VERSUCHE_COL_STATUS =
"Ergebnis dieses Verarbeitungsversuchs.";
/** Tooltip für Spalte „Provider" in der Versuche-Tabelle des Verlauf-Tabs. */
public static final String VERLAUF_VERSUCHE_COL_PROVIDER =
"KI-Provider, der für diesen Versuch verwendet wurde.";
/** Tooltip für Spalte „Modell" in der Versuche-Tabelle des Verlauf-Tabs. */
public static final String VERLAUF_VERSUCHE_COL_MODELL =
"Konkretes Sprachmodell, das für diesen Versuch verwendet wurde.";
/** Tooltip für Spalte „Vorgeschlagener Name" in der Versuche-Tabelle des Verlauf-Tabs. */
public static final String VERLAUF_VERSUCHE_COL_VORGESCHLAGENER_NAME =
"Vom System erzeugter Zieldateiname für diesen Versuch.";
// -------------------------------------------------------------------------
// Konfigurations-Tab Meldungsbereich und Modell-Neu-Laden
// -------------------------------------------------------------------------
/** Tooltip für den Button „Meldungen leeren". */
public static final String TOOLBAR_MELDUNGEN_LEEREN =
"Alle Meldungen im Meldungsbereich entfernen.";
/** Tooltip für den Button „Modelle neu laden". */
public static final String PROVIDER_MODELLE_NEU_LADEN =
"Verfügbare Modelle vom konfigurierten Provider neu abrufen.";
/** Tooltip für den Ordner-/Datei-Browser-Button. */
public static final String PFADE_BROWSER_BUTTON =
"Ordner oder Datei über den Datei-Dialog auswählen.";
// -------------------------------------------------------------------------
// Prompt-Tab Textbereich
// -------------------------------------------------------------------------
/** Tooltip für den Prompt-Textbereich im Prompt-Editor-Tab. */
public static final String PROMPT_TEXTAREA =
"KI-Anweisungstext. Dieser Prompt wird bei jedem Verarbeitungsversuch an das Sprachmodell gesendet.";
/** Nicht instanziierbar reine Konstantenklasse. */ /** Nicht instanziierbar reine Konstantenklasse. */
private GuiTooltipTexts() { private GuiTooltipTexts() {
throw new UnsupportedOperationException("Nicht instanziierbar"); throw new UnsupportedOperationException("Nicht instanziierbar");
@@ -43,6 +43,7 @@ import de.gecheckt.pdf.umbenenner.application.port.in.ResetDocumentStatusResult;
import de.gecheckt.pdf.umbenenner.application.port.in.RunSummary; import de.gecheckt.pdf.umbenenner.application.port.in.RunSummary;
import de.gecheckt.pdf.umbenenner.domain.model.DocumentFingerprint; import de.gecheckt.pdf.umbenenner.domain.model.DocumentFingerprint;
import de.gecheckt.pdf.umbenenner.domain.model.RunId; import de.gecheckt.pdf.umbenenner.domain.model.RunId;
import de.gecheckt.pdf.umbenenner.adapter.in.gui.GuiTooltipTexts;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper; import javafx.beans.property.ReadOnlyBooleanWrapper;
@@ -527,9 +528,11 @@ public final class GuiBatchRunTab {
// Selektions-Aktions-Buttons unterhalb der Tabelle (linke Spalte) // Selektions-Aktions-Buttons unterhalb der Tabelle (linke Spalte)
reprocessButton.setId("batch-run-reprocess"); reprocessButton.setId("batch-run-reprocess");
reprocessButton.setOnAction(event -> handleReprocessSelected()); reprocessButton.setOnAction(event -> handleReprocessSelected());
reprocessButton.setTooltip(new Tooltip(GuiTooltipTexts.BATCHRUN_ERNEUT_VERARBEITEN));
resetStatusButton.setId("batch-run-reset-status"); resetStatusButton.setId("batch-run-reset-status");
resetStatusButton.setOnAction(event -> handleResetSelected()); resetStatusButton.setOnAction(event -> handleResetSelected());
resetStatusButton.setTooltip(new Tooltip(GuiTooltipTexts.BATCHRUN_STATUS_ZURUECKSETZEN));
HBox selectionButtonBar = new HBox(SECONDARY_SPACING, reprocessButton, resetStatusButton); HBox selectionButtonBar = new HBox(SECONDARY_SPACING, reprocessButton, resetStatusButton);
selectionButtonBar.setAlignment(Pos.CENTER_LEFT); selectionButtonBar.setAlignment(Pos.CENTER_LEFT);
@@ -540,6 +543,7 @@ public final class GuiBatchRunTab {
messageArea.setEditable(false); messageArea.setEditable(false);
messageArea.setWrapText(true); messageArea.setWrapText(true);
messageArea.setPrefRowCount(3); messageArea.setPrefRowCount(3);
messageArea.setTooltip(new Tooltip(GuiTooltipTexts.BATCHRUN_MESSAGE_AREA));
// Hinweisbereich erst einblenden wenn eine Meldung vorliegt // Hinweisbereich erst einblenden wenn eine Meldung vorliegt
messageArea.setVisible(false); messageArea.setVisible(false);
messageArea.setManaged(false); messageArea.setManaged(false);
@@ -600,12 +604,14 @@ public final class GuiBatchRunTab {
masterCheckBox.setId("batch-run-master-checkbox"); masterCheckBox.setId("batch-run-master-checkbox");
masterCheckBox.setOnAction(e -> handleMasterCheckBoxAction()); masterCheckBox.setOnAction(e -> handleMasterCheckBoxAction());
masterCheckBox.setTooltip(new Tooltip(GuiTooltipTexts.BATCHRUN_MASTER_CHECKBOX));
checkboxCol.setGraphic(masterCheckBox); checkboxCol.setGraphic(masterCheckBox);
checkboxCol.setCellFactory(col -> new CheckBoxCell()); checkboxCol.setCellFactory(col -> new CheckBoxCell());
checkboxCol.setEditable(true); checkboxCol.setEditable(true);
TableColumn<GuiBatchRunResultRow, String> iconCol = new TableColumn<>("Status"); TableColumn<GuiBatchRunResultRow, String> iconCol = new TableColumn<>();
iconCol.setGraphic(columnHeader("Status", GuiTooltipTexts.BATCHRUN_COL_STATUS));
iconCol.setCellValueFactory(data -> new SimpleStringProperty(data.getValue().statusIcon())); iconCol.setCellValueFactory(data -> new SimpleStringProperty(data.getValue().statusIcon()));
iconCol.setPrefWidth(64); iconCol.setPrefWidth(64);
iconCol.setCellFactory(col -> new TableCell<GuiBatchRunResultRow, String>() { iconCol.setCellFactory(col -> new TableCell<GuiBatchRunResultRow, String>() {
@@ -636,11 +642,13 @@ public final class GuiBatchRunTab {
} }
}); });
TableColumn<GuiBatchRunResultRow, String> nameCol = new TableColumn<>("Originaldateiname"); TableColumn<GuiBatchRunResultRow, String> nameCol = new TableColumn<>();
nameCol.setGraphic(columnHeader("Originaldateiname", GuiTooltipTexts.BATCHRUN_COL_ORIGINALDATEINAME));
nameCol.setCellValueFactory(data -> new SimpleStringProperty(data.getValue().originalFileName())); nameCol.setCellValueFactory(data -> new SimpleStringProperty(data.getValue().originalFileName()));
nameCol.setPrefWidth(280); nameCol.setPrefWidth(280);
TableColumn<GuiBatchRunResultRow, String> newNameCol = new TableColumn<>("Neuer Dateiname"); TableColumn<GuiBatchRunResultRow, String> newNameCol = new TableColumn<>();
newNameCol.setGraphic(columnHeader("Neuer Dateiname", GuiTooltipTexts.BATCHRUN_COL_NEUER_DATEINAME));
newNameCol.setCellValueFactory(data -> { newNameCol.setCellValueFactory(data -> {
GuiBatchRunResultRow row = data.getValue(); GuiBatchRunResultRow row = data.getValue();
if (row.resetPending()) { if (row.resetPending()) {
@@ -650,14 +658,16 @@ public final class GuiBatchRunTab {
}); });
newNameCol.setPrefWidth(280); newNameCol.setPrefWidth(280);
TableColumn<GuiBatchRunResultRow, String> dateCol = new TableColumn<>("Datum"); TableColumn<GuiBatchRunResultRow, String> dateCol = new TableColumn<>();
dateCol.setGraphic(columnHeader("Datum", GuiTooltipTexts.BATCHRUN_COL_DATUM));
dateCol.setCellValueFactory(data -> new SimpleStringProperty( dateCol.setCellValueFactory(data -> new SimpleStringProperty(
data.getValue().resolvedDate() data.getValue().resolvedDate()
.map(DateTimeFormatter.ISO_LOCAL_DATE::format) .map(DateTimeFormatter.ISO_LOCAL_DATE::format)
.orElse(EMPTY_CELL_TEXT))); .orElse(EMPTY_CELL_TEXT)));
dateCol.setPrefWidth(100); dateCol.setPrefWidth(100);
TableColumn<GuiBatchRunResultRow, String> durationCol = new TableColumn<>("Dauer"); TableColumn<GuiBatchRunResultRow, String> durationCol = new TableColumn<>();
durationCol.setGraphic(columnHeader("Dauer", GuiTooltipTexts.BATCHRUN_COL_DAUER));
durationCol.setCellValueFactory(data -> new SimpleStringProperty( durationCol.setCellValueFactory(data -> new SimpleStringProperty(
formatDuration(data.getValue().processingDuration()))); formatDuration(data.getValue().processingDuration())));
durationCol.setPrefWidth(80); durationCol.setPrefWidth(80);
@@ -1145,10 +1155,12 @@ public final class GuiBatchRunTab {
// Lauf-Steuerungs-Buttons // Lauf-Steuerungs-Buttons
startButton.setId("batch-run-start"); startButton.setId("batch-run-start");
startButton.setOnAction(event -> handleStart()); startButton.setOnAction(event -> handleStart());
startButton.setTooltip(new Tooltip(GuiTooltipTexts.BATCHRUN_STARTEN));
cancelButton.setId("batch-run-cancel"); cancelButton.setId("batch-run-cancel");
cancelButton.setOnAction(event -> requestCancellation()); cancelButton.setOnAction(event -> requestCancellation());
cancelButton.setDisable(true); cancelButton.setDisable(true);
cancelButton.setTooltip(new Tooltip(GuiTooltipTexts.BATCHRUN_ABBRECHEN));
HBox runButtonBar = new HBox(SECONDARY_SPACING, startButton, cancelButton); HBox runButtonBar = new HBox(SECONDARY_SPACING, startButton, cancelButton);
runButtonBar.setAlignment(Pos.CENTER_LEFT); runButtonBar.setAlignment(Pos.CENTER_LEFT);
@@ -1439,6 +1451,21 @@ public final class GuiBatchRunTab {
// statusColor() wurde zugunsten von ProcessingStatusPresentation.cssColorFor() entfernt. // statusColor() wurde zugunsten von ProcessingStatusPresentation.cssColorFor() entfernt.
/**
* Erzeugt ein Label für den Spaltenkopf einer TableColumn mit Tooltip.
* Wird anstelle von {@code column.setText()} verwendet, da TableColumn
* kein direktes {@code setTooltip()} unterstützt.
*
* @param title sichtbarer Spaltentext; darf nicht leer sein
* @param tooltip Tooltip-Text; darf nicht leer sein
* @return ein Label mit gesetztem Tooltip
*/
private static Label columnHeader(String title, String tooltip) {
Label label = new Label(title);
label.setTooltip(new Tooltip(tooltip));
return label;
}
private static String formatDuration(Duration duration) { private static String formatDuration(Duration duration) {
double seconds = duration.toMillis() / 1000.0; double seconds = duration.toMillis() / 1000.0;
if (seconds < 10) { if (seconds < 10) {
@@ -15,6 +15,7 @@ import java.util.function.Supplier;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import de.gecheckt.pdf.umbenenner.adapter.in.gui.GuiTooltipTexts;
import de.gecheckt.pdf.umbenenner.adapter.in.gui.batchrun.ProcessingStatusPresentation; import de.gecheckt.pdf.umbenenner.adapter.in.gui.batchrun.ProcessingStatusPresentation;
import de.gecheckt.pdf.umbenenner.application.port.out.DocumentRecord; import de.gecheckt.pdf.umbenenner.application.port.out.DocumentRecord;
import de.gecheckt.pdf.umbenenner.application.port.out.ProcessingAttempt; import de.gecheckt.pdf.umbenenner.application.port.out.ProcessingAttempt;
@@ -288,7 +289,8 @@ public final class GuiHistoryTab {
overviewTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_FLEX_LAST_COLUMN); overviewTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_FLEX_LAST_COLUMN);
// Status-Icon-Spalte // Status-Icon-Spalte
TableColumn<DocumentHistoryRow, String> statusCol = new TableColumn<>("Status"); TableColumn<DocumentHistoryRow, String> statusCol = new TableColumn<>();
statusCol.setGraphic(columnHeader("Status", GuiTooltipTexts.VERLAUF_COL_STATUS));
statusCol.setCellValueFactory(cell -> statusCol.setCellValueFactory(cell ->
new SimpleStringProperty(statusIcon(cell.getValue().overallStatus()))); new SimpleStringProperty(statusIcon(cell.getValue().overallStatus())));
statusCol.setCellFactory(col -> new TableCell<>() { statusCol.setCellFactory(col -> new TableCell<>() {
@@ -310,27 +312,31 @@ public final class GuiHistoryTab {
statusCol.setMaxWidth(70); statusCol.setMaxWidth(70);
// Quelldateiname // Quelldateiname
TableColumn<DocumentHistoryRow, String> sourceCol = new TableColumn<>("Quelldatei"); TableColumn<DocumentHistoryRow, String> sourceCol = new TableColumn<>();
sourceCol.setGraphic(columnHeader("Quelldatei", GuiTooltipTexts.VERLAUF_COL_QUELLDATEI));
sourceCol.setCellValueFactory(cell -> sourceCol.setCellValueFactory(cell ->
new SimpleStringProperty(cell.getValue().sourceFileName())); new SimpleStringProperty(cell.getValue().sourceFileName()));
sourceCol.setCellFactory(col -> ellipsisCell()); sourceCol.setCellFactory(col -> ellipsisCell());
// Zieldateiname // Zieldateiname
TableColumn<DocumentHistoryRow, String> targetCol = new TableColumn<>("Zieldatei"); TableColumn<DocumentHistoryRow, String> targetCol = new TableColumn<>();
targetCol.setGraphic(columnHeader("Zieldatei", GuiTooltipTexts.VERLAUF_COL_ZIELDATEI));
targetCol.setCellValueFactory(cell -> targetCol.setCellValueFactory(cell ->
new SimpleStringProperty( new SimpleStringProperty(
cell.getValue().targetFileName() != null ? cell.getValue().targetFileName() : "")); cell.getValue().targetFileName() != null ? cell.getValue().targetFileName() : ""));
targetCol.setCellFactory(col -> ellipsisCell()); targetCol.setCellFactory(col -> ellipsisCell());
// Letzter Versuch // Letzter Versuch
TableColumn<DocumentHistoryRow, String> updatedCol = new TableColumn<>("Letzter Versuch"); TableColumn<DocumentHistoryRow, String> updatedCol = new TableColumn<>();
updatedCol.setGraphic(columnHeader("Letzter Versuch", GuiTooltipTexts.VERLAUF_COL_LETZTER_VERSUCH));
updatedCol.setCellValueFactory(cell -> updatedCol.setCellValueFactory(cell ->
new SimpleStringProperty(formatInstant(cell.getValue().updatedAt()))); new SimpleStringProperty(formatInstant(cell.getValue().updatedAt())));
updatedCol.setPrefWidth(140); updatedCol.setPrefWidth(140);
updatedCol.setMaxWidth(160); updatedCol.setMaxWidth(160);
// Anzahl Versuche // Anzahl Versuche
TableColumn<DocumentHistoryRow, String> countCol = new TableColumn<>("Versuche"); TableColumn<DocumentHistoryRow, String> countCol = new TableColumn<>();
countCol.setGraphic(columnHeader("Versuche", GuiTooltipTexts.VERLAUF_COL_VERSUCHE));
countCol.setCellValueFactory(cell -> countCol.setCellValueFactory(cell ->
new SimpleStringProperty(String.valueOf(cell.getValue().attemptCount()))); new SimpleStringProperty(String.valueOf(cell.getValue().attemptCount())));
countCol.setPrefWidth(70); countCol.setPrefWidth(70);
@@ -368,11 +374,14 @@ public final class GuiHistoryTab {
Label failureTitle = new Label("Fehlerursache (letzter Fehler-Versuch)"); Label failureTitle = new Label("Fehlerursache (letzter Fehler-Versuch)");
failureTitle.setStyle("-fx-font-weight: bold;"); failureTitle.setStyle("-fx-font-weight: bold;");
failureArea.setTooltip(new Tooltip(GuiTooltipTexts.VERLAUF_FAILURE_AREA));
// KI-Begründung // KI-Begründung
reasoningArea.setEditable(false); reasoningArea.setEditable(false);
reasoningArea.setWrapText(true); reasoningArea.setWrapText(true);
reasoningArea.setPrefRowCount(4); reasoningArea.setPrefRowCount(4);
reasoningArea.setText(DETAIL_PLACEHOLDER); reasoningArea.setText(DETAIL_PLACEHOLDER);
reasoningArea.setTooltip(new Tooltip(GuiTooltipTexts.VERLAUF_REASONING_AREA));
Label reasoningTitle = new Label("KI-Begründung (ausgewählter Versuch)"); Label reasoningTitle = new Label("KI-Begründung (ausgewählter Versuch)");
reasoningTitle.setStyle("-fx-font-weight: bold;"); reasoningTitle.setStyle("-fx-font-weight: bold;");
@@ -400,37 +409,43 @@ public final class GuiHistoryTab {
attemptsTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_FLEX_LAST_COLUMN); attemptsTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_FLEX_LAST_COLUMN);
attemptsTable.setPrefHeight(150); attemptsTable.setPrefHeight(150);
TableColumn<ProcessingAttempt, String> numCol = new TableColumn<>("#"); TableColumn<ProcessingAttempt, String> numCol = new TableColumn<>();
numCol.setGraphic(columnHeader("#", GuiTooltipTexts.VERLAUF_VERSUCHE_COL_NR));
numCol.setCellValueFactory(c -> numCol.setCellValueFactory(c ->
new SimpleStringProperty(String.valueOf(c.getValue().attemptNumber()))); new SimpleStringProperty(String.valueOf(c.getValue().attemptNumber())));
numCol.setPrefWidth(40); numCol.setPrefWidth(40);
numCol.setMaxWidth(50); numCol.setMaxWidth(50);
TableColumn<ProcessingAttempt, String> dateCol = new TableColumn<>("Datum"); TableColumn<ProcessingAttempt, String> dateCol = new TableColumn<>();
dateCol.setGraphic(columnHeader("Datum", GuiTooltipTexts.VERLAUF_VERSUCHE_COL_DATUM));
dateCol.setCellValueFactory(c -> dateCol.setCellValueFactory(c ->
new SimpleStringProperty(formatInstant(c.getValue().endedAt()))); new SimpleStringProperty(formatInstant(c.getValue().endedAt())));
dateCol.setPrefWidth(130); dateCol.setPrefWidth(130);
dateCol.setMaxWidth(150); dateCol.setMaxWidth(150);
TableColumn<ProcessingAttempt, String> statusCol = new TableColumn<>("Status"); TableColumn<ProcessingAttempt, String> statusCol = new TableColumn<>();
statusCol.setGraphic(columnHeader("Status", GuiTooltipTexts.VERLAUF_VERSUCHE_COL_STATUS));
statusCol.setCellValueFactory(c -> statusCol.setCellValueFactory(c ->
new SimpleStringProperty( new SimpleStringProperty(
ProcessingStatusPresentation.displayTextFor(c.getValue().status()))); ProcessingStatusPresentation.displayTextFor(c.getValue().status())));
statusCol.setPrefWidth(160); statusCol.setPrefWidth(160);
TableColumn<ProcessingAttempt, String> providerCol = new TableColumn<>("Provider"); TableColumn<ProcessingAttempt, String> providerCol = new TableColumn<>();
providerCol.setGraphic(columnHeader("Provider", GuiTooltipTexts.VERLAUF_VERSUCHE_COL_PROVIDER));
providerCol.setCellValueFactory(c -> providerCol.setCellValueFactory(c ->
new SimpleStringProperty( new SimpleStringProperty(
c.getValue().aiProvider() != null ? c.getValue().aiProvider() : "")); c.getValue().aiProvider() != null ? c.getValue().aiProvider() : ""));
providerCol.setPrefWidth(90); providerCol.setPrefWidth(90);
TableColumn<ProcessingAttempt, String> modelCol = new TableColumn<>("Modell"); TableColumn<ProcessingAttempt, String> modelCol = new TableColumn<>();
modelCol.setGraphic(columnHeader("Modell", GuiTooltipTexts.VERLAUF_VERSUCHE_COL_MODELL));
modelCol.setCellValueFactory(c -> modelCol.setCellValueFactory(c ->
new SimpleStringProperty( new SimpleStringProperty(
c.getValue().modelName() != null ? c.getValue().modelName() : "")); c.getValue().modelName() != null ? c.getValue().modelName() : ""));
modelCol.setCellFactory(col -> ellipsisCell()); modelCol.setCellFactory(col -> ellipsisCell());
TableColumn<ProcessingAttempt, String> fileNameCol = new TableColumn<>("Vorgeschlagener Name"); TableColumn<ProcessingAttempt, String> fileNameCol = new TableColumn<>();
fileNameCol.setGraphic(columnHeader("Vorgeschlagener Name", GuiTooltipTexts.VERLAUF_VERSUCHE_COL_VORGESCHLAGENER_NAME));
fileNameCol.setCellValueFactory(c -> fileNameCol.setCellValueFactory(c ->
new SimpleStringProperty( new SimpleStringProperty(
c.getValue().finalTargetFileName() != null c.getValue().finalTargetFileName() != null
@@ -831,6 +846,21 @@ public final class GuiHistoryTab {
}; };
} }
/**
* Erzeugt ein Label für den Spaltenkopf einer TableColumn mit Tooltip.
* Wird anstelle von {@code column.setText()} verwendet, da TableColumn
* kein direktes {@code setTooltip()} unterstützt.
*
* @param title sichtbarer Spaltentext
* @param tooltip Tooltip-Text
* @return ein Label mit gesetztem Tooltip
*/
private static Label columnHeader(String title, String tooltip) {
Label label = new Label(title);
label.setTooltip(new Tooltip(tooltip));
return label;
}
private static <T> TableCell<T, String> ellipsisCell() { private static <T> TableCell<T, String> ellipsisCell() {
return new TableCell<>() { return new TableCell<>() {
@Override @Override