claude refactor
This commit is contained in:
parent
1e6b33175a
commit
d1358cc6d3
@ -1,5 +1,5 @@
|
|||||||
#Llama Runner Configuration
|
#Llama Runner Configuration
|
||||||
#Sun Mar 29 17:31:07 CEST 2026
|
#Sun Mar 29 17:54:05 CEST 2026
|
||||||
windowHeight=1189
|
windowHeight=1189
|
||||||
windowWidth=711
|
windowWidth=711
|
||||||
windowX=1849
|
windowX=1849
|
||||||
|
|||||||
@ -10,112 +10,73 @@ import com.google.gson.JsonSyntaxException;
|
|||||||
*/
|
*/
|
||||||
public class ConfigValidation {
|
public class ConfigValidation {
|
||||||
|
|
||||||
private static final Gson GSON = new Gson();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates numeric fields for valid ranges.
|
* Validates a ModelConfig object.
|
||||||
*
|
*
|
||||||
* @return a list of error messages (empty if valid)
|
* @param config the model config to validate
|
||||||
|
* @return error message if invalid, null if valid
|
||||||
*/
|
*/
|
||||||
public static java.util.List<String> validateNumericInputs(
|
public static String validateConfig(ModelConfig config) {
|
||||||
String host,
|
|
||||||
int port,
|
|
||||||
int parallel,
|
|
||||||
int threads,
|
|
||||||
double temperature,
|
|
||||||
double topP,
|
|
||||||
int topK,
|
|
||||||
double minP,
|
|
||||||
int ctxSize,
|
|
||||||
int ngl) {
|
|
||||||
|
|
||||||
java.util.List<String> errors = new java.util.ArrayList<>();
|
|
||||||
|
|
||||||
// Validate port
|
// Validate port
|
||||||
if (port < 1 || port > 65535) {
|
if (config.getPort() < 1 || config.getPort() > 65535) {
|
||||||
errors.add("Port must be between 1 and 65535");
|
return "Port must be between 1 and 65535";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate parallel
|
// Validate parallel
|
||||||
if (parallel < 1) {
|
if (config.getParallel() < 1) {
|
||||||
errors.add("Parallel must be at least 1");
|
return "Parallel must be at least 1";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate threads
|
// Validate threads
|
||||||
if (threads < 1) {
|
if (config.getThreads() < 1) {
|
||||||
errors.add("Threads must be at least 1");
|
return "Threads must be at least 1";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate temperature
|
// Validate temperature
|
||||||
if (temperature < 0) {
|
if (config.getTemperature() < 0) {
|
||||||
errors.add("Temperature must be non-negative");
|
return "Temperature must be non-negative";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate topP
|
// Validate topP
|
||||||
if (topP < 0 || topP > 1) {
|
if (config.getTopP() < 0 || config.getTopP() > 1) {
|
||||||
errors.add("Top P must be between 0 and 1");
|
return "Top P must be between 0 and 1";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate topK
|
// Validate topK
|
||||||
if (topK < 0) {
|
if (config.getTopK() < 0) {
|
||||||
errors.add("Top K must be non-negative");
|
return "Top K must be non-negative";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate minP
|
// Validate minP
|
||||||
if (minP < 0 || minP > 1) {
|
if (config.getMinP() < 0 || config.getMinP() > 1) {
|
||||||
errors.add("Min P must be between 0 and 1");
|
return "Min P must be between 0 and 1";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate ctxSize
|
// Validate ctxSize
|
||||||
if (ctxSize < 0) {
|
if (config.getCtxSize() < 0) {
|
||||||
errors.add("Context size must be non-negative");
|
return "Context size must be non-negative";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate ngl
|
// Validate model path
|
||||||
if (ngl < 0) {
|
if (config.getModelPath() == null || config.getModelPath().trim().isEmpty()) {
|
||||||
errors.add("GPU layers must be non-negative");
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates JSON string for chatTemplateKwargs.
|
|
||||||
*
|
|
||||||
* @param json the JSON string to validate
|
|
||||||
* @return error message if invalid, null if valid
|
|
||||||
*/
|
|
||||||
public static String validateJsonKwargs(String json) {
|
|
||||||
if (json == null || json.trim().isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
GSON.fromJson(json, Object.class);
|
|
||||||
return null;
|
|
||||||
} catch (JsonSyntaxException e) {
|
|
||||||
return "Invalid JSON format in kwargs";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates model path exists.
|
|
||||||
*
|
|
||||||
* @param modelPath the model file path
|
|
||||||
* @return error message if file doesn't exist, null if valid
|
|
||||||
*/
|
|
||||||
public static String validateModelPath(String modelPath) {
|
|
||||||
if (modelPath == null || modelPath.trim().isEmpty()) {
|
|
||||||
return "Model path cannot be empty";
|
return "Model path cannot be empty";
|
||||||
}
|
}
|
||||||
|
File modelFile = new File(config.getModelPath());
|
||||||
File modelFile = new File(modelPath);
|
|
||||||
if (!modelFile.exists()) {
|
if (!modelFile.exists()) {
|
||||||
return "Model file does not exist: " + modelPath;
|
return "Model file does not exist: " + config.getModelPath();
|
||||||
|
}
|
||||||
|
if (!modelFile.isFile()) {
|
||||||
|
return "Model path is not a file: " + config.getModelPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!modelFile.isFile()) {
|
// Validate JSON kwargs
|
||||||
return "Model path is not a file: " + modelPath;
|
String json = config.getChatTemplateKwargs();
|
||||||
|
if (json != null && !json.trim().isEmpty()) {
|
||||||
|
try {
|
||||||
|
new Gson().fromJson(json, Object.class);
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
return "Invalid JSON format in kwargs";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
95
src/main/java/cz/kamma/llamarunner/InputDialog.java
Normal file
95
src/main/java/cz/kamma/llamarunner/InputDialog.java
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package cz.kamma.llamarunner;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.FlowLayout;
|
||||||
|
import java.awt.GridBagConstraints;
|
||||||
|
import java.awt.GridBagLayout;
|
||||||
|
import java.awt.Insets;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JDialog;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JTextField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reusable dialog for simple text input.
|
||||||
|
*/
|
||||||
|
public class InputDialog {
|
||||||
|
|
||||||
|
private final JDialog dialog;
|
||||||
|
private final String[] result = new String[1];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a dialog for text input.
|
||||||
|
*
|
||||||
|
* @param parent the parent frame
|
||||||
|
* @param title the dialog title
|
||||||
|
* @param label the label text
|
||||||
|
* @param defaultValue the default value
|
||||||
|
* @return the input text, or null if cancelled
|
||||||
|
*/
|
||||||
|
public static String showInputDialog(java.awt.Frame parent, String title, String label, String defaultValue) {
|
||||||
|
InputDialog dialog = new InputDialog(parent, title, label, defaultValue);
|
||||||
|
dialog.show();
|
||||||
|
return dialog.getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
private InputDialog(java.awt.Frame parent, String title, String label, String defaultValue) {
|
||||||
|
dialog = new JDialog(parent, title, true);
|
||||||
|
dialog.setResizable(false);
|
||||||
|
|
||||||
|
// Input panel
|
||||||
|
JPanel inputPanel = new JPanel(new GridBagLayout());
|
||||||
|
GridBagConstraints gbc = new GridBagConstraints();
|
||||||
|
gbc.insets = new Insets(4, 4, 4, 4);
|
||||||
|
gbc.anchor = GridBagConstraints.WEST;
|
||||||
|
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||||
|
|
||||||
|
gbc.gridx = 0;
|
||||||
|
gbc.gridy = 0;
|
||||||
|
inputPanel.add(new JLabel(label), gbc);
|
||||||
|
|
||||||
|
gbc.gridx = 1;
|
||||||
|
gbc.weightx = 1.0;
|
||||||
|
JTextField textField = new JTextField(20);
|
||||||
|
textField.setText(defaultValue);
|
||||||
|
textField.setCaretColor(Color.WHITE);
|
||||||
|
inputPanel.add(textField, gbc);
|
||||||
|
|
||||||
|
dialog.add(inputPanel, BorderLayout.CENTER);
|
||||||
|
|
||||||
|
// Button panel
|
||||||
|
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 8, 0));
|
||||||
|
JButton okButton = new JButton("OK");
|
||||||
|
okButton.addActionListener(e -> {
|
||||||
|
result[0] = textField.getText().trim();
|
||||||
|
dialog.dispose();
|
||||||
|
});
|
||||||
|
buttonPanel.add(okButton);
|
||||||
|
|
||||||
|
JButton cancelButton = new JButton("Cancel");
|
||||||
|
cancelButton.addActionListener(e -> {
|
||||||
|
result[0] = null;
|
||||||
|
dialog.dispose();
|
||||||
|
});
|
||||||
|
buttonPanel.add(cancelButton);
|
||||||
|
|
||||||
|
dialog.add(buttonPanel, BorderLayout.SOUTH);
|
||||||
|
|
||||||
|
// Center dialog
|
||||||
|
dialog.setSize(350, 100);
|
||||||
|
dialog.setLocationRelativeTo(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void show() {
|
||||||
|
dialog.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getResult() {
|
||||||
|
if (result[0] == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return result[0].isEmpty() ? null : result[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -22,7 +22,6 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.BorderFactory;
|
import javax.swing.BorderFactory;
|
||||||
import javax.swing.JDialog;
|
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JCheckBox;
|
import javax.swing.JCheckBox;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
@ -313,16 +312,27 @@ public class Main extends JFrame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
String validationError = validateCurrentConfig();
|
||||||
|
if (validationError != null) {
|
||||||
|
JOptionPane.showMessageDialog(this, validationError, "Validation Error",
|
||||||
|
JOptionPane.ERROR_MESSAGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
saveProfileToName(currentProfile);
|
saveProfileToName(currentProfile);
|
||||||
JOptionPane.showMessageDialog(this, "Profile saved!");
|
JOptionPane.showMessageDialog(this, "Profile saved!");
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
JOptionPane.showMessageDialog(this, "Error saving: " + e.getMessage() + "\n" + e.toString(), "Error",
|
JOptionPane.showMessageDialog(this, "Error saving: " + e.getMessage(), "Error",
|
||||||
JOptionPane.ERROR_MESSAGE);
|
JOptionPane.ERROR_MESSAGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String validateCurrentConfig() {
|
||||||
|
ModelConfig config = buildModelConfig();
|
||||||
|
return ConfigValidation.validateConfig(config);
|
||||||
|
}
|
||||||
|
|
||||||
private void saveProfileToName(String name) throws IOException {
|
private void saveProfileToName(String name) throws IOException {
|
||||||
ModelConfig config = buildModelConfig();
|
ModelConfig config = buildModelConfig();
|
||||||
profileManager.saveProfile(name, config);
|
profileManager.saveProfile(name, config);
|
||||||
@ -404,58 +414,9 @@ public class Main extends JFrame {
|
|||||||
String modelName = (String) modelComboBox.getSelectedItem();
|
String modelName = (String) modelComboBox.getSelectedItem();
|
||||||
String defaultName = modelName != null ? modelName : "";
|
String defaultName = modelName != null ? modelName : "";
|
||||||
|
|
||||||
String[] result = new String[1];
|
String newName = InputDialog.showInputDialog(this, "Save profile as...", "Profile name:", defaultName);
|
||||||
|
|
||||||
JDialog dialog = new JDialog(this, "Save profile as...", true);
|
if (newName == null) {
|
||||||
dialog.setLayout(new BorderLayout(8, 8));
|
|
||||||
dialog.setResizable(false);
|
|
||||||
|
|
||||||
// Input panel
|
|
||||||
JPanel inputPanel = new JPanel(new GridBagLayout());
|
|
||||||
GridBagConstraints gbc = new GridBagConstraints();
|
|
||||||
gbc.insets = new Insets(4, 4, 4, 4);
|
|
||||||
gbc.anchor = GridBagConstraints.WEST;
|
|
||||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
|
||||||
|
|
||||||
gbc.gridx = 0;
|
|
||||||
gbc.gridy = 0;
|
|
||||||
inputPanel.add(new JLabel("Profile name:"), gbc);
|
|
||||||
|
|
||||||
gbc.gridx = 1;
|
|
||||||
gbc.weightx = 1.0;
|
|
||||||
JTextField nameField = new JTextField(20);
|
|
||||||
nameField.setText(defaultName);
|
|
||||||
nameField.setCaretColor(Color.WHITE);
|
|
||||||
inputPanel.add(nameField, gbc);
|
|
||||||
|
|
||||||
dialog.add(inputPanel, BorderLayout.CENTER);
|
|
||||||
|
|
||||||
// Button panel
|
|
||||||
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 8, 0));
|
|
||||||
JButton okButton = new JButton("OK");
|
|
||||||
okButton.addActionListener(e -> {
|
|
||||||
result[0] = nameField.getText().trim();
|
|
||||||
dialog.dispose();
|
|
||||||
});
|
|
||||||
buttonPanel.add(okButton);
|
|
||||||
|
|
||||||
JButton cancelButton = new JButton("Cancel");
|
|
||||||
cancelButton.addActionListener(e -> {
|
|
||||||
result[0] = null;
|
|
||||||
dialog.dispose();
|
|
||||||
});
|
|
||||||
buttonPanel.add(cancelButton);
|
|
||||||
|
|
||||||
dialog.add(buttonPanel, BorderLayout.SOUTH);
|
|
||||||
|
|
||||||
// Center dialog
|
|
||||||
dialog.setSize(350, 100);
|
|
||||||
dialog.setLocationRelativeTo(this);
|
|
||||||
dialog.setVisible(true);
|
|
||||||
|
|
||||||
String newName = result[0];
|
|
||||||
|
|
||||||
if (newName == null || newName.isEmpty()) {
|
|
||||||
return; // Cancelled by user
|
return; // Cancelled by user
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -531,58 +492,9 @@ public class Main extends JFrame {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] result = new String[1];
|
String newName = InputDialog.showInputDialog(this, "Rename profile", "New profile name:", oldName);
|
||||||
|
|
||||||
JDialog dialog = new JDialog(this, "Rename profile", true);
|
if (newName == null) {
|
||||||
dialog.setLayout(new BorderLayout(8, 8));
|
|
||||||
dialog.setResizable(false);
|
|
||||||
|
|
||||||
// Input panel
|
|
||||||
JPanel inputPanel = new JPanel(new GridBagLayout());
|
|
||||||
GridBagConstraints gbc = new GridBagConstraints();
|
|
||||||
gbc.insets = new Insets(4, 4, 4, 4);
|
|
||||||
gbc.anchor = GridBagConstraints.WEST;
|
|
||||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
|
||||||
|
|
||||||
gbc.gridx = 0;
|
|
||||||
gbc.gridy = 0;
|
|
||||||
inputPanel.add(new JLabel("New profile name:"), gbc);
|
|
||||||
|
|
||||||
gbc.gridx = 1;
|
|
||||||
gbc.weightx = 1.0;
|
|
||||||
JTextField nameField = new JTextField(20);
|
|
||||||
nameField.setText(oldName);
|
|
||||||
nameField.setCaretColor(Color.WHITE);
|
|
||||||
inputPanel.add(nameField, gbc);
|
|
||||||
|
|
||||||
dialog.add(inputPanel, BorderLayout.CENTER);
|
|
||||||
|
|
||||||
// Button panel
|
|
||||||
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 8, 0));
|
|
||||||
JButton okButton = new JButton("OK");
|
|
||||||
okButton.addActionListener(e -> {
|
|
||||||
result[0] = nameField.getText().trim();
|
|
||||||
dialog.dispose();
|
|
||||||
});
|
|
||||||
buttonPanel.add(okButton);
|
|
||||||
|
|
||||||
JButton cancelButton = new JButton("Cancel");
|
|
||||||
cancelButton.addActionListener(e -> {
|
|
||||||
result[0] = null;
|
|
||||||
dialog.dispose();
|
|
||||||
});
|
|
||||||
buttonPanel.add(cancelButton);
|
|
||||||
|
|
||||||
dialog.add(buttonPanel, BorderLayout.SOUTH);
|
|
||||||
|
|
||||||
// Center dialog
|
|
||||||
dialog.setSize(350, 100);
|
|
||||||
dialog.setLocationRelativeTo(this);
|
|
||||||
dialog.setVisible(true);
|
|
||||||
|
|
||||||
String newName = result[0];
|
|
||||||
|
|
||||||
if (newName == null || newName.isEmpty()) {
|
|
||||||
return; // Cancelled by user
|
return; // Cancelled by user
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -895,15 +807,7 @@ public class Main extends JFrame {
|
|||||||
ctxSizeField = new JTextField("180000", 10);
|
ctxSizeField = new JTextField("180000", 10);
|
||||||
ctxSizeField.setCaretColor(Color.WHITE);
|
ctxSizeField.setCaretColor(Color.WHITE);
|
||||||
ctxSizeField.addActionListener(e -> updateCommandPreview());
|
ctxSizeField.addActionListener(e -> updateCommandPreview());
|
||||||
// Update preview on any change, not just Enter
|
ctxSizeField.getDocument().addDocumentListener(new PreviewUpdateListener(this::updateCommandPreview));
|
||||||
ctxSizeField.getDocument().addDocumentListener(new javax.swing.event.DocumentListener() {
|
|
||||||
@Override
|
|
||||||
public void insertUpdate(javax.swing.event.DocumentEvent e) { updateCommandPreview(); }
|
|
||||||
@Override
|
|
||||||
public void removeUpdate(javax.swing.event.DocumentEvent e) { updateCommandPreview(); }
|
|
||||||
@Override
|
|
||||||
public void changedUpdate(javax.swing.event.DocumentEvent e) { updateCommandPreview(); }
|
|
||||||
});
|
|
||||||
panel.add(ctxSizeField, gbc);
|
panel.add(ctxSizeField, gbc);
|
||||||
|
|
||||||
gbc.gridx = 0;
|
gbc.gridx = 0;
|
||||||
@ -916,22 +820,7 @@ public class Main extends JFrame {
|
|||||||
gbc.weightx = 1.0;
|
gbc.weightx = 1.0;
|
||||||
kwargsField = new JTextField("{\"enable_thinking\": true}");
|
kwargsField = new JTextField("{\"enable_thinking\": true}");
|
||||||
kwargsField.setCaretColor(Color.WHITE);
|
kwargsField.setCaretColor(Color.WHITE);
|
||||||
kwargsField.getDocument().addDocumentListener(new javax.swing.event.DocumentListener() {
|
kwargsField.getDocument().addDocumentListener(new PreviewUpdateListener(this::updateCommandPreview));
|
||||||
@Override
|
|
||||||
public void insertUpdate(javax.swing.event.DocumentEvent e) {
|
|
||||||
updateCommandPreview();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeUpdate(javax.swing.event.DocumentEvent e) {
|
|
||||||
updateCommandPreview();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void changedUpdate(javax.swing.event.DocumentEvent e) {
|
|
||||||
updateCommandPreview();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
panel.add(kwargsField, gbc);
|
panel.add(kwargsField, gbc);
|
||||||
|
|
||||||
return panel;
|
return panel;
|
||||||
@ -987,22 +876,7 @@ public class Main extends JFrame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private javax.swing.event.DocumentListener createNglDocumentListener() {
|
private javax.swing.event.DocumentListener createNglDocumentListener() {
|
||||||
return new javax.swing.event.DocumentListener() {
|
return new PreviewUpdateListener(this::updateCommandPreview);
|
||||||
@Override
|
|
||||||
public void insertUpdate(javax.swing.event.DocumentEvent e) {
|
|
||||||
updateCommandPreview();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeUpdate(javax.swing.event.DocumentEvent e) {
|
|
||||||
updateCommandPreview();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void changedUpdate(javax.swing.event.DocumentEvent e) {
|
|
||||||
updateCommandPreview();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void copyCommandToClipboard() {
|
private void copyCommandToClipboard() {
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
package cz.kamma.llamarunner;
|
||||||
|
|
||||||
|
import javax.swing.event.DocumentEvent;
|
||||||
|
import javax.swing.event.DocumentListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DocumentListener that updates command preview on text changes.
|
||||||
|
*/
|
||||||
|
public class PreviewUpdateListener implements DocumentListener {
|
||||||
|
|
||||||
|
private final Runnable updateCallback;
|
||||||
|
|
||||||
|
public PreviewUpdateListener(Runnable updateCallback) {
|
||||||
|
this.updateCallback = updateCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insertUpdate(DocumentEvent e) {
|
||||||
|
updateCallback.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUpdate(DocumentEvent e) {
|
||||||
|
updateCallback.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changedUpdate(DocumentEvent e) {
|
||||||
|
updateCallback.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -34,18 +34,4 @@ public class ProfileValidator {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
}
|
||||||
* Checks if a profile name is unique among existing profiles.
|
|
||||||
*
|
|
||||||
* @param newName the new profile name
|
|
||||||
* @param existingProfiles list of existing profile names
|
|
||||||
* @return true if unique, false otherwise
|
|
||||||
*/
|
|
||||||
public static boolean isProfileNameUnique(String newName, java.util.List<String> existingProfiles) {
|
|
||||||
if (existingProfiles == null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return !existingProfiles.stream()
|
|
||||||
.anyMatch(name -> name.equalsIgnoreCase(newName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user