M10, AP-001 freigegeben
This commit is contained in:
+25
@@ -0,0 +1,25 @@
|
||||
package de.gecheckt.pdf.umbenenner.adapter.in.gui.editor;
|
||||
|
||||
/**
|
||||
* Derived change-state view for the editor content.
|
||||
* <p>
|
||||
* The value is computed from the comparison between the baseline values and the current
|
||||
* editor values.
|
||||
*/
|
||||
public enum GuiChangeState {
|
||||
|
||||
/** The current editor state matches its baseline. */
|
||||
CLEAN,
|
||||
|
||||
/** The current editor state has diverged from its baseline. */
|
||||
DIRTY;
|
||||
|
||||
/**
|
||||
* Returns whether this state represents unsaved changes.
|
||||
*
|
||||
* @return {@code true} when the editor is dirty, otherwise {@code false}
|
||||
*/
|
||||
public boolean isDirty() {
|
||||
return this == DIRTY;
|
||||
}
|
||||
}
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
package de.gecheckt.pdf.umbenenner.adapter.in.gui.editor;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Root editor state for the GUI configuration editor.
|
||||
* <p>
|
||||
* The state keeps the loaded file snapshot, the baseline values and the current editable values
|
||||
* separate so later GUI layers can compare the current editor content against the original
|
||||
* representation without relying on a manually maintained dirty flag.
|
||||
*
|
||||
* @param loadedFileSnapshot loaded file representation, or empty when the editor was created
|
||||
* from the standard template
|
||||
* @param baselineValues values representing the baseline the editor compares against
|
||||
* @param values current editable configuration values
|
||||
*/
|
||||
public record GuiConfigurationEditorState(
|
||||
Optional<GuiConfigurationFileSnapshot> loadedFileSnapshot,
|
||||
GuiConfigurationValues baselineValues,
|
||||
GuiConfigurationValues values) {
|
||||
|
||||
/**
|
||||
* Creates a new editor state.
|
||||
*
|
||||
* @param loadedFileSnapshot loaded file representation; {@code null} becomes empty
|
||||
* @param baselineValues baseline values; must not be {@code null}
|
||||
* @param values current editable configuration values; must not be {@code null}
|
||||
*/
|
||||
public GuiConfigurationEditorState {
|
||||
loadedFileSnapshot = loadedFileSnapshot == null ? Optional.empty() : loadedFileSnapshot;
|
||||
baselineValues = Objects.requireNonNull(baselineValues, "baselineValues must not be null");
|
||||
values = Objects.requireNonNull(values, "values must not be null");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the editor currently contains unsaved changes.
|
||||
*
|
||||
* @return {@code true} when the current values differ from the baseline, otherwise {@code false}
|
||||
*/
|
||||
public boolean isDirty() {
|
||||
return !baselineValues.equals(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the derived change state for the current editor content.
|
||||
*
|
||||
* @return {@link GuiChangeState#DIRTY} when the editor is dirty, otherwise {@link GuiChangeState#CLEAN}
|
||||
*/
|
||||
public GuiChangeState changeState() {
|
||||
return isDirty() ? GuiChangeState.DIRTY : GuiChangeState.CLEAN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the editor currently has a loaded file snapshot.
|
||||
*
|
||||
* @return {@code true} when the editor was loaded from disk, otherwise {@code false}
|
||||
*/
|
||||
public boolean hasLoadedFileSnapshot() {
|
||||
return loadedFileSnapshot.isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the editor represents a newly created configuration.
|
||||
*
|
||||
* @return {@code true} when no file snapshot is loaded, otherwise {@code false}
|
||||
*/
|
||||
public boolean isNewConfiguration() {
|
||||
return loadedFileSnapshot.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy with different current editable values.
|
||||
*
|
||||
* @param values the new editable values; must not be {@code null}
|
||||
* @return a new editor state containing the supplied values
|
||||
*/
|
||||
public GuiConfigurationEditorState withValues(GuiConfigurationValues values) {
|
||||
return new GuiConfigurationEditorState(loadedFileSnapshot, baselineValues, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy with a different baseline.
|
||||
*
|
||||
* @param baselineValues the new baseline values; must not be {@code null}
|
||||
* @return a new editor state using the supplied baseline
|
||||
*/
|
||||
public GuiConfigurationEditorState withBaselineValues(GuiConfigurationValues baselineValues) {
|
||||
return new GuiConfigurationEditorState(loadedFileSnapshot, baselineValues, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy with a loaded file snapshot.
|
||||
*
|
||||
* @param snapshot the loaded file snapshot; must not be {@code null}
|
||||
* @return a new editor state linked to the supplied snapshot
|
||||
*/
|
||||
public GuiConfigurationEditorState withLoadedFileSnapshot(GuiConfigurationFileSnapshot snapshot) {
|
||||
return new GuiConfigurationEditorState(Optional.of(snapshot), baselineValues, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy without any loaded file snapshot.
|
||||
*
|
||||
* @return a new editor state without a loaded file snapshot
|
||||
*/
|
||||
public GuiConfigurationEditorState withoutLoadedFileSnapshot() {
|
||||
return new GuiConfigurationEditorState(Optional.empty(), baselineValues, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a clean copy of this editor state by resetting the current values to the baseline.
|
||||
*
|
||||
* @return a clean editor state
|
||||
*/
|
||||
public GuiConfigurationEditorState markClean() {
|
||||
return baselineValues.equals(values)
|
||||
? this
|
||||
: new GuiConfigurationEditorState(loadedFileSnapshot, baselineValues, baselineValues);
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
package de.gecheckt.pdf.umbenenner.adapter.in.gui.editor;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Snapshot of a configuration file loaded from disk.
|
||||
* <p>
|
||||
* This type is intentionally separate from the editable editor state. It represents the file
|
||||
* that was loaded, not the mutable values currently being edited.
|
||||
*/
|
||||
public final class GuiConfigurationFileSnapshot {
|
||||
|
||||
private final Path filePath;
|
||||
private final Properties properties;
|
||||
|
||||
/**
|
||||
* Creates a snapshot for the given file and properties.
|
||||
*
|
||||
* @param filePath path of the loaded file; must not be {@code null}
|
||||
* @param properties loaded properties; must not be {@code null}
|
||||
*/
|
||||
public GuiConfigurationFileSnapshot(Path filePath, Properties properties) {
|
||||
this.filePath = Objects.requireNonNull(filePath, "filePath must not be null");
|
||||
this.properties = copyOf(properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file path of the loaded configuration.
|
||||
*
|
||||
* @return the snapshot file path; never {@code null}
|
||||
*/
|
||||
public Path filePath() {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a defensive copy of the loaded properties.
|
||||
*
|
||||
* @return a copy of the loaded properties; never {@code null}
|
||||
*/
|
||||
public Properties properties() {
|
||||
return copyOf(properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this snapshot was loaded from the given path.
|
||||
*
|
||||
* @param candidatePath the path to compare; may be {@code null}
|
||||
* @return {@code true} when the paths match, otherwise {@code false}
|
||||
*/
|
||||
public boolean hasFilePath(Path candidatePath) {
|
||||
return filePath.equals(candidatePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof GuiConfigurationFileSnapshot that)) {
|
||||
return false;
|
||||
}
|
||||
return filePath.equals(that.filePath) && properties.equals(that.properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(filePath, properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GuiConfigurationFileSnapshot{"
|
||||
+ "filePath=" + filePath
|
||||
+ ", properties=" + properties
|
||||
+ '}';
|
||||
}
|
||||
|
||||
private static Properties copyOf(Properties source) {
|
||||
Properties copy = new Properties();
|
||||
copy.putAll(Objects.requireNonNull(source, "properties must not be null"));
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package de.gecheckt.pdf.umbenenner.adapter.in.gui.editor;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import de.gecheckt.pdf.umbenenner.application.config.provider.AiProviderFamily;
|
||||
|
||||
/**
|
||||
* Creates the standard GUI configuration template.
|
||||
* <p>
|
||||
* The template contains both known provider blocks, a complete set of general configuration
|
||||
* values and a clean editor state that can be used for a brand-new configuration.
|
||||
*/
|
||||
public final class GuiConfigurationTemplateFactory {
|
||||
|
||||
private static final String SOURCE_FOLDER = "./work/local/source";
|
||||
private static final String TARGET_FOLDER = "./work/local/target";
|
||||
private static final String SQLITE_FILE = "./work/local/pdf-umbenenner.db";
|
||||
private static final String PROMPT_TEMPLATE_FILE = "./config/prompts/template.txt";
|
||||
private static final String RUNTIME_LOCK_FILE = "./work/local/pdf-umbenenner.lock";
|
||||
private static final String LOG_DIRECTORY = "./work/local/logs";
|
||||
private static final String LOG_LEVEL = "INFO";
|
||||
private static final String MAX_RETRIES_TRANSIENT = "3";
|
||||
private static final String MAX_PAGES = "10";
|
||||
private static final String MAX_TEXT_CHARACTERS = "5000";
|
||||
|
||||
private static final String OPENAI_BASE_URL = "https://api.openai.com/v1";
|
||||
private static final String OPENAI_MODEL = "gpt-4o-mini";
|
||||
private static final String OPENAI_TIMEOUT_SECONDS = "30";
|
||||
|
||||
private static final String CLAUDE_BASE_URL = "https://api.anthropic.com";
|
||||
private static final String CLAUDE_MODEL = "claude-3-5-sonnet-20241022";
|
||||
private static final String CLAUDE_TIMEOUT_SECONDS = "60";
|
||||
|
||||
private GuiConfigurationTemplateFactory() {
|
||||
// Utility class.
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a brand-new clean editor state containing the standard configuration template.
|
||||
*
|
||||
* @return a clean editor state with no loaded file snapshot
|
||||
*/
|
||||
public static GuiConfigurationEditorState createStandardTemplate() {
|
||||
GuiConfigurationValues standardValues = createStandardValues();
|
||||
return new GuiConfigurationEditorState(Optional.empty(), standardValues, standardValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the editable values for the standard configuration template.
|
||||
*
|
||||
* @return the standard editable configuration values
|
||||
*/
|
||||
public static GuiConfigurationValues createStandardValues() {
|
||||
Map<AiProviderFamily, GuiProviderConfigurationState> providerConfigurations = new LinkedHashMap<>();
|
||||
providerConfigurations.put(AiProviderFamily.CLAUDE, new GuiProviderConfigurationState(
|
||||
CLAUDE_BASE_URL,
|
||||
CLAUDE_MODEL,
|
||||
CLAUDE_TIMEOUT_SECONDS,
|
||||
GuiProviderApiKeyState.unresolved()));
|
||||
providerConfigurations.put(AiProviderFamily.OPENAI_COMPATIBLE, new GuiProviderConfigurationState(
|
||||
OPENAI_BASE_URL,
|
||||
OPENAI_MODEL,
|
||||
OPENAI_TIMEOUT_SECONDS,
|
||||
GuiProviderApiKeyState.unresolved()));
|
||||
|
||||
return new GuiConfigurationValues(
|
||||
SOURCE_FOLDER,
|
||||
TARGET_FOLDER,
|
||||
SQLITE_FILE,
|
||||
PROMPT_TEMPLATE_FILE,
|
||||
RUNTIME_LOCK_FILE,
|
||||
LOG_DIRECTORY,
|
||||
LOG_LEVEL,
|
||||
MAX_RETRIES_TRANSIENT,
|
||||
MAX_PAGES,
|
||||
MAX_TEXT_CHARACTERS,
|
||||
Boolean.toString(false),
|
||||
AiProviderFamily.CLAUDE.getIdentifier(),
|
||||
providerConfigurations);
|
||||
}
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
package de.gecheckt.pdf.umbenenner.adapter.in.gui.editor;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import de.gecheckt.pdf.umbenenner.application.config.provider.AiProviderFamily;
|
||||
|
||||
/**
|
||||
* Editable GUI values for the complete configuration document.
|
||||
* <p>
|
||||
* This object combines all known general configuration values and the provider-specific blocks
|
||||
* in a single model that can be rendered and edited by the GUI.
|
||||
*
|
||||
* @param sourceFolder source-folder path as editable text
|
||||
* @param targetFolder target-folder path as editable text
|
||||
* @param sqliteFile SQLite file path as editable text
|
||||
* @param promptTemplateFile prompt-template path as editable text
|
||||
* @param runtimeLockFile optional runtime lock file path as editable text
|
||||
* @param logDirectory optional log directory as editable text
|
||||
* @param logLevel log level as editable text
|
||||
* @param maxRetriesTransient transient retry limit as editable text
|
||||
* @param maxPages page limit as editable text
|
||||
* @param maxTextCharacters text limit as editable text
|
||||
* @param logAiSensitive raw value of {@code log.ai.sensitive} as editable text
|
||||
* @param activeProviderFamily raw value of {@code ai.provider.active} as editable text
|
||||
* @param providerConfigurations provider-specific editor state keyed by provider family
|
||||
*/
|
||||
public record GuiConfigurationValues(
|
||||
String sourceFolder,
|
||||
String targetFolder,
|
||||
String sqliteFile,
|
||||
String promptTemplateFile,
|
||||
String runtimeLockFile,
|
||||
String logDirectory,
|
||||
String logLevel,
|
||||
String maxRetriesTransient,
|
||||
String maxPages,
|
||||
String maxTextCharacters,
|
||||
String logAiSensitive,
|
||||
String activeProviderFamily,
|
||||
Map<AiProviderFamily, GuiProviderConfigurationState> providerConfigurations) {
|
||||
|
||||
/**
|
||||
* Creates a new editable configuration state.
|
||||
*
|
||||
* @param sourceFolder source-folder path; {@code null} becomes an empty string
|
||||
* @param targetFolder target-folder path; {@code null} becomes an empty string
|
||||
* @param sqliteFile SQLite file path; {@code null} becomes an empty string
|
||||
* @param promptTemplateFile prompt-template path; {@code null} becomes an empty string
|
||||
* @param runtimeLockFile runtime lock file path; {@code null} becomes an empty string
|
||||
* @param logDirectory log directory; {@code null} becomes an empty string
|
||||
* @param logLevel log level; {@code null} becomes an empty string
|
||||
* @param maxRetriesTransient transient retry limit; {@code null} becomes an empty string
|
||||
* @param maxPages page limit; {@code null} becomes an empty string
|
||||
* @param maxTextCharacters text limit; {@code null} becomes an empty string
|
||||
* @param logAiSensitive raw {@code log.ai.sensitive} value; {@code null} becomes an empty string
|
||||
* @param activeProviderFamily raw {@code ai.provider.active} value; {@code null} becomes an empty string
|
||||
* @param providerConfigurations provider-specific state map; must not be {@code null}
|
||||
*/
|
||||
public GuiConfigurationValues {
|
||||
sourceFolder = normalizeText(sourceFolder);
|
||||
targetFolder = normalizeText(targetFolder);
|
||||
sqliteFile = normalizeText(sqliteFile);
|
||||
promptTemplateFile = normalizeText(promptTemplateFile);
|
||||
runtimeLockFile = normalizeText(runtimeLockFile);
|
||||
logDirectory = normalizeText(logDirectory);
|
||||
logLevel = normalizeText(logLevel);
|
||||
maxRetriesTransient = normalizeText(maxRetriesTransient);
|
||||
maxPages = normalizeText(maxPages);
|
||||
maxTextCharacters = normalizeText(maxTextCharacters);
|
||||
logAiSensitive = normalizeText(logAiSensitive);
|
||||
activeProviderFamily = normalizeText(activeProviderFamily);
|
||||
|
||||
LinkedHashMap<AiProviderFamily, GuiProviderConfigurationState> copy = new LinkedHashMap<>();
|
||||
Objects.requireNonNull(providerConfigurations, "providerConfigurations must not be null")
|
||||
.forEach(copy::put);
|
||||
providerConfigurations = Collections.unmodifiableMap(copy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the editable state for the requested provider family.
|
||||
*
|
||||
* @param providerFamily the provider family to look up; must not be {@code null}
|
||||
* @return the matching provider state, or {@code null} when not present
|
||||
*/
|
||||
public GuiProviderConfigurationState providerConfiguration(AiProviderFamily providerFamily) {
|
||||
return providerConfigurations.get(providerFamily);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy with a different active provider-family identifier.
|
||||
*
|
||||
* @param providerFamily raw provider-family identifier; {@code null} becomes an empty string
|
||||
* @return a new configuration values object with the requested active provider value
|
||||
*/
|
||||
public GuiConfigurationValues withActiveProviderFamily(String providerFamily) {
|
||||
return new GuiConfigurationValues(sourceFolder, targetFolder, sqliteFile, promptTemplateFile,
|
||||
runtimeLockFile, logDirectory, logLevel, maxRetriesTransient, maxPages, maxTextCharacters,
|
||||
logAiSensitive, providerFamily, providerConfigurations);
|
||||
}
|
||||
|
||||
private static String normalizeText(String value) {
|
||||
return value == null ? "" : value;
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package de.gecheckt.pdf.umbenenner.adapter.in.gui.editor;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Editable state for a provider-specific API key.
|
||||
* <p>
|
||||
* This value object keeps the editable property value separate from the later displayable
|
||||
* origin of the effective key value. The editor can therefore preserve the property text
|
||||
* while later layers determine whether the effective value comes from the file, an
|
||||
* environment variable, a compatibility fallback, or a technical default.
|
||||
*
|
||||
* @param propertyValue editable API-key property value as entered or loaded from the file
|
||||
* @param effectiveValueOrigin provenance of the effective value shown or inferred later
|
||||
* @param effectiveValueDescription human-readable provenance description for later display
|
||||
*/
|
||||
public record GuiProviderApiKeyState(
|
||||
String propertyValue,
|
||||
GuiValueOrigin effectiveValueOrigin,
|
||||
String effectiveValueDescription) {
|
||||
|
||||
/**
|
||||
* Creates a key state with a blank property value and unresolved provenance.
|
||||
*
|
||||
* @return a new unresolved API-key state
|
||||
*/
|
||||
public static GuiProviderApiKeyState unresolved() {
|
||||
return new GuiProviderApiKeyState("", GuiValueOrigin.UNKNOWN, "nicht aufgeloest");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a key state with the supplied property value and unresolved provenance.
|
||||
*
|
||||
* @param propertyValue editable property value; may be {@code null}
|
||||
* @return a new unresolved API-key state
|
||||
*/
|
||||
public static GuiProviderApiKeyState unresolved(String propertyValue) {
|
||||
return new GuiProviderApiKeyState(propertyValue, GuiValueOrigin.UNKNOWN, "nicht aufgeloest");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a key state with an explicit effective-value provenance.
|
||||
*
|
||||
* @param propertyValue editable property value; may be {@code null}
|
||||
* @param effectiveValueOrigin origin of the effective value; must not be {@code null}
|
||||
* @param effectiveValueDescription human-readable provenance description; may be {@code null}
|
||||
* @return a new API-key state with the requested provenance
|
||||
*/
|
||||
public static GuiProviderApiKeyState resolved(String propertyValue,
|
||||
GuiValueOrigin effectiveValueOrigin,
|
||||
String effectiveValueDescription) {
|
||||
return new GuiProviderApiKeyState(propertyValue, effectiveValueOrigin, effectiveValueDescription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new key state.
|
||||
*
|
||||
* @param propertyValue editable property value; {@code null} is converted to an empty string
|
||||
* @param effectiveValueOrigin origin of the effective value; {@code null} becomes {@link GuiValueOrigin#UNKNOWN}
|
||||
* @param effectiveValueDescription human-readable provenance description; {@code null} becomes an empty string
|
||||
*/
|
||||
public GuiProviderApiKeyState {
|
||||
propertyValue = propertyValue == null ? "" : propertyValue;
|
||||
effectiveValueOrigin = Objects.requireNonNullElse(effectiveValueOrigin, GuiValueOrigin.UNKNOWN);
|
||||
effectiveValueDescription = effectiveValueDescription == null ? "" : effectiveValueDescription;
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package de.gecheckt.pdf.umbenenner.adapter.in.gui.editor;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Editable GUI state for one provider-family configuration block.
|
||||
* <p>
|
||||
* The fields are stored as editor-friendly strings so later GUI layers can bind them directly
|
||||
* to text-based controls without prematurely parsing or validating them.
|
||||
*
|
||||
* @param baseUrl provider endpoint base URL as editable text
|
||||
* @param model model identifier as editable text
|
||||
* @param timeoutSeconds timeout value as editable text
|
||||
* @param apiKey API-key state for the provider
|
||||
*/
|
||||
public record GuiProviderConfigurationState(
|
||||
String baseUrl,
|
||||
String model,
|
||||
String timeoutSeconds,
|
||||
GuiProviderApiKeyState apiKey) {
|
||||
|
||||
/**
|
||||
* Creates a provider configuration state with all text fields blank and the API key unresolved.
|
||||
*
|
||||
* @return a blank provider configuration state
|
||||
*/
|
||||
public static GuiProviderConfigurationState blank() {
|
||||
return new GuiProviderConfigurationState("", "", "", GuiProviderApiKeyState.unresolved());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new provider configuration state.
|
||||
*
|
||||
* @param baseUrl provider endpoint base URL; {@code null} becomes an empty string
|
||||
* @param model model identifier; {@code null} becomes an empty string
|
||||
* @param timeoutSeconds timeout value; {@code null} becomes an empty string
|
||||
* @param apiKey API-key state; when {@code null}, an unresolved blank key state is used
|
||||
*/
|
||||
public GuiProviderConfigurationState {
|
||||
baseUrl = baseUrl == null ? "" : baseUrl;
|
||||
model = model == null ? "" : model;
|
||||
timeoutSeconds = timeoutSeconds == null ? "" : timeoutSeconds;
|
||||
apiKey = Objects.requireNonNullElse(apiKey, GuiProviderApiKeyState.unresolved());
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package de.gecheckt.pdf.umbenenner.adapter.in.gui.editor;
|
||||
|
||||
/**
|
||||
* Describes the effective origin of a configuration value shown by the editor.
|
||||
* <p>
|
||||
* The enum is intentionally broad enough to accommodate later provenance display for
|
||||
* provider-specific values such as API keys.
|
||||
*/
|
||||
public enum GuiValueOrigin {
|
||||
|
||||
/** The value has not been resolved to a concrete origin yet. */
|
||||
UNKNOWN,
|
||||
|
||||
/** The value comes from the editable property value stored in the configuration file. */
|
||||
PROPERTY_VALUE,
|
||||
|
||||
/** The value comes from a provider-specific environment variable. */
|
||||
ENVIRONMENT_VARIABLE,
|
||||
|
||||
/** The value comes from the legacy environment variable accepted for compatibility. */
|
||||
LEGACY_ENVIRONMENT_VARIABLE,
|
||||
|
||||
/** The value is a technical default supplied by the application. */
|
||||
DEFAULT_VALUE
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Editor state and template model for the JavaFX configuration editor.
|
||||
* <p>
|
||||
* This package contains the GUI-side representation of configuration data that can be edited
|
||||
* independently from file I/O and validation. It separates loaded file snapshots, baseline
|
||||
* editor values, current editor values, provider-specific API key state, and the derived
|
||||
* dirty-state view used by the GUI.
|
||||
* <p>
|
||||
* The classes in this package are intentionally free of JavaFX controls so they can be reused
|
||||
* by later GUI layers without coupling the model to a particular layout implementation.
|
||||
*/
|
||||
package de.gecheckt.pdf.umbenenner.adapter.in.gui.editor;
|
||||
Reference in New Issue
Block a user