All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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 values = new ArrayList<>(length); for (int i = 0; i < length; i++) { values.add(Array.get(value, i)); } toSave = Joiner.on(",").join(values); } else { toSave = value.toString(); } } applicationConfig.setOption(option.getKey(), toSave); } // l'option a été sauvegardée, on la marque option.setSaved(true); // this is the new original value option.initValue(value); } if (option.isTransient()) { transients.add(option.getKey()); } } setSaved(true); // save config // Ano // applicationConfig.saveForUser(transients.toArray(new String[transients.size()])); try { applicationConfig.save(configFile, false, transients.toArray(new String[0])); } catch (IOException eee) { log.warn(t("config.error.applicationconfig.save", configFile), eee); } // notify data has changed categoryModel.firePropertyChange(CategoryModel.MODIFIED_PROPERTY_NAME, categoryModel.isModified(), true); categoryModel.firePropertyChange(CategoryModel.VALID_PROPERTY_NAME, false, categoryModel.isValid()); categoryModel.firePropertyChange(CategoryModel.RELOAD_PROPERTY_NAME, false, true); } public void reset() { // reset all modified options of the current category for (OptionModel key : categoryModel) { if (key.isModified()) { key.initValue(key.getOriginalValue()); } } // notify data has changed categoryModel.firePropertyChange(CategoryModel.MODIFIED_PROPERTY_NAME, categoryModel.isModified(), true); categoryModel.firePropertyChange(CategoryModel.VALID_PROPERTY_NAME, false, categoryModel.isValid()); categoryModel.firePropertyChange(CategoryModel.RELOAD_PROPERTY_NAME, false, true); } public int getCategoryIndex(String category) { int i = 0; for (CategoryModel m : this) { if (category.equals(m.getCategory())) { return i; } i++; } // not found return -1; } public void firePropertyChange(String propertyName, Object oldValue, Object newValue) { pcs.firePropertyChange(propertyName, oldValue, newValue); } public void addPropertyChangeListener(PropertyChangeListener listener) { pcs.addPropertyChangeListener(listener); } public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { pcs.addPropertyChangeListener(propertyName, listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { pcs.removePropertyChangeListener(listener); } public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { pcs.removePropertyChangeListener(propertyName, listener); } public boolean hasListeners(String propertyName) { return pcs.hasListeners(propertyName); } public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { return pcs.getPropertyChangeListeners(propertyName); } public PropertyChangeListener[] getPropertyChangeListeners() { return pcs.getPropertyChangeListeners(); } public void destroy() { JAXXUtil.destroy(pcs); categories.values().forEach(CategoryModel::destroy); } /** * @return the underlined application config * @since 2.5.4 */ protected ApplicationConfig getApplicationConfig() { return applicationConfig; } protected CallBacksManager getCallBacksManager() { return callBacksManager; } public String getCategoryName(int index) { return new ArrayList<>(categories.keySet()).get(index); } }