org.nuiton.jaxx.widgets.config.model.ConfigUIModel Maven / Gradle / Ivy
package org.nuiton.jaxx.widgets.config.model;
/*
* #%L
* JAXX :: Widgets
* %%
* Copyright (C) 2008 - 2024 Code Lutin, Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
import com.google.common.base.Joiner;
import io.ultreia.java4all.config.ApplicationConfig;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.nuiton.jaxx.runtime.JAXXUtil;
import javax.swing.Icon;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static io.ultreia.java4all.i18n.I18n.t;
/**
* Le modele de l'ui des preferences.
*
* Ce modele contient les catégories des options.
*
* @author Tony Chemit - [email protected]
* @since 2.5.11
*/
public class ConfigUIModel implements Iterable {
public static final String CATEGORY_MODEL_PROPERTY_NAME = "categoryModel";
/**
* Logger.
*/
private static final Logger log = LogManager.getLogger(ConfigUIModel.class);
/**
* le dictionnaire des options disponibles par categorie
*/
protected final Map categories;
/**
* Le fichier où sauvegarder la configuration.
*
* @since 2.5.21
*/
protected final File configFile;
/**
* La configuration de l'application
*/
protected final Object configBean;
/**
* La configuration de l'application
*/
protected final ApplicationConfig applicationConfig;
/**
* Callbacks manager
*/
protected final CallBacksManager callBacksManager;
/**
* support of modification notifications
*/
protected final PropertyChangeSupport pcs;
/**
* la cateogrie en cours d'utilisation
*/
protected CategoryModel categoryModel;
/**
* un drapeau pour savoir si la configuration a été modifiée au moins une
* fois.
*
* On utilise ce drapeau lors de la sortie pour verifier s'il faut ou non
* redemarer l'application (si non en mode standalone)
*/
protected boolean saved;
/**
* un drapeau pour savoir si l'ui de configuration a été lancée en mode
* standalone ou pas.
*
* Si pas lancée en mode standalone, et si la confi a été sauvé on vérifie
* s'il ne faut pas relancer l'application.
*/
protected boolean standalone;
/**
* optional action to execute (if not null) if no call backs fits.
*
* @since 1.4.2
*/
protected Runnable closeAction;
public ConfigUIModel(Object configBean, ApplicationConfig applicationConfig, File configFile) {
this.configBean = configBean;
this.applicationConfig = applicationConfig;
this.configFile = configFile;
this.categories = new LinkedHashMap<>();
callBacksManager = new CallBacksManager();
pcs = new PropertyChangeSupport(this);
}
/**
* Ajoute une categorie dans le modele.
*
* @param category la categorie a ajouter au modèle.
*/
public void addCategory(CategoryModel category) {
if (categories.containsKey(category.getCategory())) {
throw new IllegalArgumentException(t("config.error.category.already.exists", category.getCategory()));
}
categories.put(category.getCategory(), category);
}
/**
* Change la categorie en cours d'édition.
*
* @param category l'id de la categorie courante
*/
public void setCategory(String category) {
if (!categories.containsKey(category)) {
throw new IllegalArgumentException(t("config.error.category.not.found", category));
}
CategoryModel newCategoryModel = categories.get(category);
setCategoryModel(newCategoryModel);
newCategoryModel.firePropertyChange(CategoryModel.MODIFIED_PROPERTY_NAME, false, getCategoryModel().isModified());
newCategoryModel.firePropertyChange(CategoryModel.VALID_PROPERTY_NAME, false, getCategoryModel().isValid());
}
/**
* Registers a new callback.
*
* Note: the order of registred callback is used to determine
* the higher priority of callback to launch if required.
*
* @param name the unique name of a callback
* @param description the i18n key to describe the action
* @param icon the icon of the callBack (used in ui)
* @param action the action of the callback
*/
public void registerCallBack(String name,
String description,
Icon icon,
Runnable action) {
callBacksManager.registerCallBack(name, description, icon, action);
}
/**
* Registers a option into a known callback.
*
* @param name the name of the callback
* @param option the option to register for the given callback
*/
public void registerOptionCallBack(String name, OptionModel option) {
callBacksManager.registerOption(name, option);
}
public void setFinalizer(CallBackFinalizer finalizer) {
callBacksManager.setFinalizer(finalizer);
}
public Runnable getCloseAction() {
return closeAction;
}
public void setCloseAction(Runnable closeAction) {
this.closeAction = closeAction;
}
/**
* Obtain the dictionnary of callback for all to saved modified options.
*
* @return the dictonnary
*/
public CallBackMap getCallBacksForSaved() {
return callBacksManager.getCallBacksForSaved(this);
}
@Override
public Iterator iterator() {
return categories.values().iterator();
}
public CategoryModel getCategoryModel() {
return categoryModel;
}
public void setCategoryModel(CategoryModel categoryModel) {
CategoryModel old = this.categoryModel;
this.categoryModel = categoryModel;
firePropertyChange(CATEGORY_MODEL_PROPERTY_NAME, old, categoryModel);
}
public boolean isSaved() {
return saved;
}
public void setSaved(boolean saved) {
this.saved = saved;
}
public boolean isStandalone() {
return standalone;
}
public void setStandalone(boolean standalone) {
this.standalone = standalone;
}
public void saveModified() {
// compute transients keys (to never be saved)
List transients = new ArrayList<>();
for (OptionModel option : categoryModel) {
if (option.isModified()) {
Object value = option.getValue();
if (option.getPropertyName() != null) {
// this is a javaBean option, push value via mutator
try {
PropertyUtils.setProperty(configBean, option.getPropertyName(), value);
} catch (Exception e) {
throw new RuntimeException(String.format("could not set property [%s] with value = %s", option.getPropertyName(), value), e);
}
} else {
// simple option with no javabeans, just push the option
// value
String toSave;
if (value == null) {
toSave = null;
} else {
if (option.isArrayType()) {
int length = Array.getLength(value);
List