diff --git a/ccm-bundle-devel-wildfly-web/src/main/resources/log4j2.xml b/ccm-bundle-devel-wildfly-web/src/main/resources/log4j2.xml index 340d8d223..c1a52dc5d 100644 --- a/ccm-bundle-devel-wildfly-web/src/main/resources/log4j2.xml +++ b/ccm-bundle-devel-wildfly-web/src/main/resources/log4j2.xml @@ -12,6 +12,9 @@ + + diff --git a/ccm-core/src/main/java/com/arsdigita/bebop/ActionLink.java b/ccm-core/src/main/java/com/arsdigita/bebop/ActionLink.java index b5a63603a..4c4aab7b2 100644 --- a/ccm-core/src/main/java/com/arsdigita/bebop/ActionLink.java +++ b/ccm-core/src/main/java/com/arsdigita/bebop/ActionLink.java @@ -47,7 +47,7 @@ public class ActionLink extends ControlLink { /** * The value for the XML type attribute for an {@link ActionLink}. */ - protected final String TYPE_ACTION = "action"; + protected static final String TYPE_ACTION = "action"; /** * Constructs a new ActionLink. The link encapsulates diff --git a/ccm-core/src/main/java/com/arsdigita/ui/UIConfig.java b/ccm-core/src/main/java/com/arsdigita/ui/UIConfig.java index 276af75ec..ce1af3761 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/UIConfig.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/UIConfig.java @@ -159,10 +159,10 @@ public final class UIConfig { @Override public String toString() { - final StringJoiner joiner = new StringJoiner(", "); - if (defaultLayout != null) { - defaultLayout.forEach(s -> joiner.add(s)); - } +// final StringJoiner joiner = new StringJoiner(", "); +// if (defaultLayout != null) { +// defaultLayout.forEach(s -> joiner.add(s)); +// } return String.format("%s{ " + "defaultLayout = \"%s\", " diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/AbstractSettingFormSingleValue.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/AbstractSettingFormSingleValue.java index 0e3ff0340..2bf1c0dff 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/AbstractSettingFormSingleValue.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/AbstractSettingFormSingleValue.java @@ -40,11 +40,11 @@ import org.libreccm.cdi.utils.CdiUtil; import org.libreccm.configuration.ConfigurationManager; import java.lang.reflect.Field; -import java.math.BigDecimal; import static com.arsdigita.ui.admin.AdminUiConstants.*; /** + * An abstract base class for a form for editing settings with a single value. * * @author Jens Pelzetter * @param @@ -56,6 +56,16 @@ public abstract class AbstractSettingFormSingleValue extends Form { private static final String VALUE_FIELD = "valueField"; + private final SaveCancelSection saveCancelSection; + + /** + * Constructor, initialises the form and the supporting widgets. + * + * @param configurationTab The configuration tab in which the form is shown. + * @param selectedConf Parameter containing the selected configuration + * class. + * @param selectedSetting Parameter containing the selected setting. + */ public AbstractSettingFormSingleValue( final ConfigurationTab configurationTab, final ParameterSingleSelectionModel selectedConf, @@ -63,7 +73,9 @@ public abstract class AbstractSettingFormSingleValue extends Form { super("settingFormSingleValue", new BoxPanel(BoxPanel.VERTICAL)); - add(new SettingFormHeader(selectedConf, selectedSetting)); + add(new SettingFormHeader(configurationTab, + selectedConf, + selectedSetting)); add(new SettingFormCurrentValuePanel(selectedConf, selectedSetting)); @@ -72,7 +84,7 @@ public abstract class AbstractSettingFormSingleValue extends Form { "ui.admin.configuration.setting.edit.new_value", ADMIN_BUNDLE)); add(valueField); - final SaveCancelSection saveCancelSection = new SaveCancelSection(); + saveCancelSection = new SaveCancelSection(); add(saveCancelSection); addInitListener(new InitListener(selectedConf, @@ -87,8 +99,20 @@ public abstract class AbstractSettingFormSingleValue extends Form { } + /** + * Converts a string to the value type of the setting. Must be overwritten + * by the none abstract sub classes. + * + * @param valueData The data to convert. + * + * @return The converted data. + */ abstract T convertValue(final String valueData); + /** + * {@link FormInitListener} for the form. Loads the current value of the + * setting from the database and puts it into the input field. + */ private class InitListener implements FormInitListener { private final ParameterSingleSelectionModel selectedConf; @@ -126,10 +150,14 @@ public abstract class AbstractSettingFormSingleValue extends Form { final Object value; try { - value = confClass.getField(selectedSetting - .getSelectedKey(state)).get(config); - } catch (NoSuchFieldException | SecurityException | - IllegalAccessException | ClassCastException ex) { + final Field field = confClass.getDeclaredField(selectedSetting + .getSelectedKey(state)); + field.setAccessible(true); + value = field.get(config); + } catch (NoSuchFieldException | + SecurityException | + IllegalAccessException | + ClassCastException ex) { LOGGER.warn("Failed to read setting {} from configuration {}", selectedSetting.getSelectedKey(state), selectedConf.getSelectedKey(state)); @@ -142,33 +170,47 @@ public abstract class AbstractSettingFormSingleValue extends Form { } + /** + * {@link FormValidationListener} which checks if the value provided by the + * user can be converted into the type of the setting. + * + */ private class ValidationListener implements FormValidationListener { @Override - public void validate(final FormSectionEvent event) throws - FormProcessException { + public void validate(final FormSectionEvent event) + throws FormProcessException { + final FormData data = event.getFormData(); + final PageState state = event.getPageState(); - final String valueData = data.getString(VALUE_FIELD); - if (Strings.isBlank(valueData)) { - data.addError(VALUE_FIELD, - new GlobalizedMessage( - "ui.admin.configuration.setting.error.blank", - ADMIN_BUNDLE)); - } - try { - final T value = convertValue(valueData); - LOGGER.debug("New value {} is a valid BigDecimal.", value); - } catch (NumberFormatException ex) { - data.addError(VALUE_FIELD, - new GlobalizedMessage( - "ui.admin.configuration.setting.error.not_a_bigdecimal", - ADMIN_BUNDLE)); + if (saveCancelSection.getSaveButton().isSelected(state)) { + final String valueData = data.getString(VALUE_FIELD); + if (Strings.isBlank(valueData)) { + data.addError(VALUE_FIELD, + new GlobalizedMessage( + "ui.admin.configuration.setting.error.blank", + ADMIN_BUNDLE)); + } + try { + final T value = convertValue(valueData); + LOGGER.debug("New value {} is a valid BigDecimal.", value); + } catch (NumberFormatException ex) { + data.addError( + VALUE_FIELD, + new GlobalizedMessage( + "ui.admin.configuration.setting.error.incorrect_format", + ADMIN_BUNDLE)); + } } } } + /** + * {@link FormProcessListener} to store the new value of the setting + * in the database. + */ private class ProcessListener implements FormProcessListener { private final ConfigurationTab configurationTab; @@ -189,58 +231,75 @@ public abstract class AbstractSettingFormSingleValue extends Form { throws FormProcessException { final PageState state = event.getPageState(); - final FormData data = event.getFormData(); - final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); - final Class confClass; - try { - confClass = Class - .forName(selectedConf.getSelectedKey(state)); - } catch (ClassNotFoundException ex) { - throw new UncheckedWrapperException(ex); + if (saveCancelSection.getSaveButton().isSelected(state)) { + final FormData data = event.getFormData(); + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + + final Class confClass; + try { + confClass = Class + .forName(selectedConf.getSelectedKey(state)); + } catch (ClassNotFoundException ex) { + throw new UncheckedWrapperException(ex); + } + + final ConfigurationManager confManager = cdiUtil.findBean( + ConfigurationManager.class); + final String settingName = selectedSetting.getSelectedKey(state); + + final Object config = confManager.findConfiguration(confClass); + + final Field field; + try { + field = confClass.getDeclaredField(settingName); + field.setAccessible(true); + } catch (NoSuchFieldException | SecurityException ex) { + LOGGER.error("Failed to retrieve field \"{}\" " + + "from configuration class \"{}\".", + settingName, + confClass.getName()); + LOGGER.error(ex); + throw new FormProcessException( + String.format( + "Failed to retrieve field \"%s\" " + + "from configuration class \"%s\".", + settingName, + confClass.getName()), + new GlobalizedMessage( + "ui.admin.configuration.setting.failed_to_set_value", + ADMIN_BUNDLE), + ex); + } + + final String valueData = data.getString(VALUE_FIELD); + + final T value = convertValue(valueData); + + try { + field.set(config, value); + confManager.saveConfiguration(config); + configurationTab.hideSettingForms(state); + } catch (IllegalArgumentException | IllegalAccessException ex) { + LOGGER.error("Failed to change value of field \"{}\" " + + "of configuration class \"{}\".", + settingName, + confClass.getName()); + LOGGER.error(ex); + throw new FormProcessException( + String.format( + "Failed to change value of field \"%s\" " + + "of configuration class \"%s\".", + settingName, + confClass.getName()), + new GlobalizedMessage( + "ui.admin.configuration.setting.failed_to_set_value", + ADMIN_BUNDLE), + ex); + } } - final ConfigurationManager confManager = cdiUtil.findBean( - ConfigurationManager.class); - final String settingName = selectedSetting.getSelectedKey(state); - - final Object config = confManager.findConfiguration(confClass); - - final Field field; - try { - field = confClass.getField(settingName); - } catch (NoSuchFieldException | SecurityException ex) { - throw new FormProcessException( - String.format( - "Failed to retrieve field \"%s\" " - + "from configuration class \"%s\".", - settingName, - confClass.getName()), - new GlobalizedMessage( - "ui.admin.configuration.setting.failed_to_set_value", - ADMIN_BUNDLE), - ex); - } - - final String valueData = data.getString(VALUE_FIELD); - - final T value = convertValue(valueData); - - try { - field.set(config, value); - configurationTab.hideSettingForms(state); - } catch (IllegalArgumentException | IllegalAccessException ex) { - throw new FormProcessException( - String.format( - "Failed to change value of field \"%s\" " - + "of configuration class \"%s\".", - settingName, - confClass.getName()), - new GlobalizedMessage( - "ui.admin.configuration.setting.failed_to_set_value", - ADMIN_BUNDLE), - ex); - } + configurationTab.hideSettingForms(state); } } diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/ConfigurationTab.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/ConfigurationTab.java index 42a599c2e..3f0307cef 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/ConfigurationTab.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/ConfigurationTab.java @@ -31,10 +31,18 @@ import com.arsdigita.bebop.form.TextField; import com.arsdigita.bebop.parameters.StringParameter; import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.toolbox.ui.LayoutPanel; +import com.arsdigita.util.UncheckedWrapperException; + +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.configuration.ConfigurationInfo; +import org.libreccm.configuration.ConfigurationManager; +import org.libreccm.l10n.GlobalizationHelper; import static com.arsdigita.ui.admin.AdminUiConstants.*; /** + * Tab for the admin application containing the UI to manage the settings in the + * various configuration classes. * * @author Jens Pelzetter */ @@ -42,31 +50,86 @@ public class ConfigurationTab extends LayoutPanel { private static final String CONF_CLASSES_FILTER = "confClassesFilter"; + /** + * Parameter for the selected configuration. + */ private final StringParameter selectedConfParam; private final ParameterSingleSelectionModel selectedConf; + /** + * Parameter for the selected setting. + */ private final StringParameter selectedSettingParam; private final ParameterSingleSelectionModel selectedSetting; + /** + * Parameter for the selected value of multi-value settings. + */ private final StringParameter selectedValueParam; private final ParameterSingleSelectionModel selectedValue; + /** + * Heading of the table of configurations. + */ private final Label confClassesFilterHeading; + /** + * Form for filtering the table of configurations. + */ private final Form confClassesFilterForm; + /** + * The table which lists all available configurations. + */ private final ConfigurationsTable configurationsTable; + /** + * Link to go back to the listing of configurations. + */ private final ActionLink configurationBackLink; + /** + * Heading for the list of settings of a configuration. + */ + private final Label configurationHeading; + /** + * The table which lists a settings of configuration. + */ private final ConfigurationTable configurationTable; + /** + * The form for editing a setting of the type {@code boolean}. + */ private final SettingFormBoolean settingFormBoolean; + /** + * The form for editing a setting of the type {@code long}. + */ private final SettingFormLong settingFormLong; + /** + * The form for editing a setting of the type {@code double}. + */ private final SettingFormDouble settingFormDouble; + /** + * The form for editing a setting of the type {@code BigDecimal}. + */ private final SettingFormBigDecimal settingFormBigDecimal; + /** + * The form for editing a setting of the type {@code String}. + */ private final SettingFormString settingFormString; + /** + * The form for editing a setting of the type {@code LocalizedString}. + */ private final SettingEditorLocalizedString settingEditorLocalizedString; + /** + * The form for editing a setting of the type {@code List}. + */ private final SettingEditorStringList settingEditorStringList; + /** + * The form for editing a setting of the type {@code Set}. + */ private final SettingEditorEnum settingEditorEnum; + /** + * Initialises the parameters, widgets and forms. + */ public ConfigurationTab() { super(); @@ -77,7 +140,7 @@ public class ConfigurationTab extends LayoutPanel { selectedSettingParam = new StringParameter("selectedSetting"); selectedSetting = new ParameterSingleSelectionModel<>( - selectedSettingParam); + selectedSettingParam); selectedValueParam = new StringParameter("selectedValue"); selectedValue = new ParameterSingleSelectionModel<>(selectedValueParam); @@ -85,15 +148,15 @@ public class ConfigurationTab extends LayoutPanel { final SegmentedPanel left = new SegmentedPanel(); confClassesFilterHeading = new Label(new GlobalizedMessage( - "ui.admin.configuration.classes.filter.heading", ADMIN_BUNDLE)); + "ui.admin.configuration.classes.filter.heading", ADMIN_BUNDLE)); confClassesFilterForm = new Form("confClassesForm"); final TextField confClassesFilter = new TextField(CONF_CLASSES_FILTER); confClassesFilterForm.add(confClassesFilter); confClassesFilterForm.add(new Submit(new GlobalizedMessage( - "ui.admin.configuration.classes.filter.submit", ADMIN_BUNDLE))); + "ui.admin.configuration.classes.filter.submit", ADMIN_BUNDLE))); final ActionLink clearLink = new ActionLink(new GlobalizedMessage( - "ui.admin.configuration.classes.filter.clear", ADMIN_BUNDLE)); + "ui.admin.configuration.classes.filter.clear", ADMIN_BUNDLE)); clearLink.addActionListener(e -> { final PageState state = e.getPageState(); confClassesFilter.setValue(state, null); @@ -105,17 +168,48 @@ public class ConfigurationTab extends LayoutPanel { final BoxPanel body = new BoxPanel(BoxPanel.VERTICAL); configurationsTable = new ConfigurationsTable( - this, selectedConf, confClassesFilter); + this, selectedConf, confClassesFilter); body.add(configurationsTable); configurationBackLink = new ActionLink(new GlobalizedMessage( - "ui.admin.configuration.back_to_configurations", - ADMIN_BUNDLE)); + "ui.admin.configuration.back_to_configurations", + ADMIN_BUNDLE)); configurationBackLink.addActionListener(e -> { final PageState state = e.getPageState(); hideConfiguration(state); }); body.add(configurationBackLink); + configurationHeading = new Label(e -> { + //This print listener includes the (localised title) of the selected + //configuration in the heading + final PageState state = e.getPageState(); + + final Class confClass; + try { + confClass = Class.forName(selectedConf.getSelectedKey(state)); + } catch (ClassNotFoundException ex) { + throw new UncheckedWrapperException( + String.format("Configuration class \"%s\" not found.", + selectedConf.getSelectedKey(state)), + ex); + } + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final ConfigurationManager confManager = cdiUtil.findBean( + ConfigurationManager.class); + final ConfigurationInfo confInfo = confManager.getConfigurationInfo( + confClass); + final GlobalizationHelper globalizationHelper = cdiUtil.findBean( + GlobalizationHelper.class); + final Label target = (Label) e.getTarget(); + final String confTitle = confInfo.getTitle(globalizationHelper + .getNegotiatedLocale()); + target.setLabel(new GlobalizedMessage( + "ui.admin.configuration.editing_configuration", + ADMIN_BUNDLE, + new String[]{confTitle})); + }); + configurationHeading.setClassAttr("heading"); + body.add(configurationHeading); configurationTable = new ConfigurationTable(this, selectedConf, selectedSetting); @@ -147,20 +241,27 @@ public class ConfigurationTab extends LayoutPanel { body.add(settingFormString); settingEditorLocalizedString = new SettingEditorLocalizedString( - this, selectedConf, selectedSetting, selectedValue); + this, selectedConf, selectedSetting, selectedValue); body.add(settingEditorLocalizedString); settingEditorStringList = new SettingEditorStringList( - this, selectedConf, selectedSetting, selectedValue); + this, selectedConf, selectedSetting, selectedValue); body.add(settingEditorStringList); settingEditorEnum = new SettingEditorEnum( - this, selectedConf, selectedSetting, selectedValue); + this, selectedConf, selectedSetting, selectedValue); body.add(settingEditorEnum); setBody(body); } + /** + * Registers all forms and widgets in the page for visibility management and + * registers all parameters. The method is called by Bebop when the tab is + * rendered. + * + * @param page The page which this tab is part of. + */ @Override public void register(final Page page) { super.register(page); @@ -174,6 +275,7 @@ public class ConfigurationTab extends LayoutPanel { page.setVisibleDefault(configurationsTable, true); page.setVisibleDefault(configurationBackLink, false); + page.setVisibleDefault(configurationHeading, false); page.setVisibleDefault(configurationTable, false); page.setVisibleDefault(settingFormBoolean, false); @@ -186,6 +288,12 @@ public class ConfigurationTab extends LayoutPanel { page.setVisibleDefault(settingEditorEnum, false); } + /** + * Shows the {@link #configurationsTable} and hides all other widgets and + * forms. + * + * @param state The current {@link PageState}. + */ protected void showConfigurationsTable(final PageState state) { confClassesFilterHeading.setVisible(state, true); confClassesFilterForm.setVisible(state, true); @@ -203,22 +311,41 @@ public class ConfigurationTab extends LayoutPanel { settingEditorEnum.setVisible(state, false); } + /** + * Hides the {@link #configurationsTable} and its supporting widgets. + * + * @param state The current {@link PageState}. + */ protected void hideConfigurationsTable(final PageState state) { confClassesFilterHeading.setVisible(state, false); confClassesFilterForm.setVisible(state, false); configurationsTable.setVisible(state, false); } + /** + * Shows the {@link #configurationTable} which lists all settings of a + * configuration. + * + * @param state The current {@link PageState}. + */ protected void showConfiguration(final PageState state) { hideConfigurationsTable(state); hideSettingForms(state); configurationBackLink.setVisible(state, true); + configurationHeading.setVisible(state, true); configurationTable.setVisible(state, true); } + /** + * Hides the configuration table and resets the {@link #selectedConf} + * parameter. + * + * @param state The current {@link PageState}. + */ protected void hideConfiguration(final PageState state) { configurationBackLink.setVisible(state, false); + configurationHeading.setVisible(state, false); configurationTable.setVisible(state, false); selectedConf.clearSelection(state); @@ -226,11 +353,18 @@ public class ConfigurationTab extends LayoutPanel { showConfigurationsTable(state); } + /** + * Shows the {@link #settingFormBigDecimal}. + * + * @param state The current {@link PageState}. + */ protected void showBigDecimalSettingForm(final PageState state) { confClassesFilterHeading.setVisible(state, false); confClassesFilterForm.setVisible(state, false); configurationsTable.setVisible(state, false); + configurationBackLink.setVisible(state, false); + configurationHeading.setVisible(state, false); configurationTable.setVisible(state, false); settingFormBoolean.setVisible(state, false); @@ -243,11 +377,18 @@ public class ConfigurationTab extends LayoutPanel { settingEditorEnum.setVisible(state, false); } + /** + * Shows the {@link #settingFormBoolean}. + * + * @param state The current {@link PageState}. + */ protected void showBooleanSettingForm(final PageState state) { confClassesFilterHeading.setVisible(state, false); confClassesFilterForm.setVisible(state, false); configurationsTable.setVisible(state, false); + configurationBackLink.setVisible(state, false); + configurationHeading.setVisible(state, false); configurationTable.setVisible(state, false); settingFormBoolean.setVisible(state, true); @@ -260,11 +401,18 @@ public class ConfigurationTab extends LayoutPanel { settingEditorEnum.setVisible(state, false); } + /** + * Shows the {@link #settingFormDouble}. + * + * @param state The current {@link PageState}. + */ protected void showDoubleSettingForm(final PageState state) { confClassesFilterHeading.setVisible(state, false); confClassesFilterForm.setVisible(state, false); configurationsTable.setVisible(state, false); + configurationBackLink.setVisible(state, false); + configurationHeading.setVisible(state, false); configurationTable.setVisible(state, false); settingFormBoolean.setVisible(state, false); @@ -277,11 +425,18 @@ public class ConfigurationTab extends LayoutPanel { settingEditorEnum.setVisible(state, false); } + /** + * Shows the {@link #settingEditorEnum}. + * + * @param state The current {@link PageState}. + */ protected void showEnumSettingForm(final PageState state) { confClassesFilterHeading.setVisible(state, false); confClassesFilterForm.setVisible(state, false); configurationsTable.setVisible(state, false); + configurationBackLink.setVisible(state, false); + configurationHeading.setVisible(state, false); configurationTable.setVisible(state, false); settingFormBoolean.setVisible(state, false); @@ -294,11 +449,18 @@ public class ConfigurationTab extends LayoutPanel { settingEditorEnum.setVisible(state, true); } + /** + * Show the {@link #settingEditorLocalizedString}. + * + * @param state The current {@link PageState}. + */ protected void showLocalizedStringSettingForm(final PageState state) { confClassesFilterHeading.setVisible(state, false); confClassesFilterForm.setVisible(state, false); configurationsTable.setVisible(state, false); + configurationBackLink.setVisible(state, false); + configurationHeading.setVisible(state, false); configurationTable.setVisible(state, false); settingFormBoolean.setVisible(state, false); @@ -311,11 +473,18 @@ public class ConfigurationTab extends LayoutPanel { settingEditorEnum.setVisible(state, false); } + /** + * Shows the {@link #settingFormLong}. + * + * @param state The current {@link PageState}. + */ protected void showLongSettingForm(final PageState state) { confClassesFilterHeading.setVisible(state, false); confClassesFilterForm.setVisible(state, false); configurationsTable.setVisible(state, false); + configurationBackLink.setVisible(state, false); + configurationHeading.setVisible(state, false); configurationTable.setVisible(state, false); settingFormBoolean.setVisible(state, false); @@ -328,11 +497,18 @@ public class ConfigurationTab extends LayoutPanel { settingEditorEnum.setVisible(state, false); } + /** + * Shows the {@link #settingEditorStringList}. + * + * @param state The current {@link PageState}. + */ protected void showStringListSettingForm(final PageState state) { confClassesFilterHeading.setVisible(state, false); confClassesFilterForm.setVisible(state, false); configurationsTable.setVisible(state, false); + configurationBackLink.setVisible(state, false); + configurationHeading.setVisible(state, false); configurationTable.setVisible(state, false); settingFormBoolean.setVisible(state, false); @@ -345,11 +521,18 @@ public class ConfigurationTab extends LayoutPanel { settingEditorEnum.setVisible(state, false); } + /** + * Shows the {@link #settingFormString}. + * + * @param state The current {@link PageState}. + */ protected void showStringSettingForm(final PageState state) { confClassesFilterHeading.setVisible(state, false); confClassesFilterForm.setVisible(state, false); configurationsTable.setVisible(state, false); + configurationBackLink.setVisible(state, false); + configurationHeading.setVisible(state, false); configurationTable.setVisible(state, false); settingFormBoolean.setVisible(state, false); @@ -362,12 +545,20 @@ public class ConfigurationTab extends LayoutPanel { settingEditorEnum.setVisible(state, false); } + /** + * Hides all settings forms/editors and resets the {@link #selectedSetting} + * and {@link #selectedValue} parameters. + * + * @param state The current {@link PageState}. + */ protected void hideSettingForms(final PageState state) { confClassesFilterHeading.setVisible(state, false); confClassesFilterForm.setVisible(state, false); configurationsTable.setVisible(state, false); - configurationTable.setVisible(state, false); + configurationBackLink.setVisible(state, true); + configurationHeading.setVisible(state, true); + configurationTable.setVisible(state, true); settingFormBoolean.setVisible(state, false); settingFormLong.setVisible(state, false); diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/ConfigurationTable.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/ConfigurationTable.java index f82657002..9168a9f22 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/ConfigurationTable.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/ConfigurationTable.java @@ -34,6 +34,7 @@ import com.arsdigita.bebop.table.TableModelBuilder; import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.util.LockableImpl; import com.arsdigita.util.UncheckedWrapperException; + import java.lang.reflect.Field; import org.apache.logging.log4j.LogManager; @@ -43,19 +44,27 @@ import org.libreccm.configuration.ConfigurationManager; import org.libreccm.configuration.SettingInfo; import org.libreccm.configuration.SettingManager; import org.libreccm.l10n.GlobalizationHelper; +import org.libreccm.l10n.LocalizedString; +import java.util.ArrayList; import java.util.List; +import java.util.Objects; +import java.util.Set; import static com.arsdigita.ui.admin.AdminUiConstants.*; /** + * This table lists all settings of a configuration class. The table shows the + * current value and the description of each setting. If there is localised + * label for the setting this label is used, otherwise the name of the setting + * is used. * * @author Jens Pelzetter */ public class ConfigurationTable extends Table { private static final Logger LOGGER = LogManager.getLogger( - ConfigurationTable.class); + ConfigurationTable.class); private static final int COL_SETTING_LABEL = 0; private static final int COL_SETTING_VALUE = 1; @@ -66,9 +75,9 @@ public class ConfigurationTable extends Table { private ParameterSingleSelectionModel selectedSetting; public ConfigurationTable( - final ConfigurationTab configurationTab, - final ParameterSingleSelectionModel selectedConf, - final ParameterSingleSelectionModel selectedSetting) { + final ConfigurationTab configurationTab, + final ParameterSingleSelectionModel selectedConf, + final ParameterSingleSelectionModel selectedSetting) { super(); @@ -78,32 +87,32 @@ public class ConfigurationTable extends Table { this.selectedSetting = selectedSetting; setEmptyView(new Label(new GlobalizedMessage( - "ui.admin.configuration.settings.none", ADMIN_BUNDLE))); + "ui.admin.configuration.settings.none", ADMIN_BUNDLE))); final TableColumnModel columnModel = getColumnModel(); columnModel.add(new TableColumn( - COL_SETTING_LABEL, - new Label(new GlobalizedMessage( - "ui.admin.configuration.settings.table.col_setting_label.header", - ADMIN_BUNDLE)))); + COL_SETTING_LABEL, + new Label(new GlobalizedMessage( + "ui.admin.configuration.settings.table.col_setting_label.header", + ADMIN_BUNDLE)))); columnModel.add(new TableColumn( - COL_SETTING_VALUE, - new Label(new GlobalizedMessage( - "ui.admin.configuration.settings.table.col_setting_value.header", - ADMIN_BUNDLE)))); + COL_SETTING_VALUE, + new Label(new GlobalizedMessage( + "ui.admin.configuration.settings.table.col_setting_value.header", + ADMIN_BUNDLE)))); columnModel.add(new TableColumn( - COL_SETTING_DESC, - new Label(new GlobalizedMessage( - "ui.admin.configuration.settings.table.col_setting_desc.header", - ADMIN_BUNDLE)))); + COL_SETTING_DESC, + new Label(new GlobalizedMessage( + "ui.admin.configuration.settings.table.col_setting_desc.header", + ADMIN_BUNDLE)))); columnModel.add(new TableColumn( - COL_EDIT_SETTING, - new Label(new GlobalizedMessage( - "ui.admin.configuration.settings.table.col_edit_setting.header", - ADMIN_BUNDLE)))); + COL_EDIT_SETTING, + new Label(new GlobalizedMessage( + "ui.admin.configuration.settings.table.col_edit_setting.header", + ADMIN_BUNDLE)))); columnModel.get(COL_EDIT_SETTING).setCellRenderer( - new TableCellRenderer() { + new TableCellRenderer() { @Override public Component getComponent(final Table table, @@ -131,32 +140,41 @@ public class ConfigurationTable extends Table { switch (getTypeOfSelectedSetting(state)) { case "boolean": LOGGER.debug("Setting is of type boolean"); + configurationTab.showBooleanSettingForm(state); break; case "long": LOGGER.debug("Setting is of type long"); + configurationTab.showLongSettingForm(state); break; case "double": LOGGER.debug("Setting is of type double"); + configurationTab.showDoubleSettingForm(state); break; case "java.math.BigDecimal": LOGGER.debug("Setting is of type BigDecimal"); + configurationTab.showBigDecimalSettingForm(state); break; case "org.libreccm.l10n.LocalizedString": LOGGER.debug("Setting is of type LocalizedString"); + configurationTab.showLocalizedStringSettingForm( + state); break; case "java.lang.String": LOGGER.debug("Setting is of type String"); + configurationTab.showStringSettingForm(state); break; case "java.util.Set": LOGGER.debug("Setting is of type Enum"); + configurationTab.showEnumSettingForm(state); break; case "java.util.List": LOGGER.debug("Setting is of type List"); + configurationTab.showStringListSettingForm(state); break; default: throw new IllegalArgumentException(String.format( - "Unknown setting type \"%s\".", - getTypeOfSelectedSetting(state))); + "Unknown setting type \"%s\".", + getTypeOfSelectedSetting(state))); } } @@ -180,28 +198,28 @@ public class ConfigurationTable extends Table { LOGGER.error("Configuration class '{}' not found.", selectedConf.getSelectedKey(state)); throw new UncheckedWrapperException(String.format( - "Configuration class '%s not found'", - selectedConf.getSelectedKey(state)), ex); + "Configuration class '%s not found'", + selectedConf.getSelectedKey(state)), ex); } final SettingManager settingManager = CdiUtil.createCdiUtil().findBean( - SettingManager.class); + SettingManager.class); final SettingInfo info = settingManager.getSettingInfo(confClass, selectedSetting. getSelectedKey( - state)); + state)); return info.getValueType(); } private class ConfigurationTableModelBuilder - extends LockableImpl implements TableModelBuilder { + extends LockableImpl implements TableModelBuilder { @Override public TableModel makeModel(final Table table, final PageState state) { final ConfigurationManager confManager = CdiUtil.createCdiUtil() - .findBean(ConfigurationManager.class); + .findBean(ConfigurationManager.class); final Class confClass; try { confClass = Class.forName(selectedConf.getSelectedKey(state)); @@ -209,12 +227,12 @@ public class ConfigurationTable extends Table { LOGGER.error("Configuration class '{}' not found.", selectedConf.getSelectedKey(state)); throw new UncheckedWrapperException(String.format( - "Configuration class '%s not found'", - selectedConf.getSelectedKey(state)), ex); + "Configuration class '%s not found'", + selectedConf.getSelectedKey(state)), ex); } final Object configuration = confManager - .findConfiguration(confClass); + .findConfiguration(confClass); return new ConfigurationTableModel(configuration, state); } @@ -259,43 +277,73 @@ public class ConfigurationTable extends Table { public Object getElementAt(final int columnIndex) { final String setting = settings.get(index); final SettingInfo settingInfo = settingManager.getSettingInfo( - configuration.getClass(), setting); + configuration.getClass(), setting); switch (columnIndex) { case COL_SETTING_LABEL: return settingInfo.getLabel(globalizationHelper - .getNegotiatedLocale()); + .getNegotiatedLocale()); case COL_SETTING_VALUE: { try { final Field field = configuration.getClass(). - getDeclaredField(setting); + getDeclaredField(setting); field.setAccessible(true); - return field.get(configuration); -// return configuration.getClass(). -// getDeclaredField(setting).get(configuration); + return buildValueColumn(settingInfo, + field.get(configuration)); } catch (NoSuchFieldException | SecurityException | IllegalAccessException ex) { LOGGER.error("Failed to read value from configuration.", ex); return new Label(new GlobalizedMessage( - "ui.admin.configuration.settings.read_error", - ADMIN_BUNDLE)); + "ui.admin.configuration.settings.read_error", + ADMIN_BUNDLE)); } } case COL_SETTING_DESC: return settingInfo.getDescription(globalizationHelper - .getNegotiatedLocale()); + .getNegotiatedLocale()); case COL_EDIT_SETTING: return new Label(new GlobalizedMessage( - "ui.admin.configuration.settings.edit", ADMIN_BUNDLE)); + "ui.admin.configuration.settings.edit", ADMIN_BUNDLE)); default: throw new IllegalArgumentException("Illegal column index"); } } + private String buildValueColumn(final SettingInfo settingInfo, + final Object settingValue) { + switch (settingInfo.getValueType()) { + case "java.util.List": { + @SuppressWarnings("unchecked") + final List value = (List) settingValue; + return String.join(", ", value); + } + case "java.util.Set": { + @SuppressWarnings("unchecked") + final Set value = (Set) settingValue; + return String.join(", ", value); + } + case "org.libreccm.l10n.LocalizedString": { + final LocalizedString value = (LocalizedString) settingValue; + final List entries = new ArrayList<>(); + value.getValues().entrySet().forEach(e -> { + entries.add(String.format("%s: %s", + e.getKey(), + e.getValue())); + }); + + return String.join("; ", entries); + } + default: { + return Objects.toString(settingValue); + } + } + } + @Override - public Object getKeyAt(final int columnIndex) { + public Object getKeyAt(final int columnIndex + ) { return settings.get(index); } diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/ConfigurationsTable.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/ConfigurationsTable.java index 243a2b2b4..945b382ae 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/ConfigurationsTable.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/ConfigurationsTable.java @@ -50,6 +50,10 @@ import java.util.stream.Collectors; import static com.arsdigita.ui.admin.AdminUiConstants.*; /** + * This table lists all available configuration classes together with their + * descriptions (if any). If there is localised title for the configuration this + * title is used, otherwise the fully qualified name of the configuration is + * used. * * @author Jens Pelzetter */ @@ -106,7 +110,7 @@ public class ConfigurationsTable extends Table { if (event.getColumn() == COL_TITLE) { final String confClassName = (String) event.getRowKey(); selectedConf.setSelectedKey(state, confClassName); - + configurationTab.showConfiguration(state); } } diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingEditorEnum.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingEditorEnum.java index 49f35d3b6..ee7e302fa 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingEditorEnum.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingEditorEnum.java @@ -18,7 +18,6 @@ */ package com.arsdigita.ui.admin.configuration; -import com.arsdigita.bebop.ActionLink; import com.arsdigita.bebop.BoxPanel; import com.arsdigita.bebop.Component; import com.arsdigita.bebop.ControlLink; @@ -46,7 +45,9 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.libreccm.cdi.utils.CdiUtil; import org.libreccm.configuration.ConfigurationManager; +import org.libreccm.configuration.EnumSetting; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -55,6 +56,10 @@ import java.util.Set; import static com.arsdigita.ui.admin.AdminUiConstants.*; /** + * Editor for {@link EnumSetting}s. The editor consists of the usual header (see + * {@link SettingFormHeader}) which is used by all setting forms/editors, a + * table which displays all current values together with links for editing and + * deleting the values and a form for adding and editing values. * * @author Jens Pelzetter */ @@ -85,15 +90,9 @@ public class SettingEditorEnum extends BoxPanel { this.selectedSetting = selectedSetting; this.selectedValue = selectedValue; - final ActionLink backLink = new ActionLink(new GlobalizedMessage( - "ui.admin.configuration.setting.localized_string.back", - ADMIN_BUNDLE)); - backLink.addActionListener(e -> { - configurationTab.hideSettingForms(e.getPageState()); - }); - add(backLink); - - add(new SettingFormHeader(selectedConf, selectedSetting)); + add(new SettingFormHeader(configurationTab, + selectedConf, + selectedSetting)); add(new ValuesTable()); @@ -194,10 +193,14 @@ public class SettingEditorEnum extends BoxPanel { final Set values; try { - values = (Set) confClass.getField( - selectedSetting.getSelectedKey(state)).get(config); - } catch (NoSuchFieldException | SecurityException | - IllegalAccessException | ClassCastException ex) { + final Field field = confClass.getDeclaredField( + selectedSetting.getSelectedKey(state)); + field.setAccessible(true); + values = (Set) field.get(config); + } catch (NoSuchFieldException | + SecurityException | + IllegalAccessException | + ClassCastException ex) { LOGGER.warn( "Failed to read setting {} from configuration {}", selectedSetting.getSelectedKey(state), @@ -274,14 +277,17 @@ public class SettingEditorEnum extends BoxPanel { final Object config = confManager.findConfiguration(confClass); try { @SuppressWarnings("unchecked") - final Set valuesSet = (Set) confClass.getField( - selectedSetting - .getSelectedKey(state)).get(config); + final Field field = confClass.getDeclaredField(selectedSetting + .getSelectedKey(state)); + field.setAccessible(true); + final Set valuesSet = (Set) field.get(config); values = new ArrayList<>(valuesSet); - } catch (NoSuchFieldException | SecurityException | - IllegalAccessException | ClassCastException ex) { + } catch (NoSuchFieldException | + SecurityException | + IllegalAccessException | + ClassCastException ex) { LOGGER.warn("Failed to read setting {} from configuration {}", selectedSetting.getSelectedKey(state), selectedConf.getSelectedKey(state)); @@ -378,18 +384,23 @@ public class SettingEditorEnum extends BoxPanel { final Set enumSetting; try { - final Object value = confClass.getField(selectedSetting - .getSelectedKey(state)).get(config); + final Field field = confClass.getDeclaredField( + selectedSetting.getSelectedKey(state)); + field.setAccessible(true); + final Object value = field.get(config); if (value == null) { enumSetting = new HashSet<>(); - confClass.getField(selectedSetting.getSelectedKey( - state)).set(config, enumSetting); + confClass.getDeclaredField(selectedSetting + .getSelectedKey(state)).set(config, + enumSetting); } else { enumSetting = (Set) value; } - } catch (NoSuchFieldException | SecurityException | - IllegalAccessException | ClassCastException ex) { + } catch (NoSuchFieldException | + SecurityException | + IllegalAccessException | + ClassCastException ex) { LOGGER.warn( "Failed to read setting {} from configuration {}", selectedSetting.getSelectedKey(state), @@ -411,6 +422,9 @@ public class SettingEditorEnum extends BoxPanel { } confManager.saveConfiguration(config); } + + selectedValue.clearSelection(state); + valueField.setValue(state, null); }); } diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingEditorLocalizedString.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingEditorLocalizedString.java index 48d4d7ee2..50b02e34d 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingEditorLocalizedString.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingEditorLocalizedString.java @@ -18,7 +18,6 @@ */ package com.arsdigita.ui.admin.configuration; -import com.arsdigita.bebop.ActionLink; import com.arsdigita.bebop.BoxPanel; import com.arsdigita.bebop.Component; import com.arsdigita.bebop.ControlLink; @@ -51,6 +50,7 @@ import org.libreccm.cdi.utils.CdiUtil; import org.libreccm.configuration.ConfigurationManager; import org.libreccm.l10n.LocalizedString; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -61,6 +61,10 @@ import java.util.TooManyListenersException; import static com.arsdigita.ui.admin.AdminUiConstants.*; /** + * Editor for {@link LocalizedStringSetting}s. The editor consists of the usual + * header (see {@link SettingFormHeader}) which is used by all setting + * forms/editors, a table which displays all current values together with links + * for editing and deleting the values and a form for adding and editing values. * * @author Jens Pelzetter */ @@ -92,15 +96,9 @@ public class SettingEditorLocalizedString extends BoxPanel { this.selectedSetting = selectedSetting; this.selectedValue = selectedValue; - final ActionLink backLink = new ActionLink(new GlobalizedMessage( - "ui.admin.configuration.setting.localized_string.back", - ADMIN_BUNDLE)); - backLink.addActionListener(e -> { - configurationTab.hideSettingForms(e.getPageState()); - }); - add(backLink); - - add(new SettingFormHeader(selectedConf, selectedSetting)); + add(new SettingFormHeader(configurationTab, + selectedConf, + selectedSetting)); add(new ValuesTable()); @@ -134,7 +132,7 @@ public class SettingEditorLocalizedString extends BoxPanel { columnModel.add(new TableColumn( COL_EDIT, new Label(new GlobalizedMessage( - "ui.admin.configuration.setting.localized_string.col_del", + "ui.admin.configuration.setting.localized_string.col_edit", ADMIN_BUNDLE)))); columnModel.add(new TableColumn( COL_DEL, @@ -212,19 +210,21 @@ public class SettingEditorLocalizedString extends BoxPanel { final LocalizedString localizedStr; try { - final Object value = confClass.getField( - selectedSetting - .getSelectedKey(state)).get(config); + final Field field = confClass.getDeclaredField( + selectedSetting.getSelectedKey(state)); + field.setAccessible(true); + final Object value = field.get(config); if (value == null) { localizedStr = new LocalizedString(); - confClass.getField(selectedSetting - .getSelectedKey( - state)).set(config, localizedStr); + field.set(config, localizedStr); } else { localizedStr = (LocalizedString) value; } - } catch (NoSuchFieldException | SecurityException | IllegalAccessException | ClassCastException ex) { + } catch (NoSuchFieldException | + SecurityException | + IllegalAccessException | + ClassCastException ex) { LOGGER.warn( "Failed to read setting {} from configuration {}", selectedSetting.getSelectedKey(state), @@ -294,16 +294,20 @@ public class SettingEditorLocalizedString extends BoxPanel { final Object config = confManager.findConfiguration(confClass); try { - value = (LocalizedString) confClass.getField(selectedSetting - .getSelectedKey(state)).get(config); + final Field field = confClass.getDeclaredField(selectedSetting + .getSelectedKey(state)); + field.setAccessible(true); + value = (LocalizedString) field.get(config); locales = new ArrayList<>(); locales.addAll(value.getAvailableLocales()); locales.sort((s1, s2) -> { return s1.toString().compareTo(s2.toString()); }); - } catch (NoSuchFieldException | SecurityException | - IllegalAccessException | ClassCastException ex) { + } catch (NoSuchFieldException | + SecurityException | + IllegalAccessException | + ClassCastException ex) { LOGGER.warn("Failed to read setting {} from configuration {}", selectedSetting.getSelectedKey(state), selectedConf.getSelectedKey(state)); @@ -391,10 +395,14 @@ public class SettingEditorLocalizedString extends BoxPanel { final LocalizedString value; try { - value = (LocalizedString) confClass.getField( - selectedSetting.getSelectedKey(state)).get( - config); - } catch (NoSuchFieldException | SecurityException | IllegalAccessException | ClassCastException ex) { + final Field field = confClass.getDeclaredField( + selectedSetting.getSelectedKey(state)); + field.setAccessible(true); + value = (LocalizedString) field.get(config); + } catch (NoSuchFieldException | + SecurityException | + IllegalAccessException | + ClassCastException ex) { LOGGER.warn( "Failed to read setting {} from configuration {}", selectedSetting.getSelectedKey(state), @@ -471,11 +479,12 @@ public class SettingEditorLocalizedString extends BoxPanel { confClass); try { + final Field field = confClass.getDeclaredField( + selectedSetting.getSelectedKey(state)); + field.setAccessible(true); final LocalizedString localizedStr - = (LocalizedString) confClass - .getField( - selectedSetting.getSelectedKey(state)).get( - config); + = (LocalizedString) field.get( + config); final String value = localizedStr.getValue(new Locale( selectedValue.getSelectedKey(state))); @@ -497,7 +506,9 @@ public class SettingEditorLocalizedString extends BoxPanel { addProcessListener(e -> { final PageState state = e.getPageState(); + if (saveCancelSection.getSaveButton().isSelected(state)) { + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); final Class confClass; @@ -516,18 +527,22 @@ public class SettingEditorLocalizedString extends BoxPanel { final LocalizedString localizedStr; try { - final Object value = confClass.getField(selectedSetting - .getSelectedKey(state)).get(config); + final Field field = confClass.getDeclaredField( + selectedSetting.getSelectedKey(state)); + field.setAccessible(true); + final Object value = field.get(config); if (value == null) { localizedStr = new LocalizedString(); - confClass.getField(selectedSetting.getSelectedKey( - state)).set(config, localizedStr); + + field.set(config, localizedStr); } else { localizedStr = (LocalizedString) value; } - } catch (NoSuchFieldException | SecurityException | - IllegalAccessException | ClassCastException ex) { + } catch (NoSuchFieldException | + SecurityException | + IllegalAccessException | + ClassCastException ex) { LOGGER.warn( "Failed to read setting {} from configuration {}", selectedSetting.getSelectedKey(state), @@ -545,6 +560,10 @@ public class SettingEditorLocalizedString extends BoxPanel { confManager.saveConfiguration(config); } + + selectedValue.clearSelection(state); + localeSelect.setValue(state, null); + localizedValue.setValue(state, null); }); } @@ -553,8 +572,6 @@ public class SettingEditorLocalizedString extends BoxPanel { if (super.isVisible(state)) { if (selectedValue.getSelectedKey(state) == null) { - return true; - } else { final ConfigurationManager confManager = CdiUtil .createCdiUtil() .findBean(ConfigurationManager.class); @@ -572,10 +589,14 @@ public class SettingEditorLocalizedString extends BoxPanel { final LocalizedString value; try { - value = (LocalizedString) confClass.getField( - selectedSetting.getSelectedKey(state)).get( - config); - } catch (NoSuchFieldException | SecurityException | IllegalAccessException | ClassCastException ex) { + final Field field = confClass.getDeclaredField( + selectedSetting.getSelectedKey(state)); + field.setAccessible(true); + value = (LocalizedString) field.get(config); + } catch (NoSuchFieldException | + SecurityException | + IllegalAccessException | + ClassCastException ex) { LOGGER.warn( "Failed to read setting {} from configuration {}", selectedSetting.getSelectedKey(state), @@ -597,6 +618,8 @@ public class SettingEditorLocalizedString extends BoxPanel { }); return !assignedLanguages.equals(supportedLanguages); + } else { + return true; } } else { diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingEditorStringList.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingEditorStringList.java index 0661c6870..6d1de5f80 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingEditorStringList.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingEditorStringList.java @@ -18,7 +18,6 @@ */ package com.arsdigita.ui.admin.configuration; -import com.arsdigita.bebop.ActionLink; import com.arsdigita.bebop.BoxPanel; import com.arsdigita.bebop.Component; import com.arsdigita.bebop.ControlLink; @@ -46,13 +45,19 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.libreccm.cdi.utils.CdiUtil; import org.libreccm.configuration.ConfigurationManager; +import org.libreccm.configuration.EnumSetting; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import static com.arsdigita.ui.admin.AdminUiConstants.*; /** + * Editor for {@link EnumSetting}s. The editor consists of the usual header (see + * {@link SettingFormHeader}) which is used by all setting forms/editors, a + * table which displays all current values together with links for moving, + * editing and deleting the values and a form for adding and editing values. * * @author Jens Pelzetter */ @@ -85,15 +90,9 @@ public class SettingEditorStringList extends BoxPanel { this.selectedSetting = selectedSetting; this.selectedValue = selectedValue; - final ActionLink backLink = new ActionLink(new GlobalizedMessage( - "ui.admin.configuration.setting.localized_string.back", - ADMIN_BUNDLE)); - backLink.addActionListener(e -> { - configurationTab.hideSettingForms(e.getPageState()); - }); - add(backLink); - - add(new SettingFormHeader(selectedConf, selectedSetting)); + add(new SettingFormHeader(configurationTab, + selectedConf, + selectedSetting)); add(new ValuesTable()); @@ -153,7 +152,7 @@ public class SettingEditorStringList extends BoxPanel { if (row > 0) { return new ControlLink((Component) value); } else { - return null; + return new Text(""); } } @@ -162,6 +161,7 @@ public class SettingEditorStringList extends BoxPanel { columnModel.get(COL_DOWN).setCellRenderer(new TableCellRenderer() { @Override + @SuppressWarnings("unchecked") public Component getComponent(final Table table, final PageState state, final Object value, @@ -188,9 +188,14 @@ public class SettingEditorStringList extends BoxPanel { final List values; try { - values = (List) confClass.getField( - selectedSetting.getSelectedKey(state)).get(config); - } catch (NoSuchFieldException | SecurityException | IllegalAccessException | ClassCastException ex) { + final Field field = confClass.getDeclaredField( + selectedSetting.getSelectedKey(state)); + field.setAccessible(true); + values = (List) field.get(config); + } catch (NoSuchFieldException | + SecurityException | + IllegalAccessException | + ClassCastException ex) { LOGGER.warn( "Failed to read setting {} from configuration {}", selectedSetting.getSelectedKey(state), @@ -203,7 +208,7 @@ public class SettingEditorStringList extends BoxPanel { if (row < values.size()) { return new ControlLink((Component) value); } else { - return null; + return new Text(""); } } @@ -251,6 +256,7 @@ public class SettingEditorStringList extends BoxPanel { addTableActionListener(new TableActionListener() { @Override + @SuppressWarnings("unchecked") public void cellSelected(final TableActionEvent event) { final PageState state = event.getPageState(); @@ -273,8 +279,10 @@ public class SettingEditorStringList extends BoxPanel { final List values; try { - values = (List) confClass.getField( - selectedSetting.getSelectedKey(state)).get(config); + final Field field = confClass.getDeclaredField( + selectedSetting.getSelectedKey(state)); + field.setAccessible(true); + values = (List) field.get(config); } catch (NoSuchFieldException | SecurityException | IllegalAccessException | ClassCastException ex) { LOGGER.warn( @@ -289,7 +297,8 @@ public class SettingEditorStringList extends BoxPanel { switch (event.getColumn()) { case COL_UP: { - final int currentIndex = (int) event.getRowKey(); + final int currentIndex = Integer.parseInt( + (String) event.getRowKey()); final int previousIndex = currentIndex - 1; final String currentValue = values.get(currentIndex); @@ -305,7 +314,8 @@ public class SettingEditorStringList extends BoxPanel { } case COL_DOWN: { - final int currentIndex = (int) event.getRowKey(); + final int currentIndex = Integer.parseInt( + (String) event.getRowKey()); final int nextIndex = currentIndex + 1; final String currentValue = values.get(currentIndex); @@ -324,7 +334,8 @@ public class SettingEditorStringList extends BoxPanel { break; } case COL_DEL: { - values.remove((int) event.getRowKey()); + values.remove(Integer.parseInt((String) event + .getRowKey())); confManager.saveConfiguration(config); @@ -365,6 +376,7 @@ public class SettingEditorStringList extends BoxPanel { private final List values; private int index = -1; + @SuppressWarnings("unchecked") public ValuesTableModel(final PageState state) { final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); @@ -383,10 +395,14 @@ public class SettingEditorStringList extends BoxPanel { final Object config = confManager.findConfiguration(confClass); try { - values = (List) confClass.getField(selectedSetting - .getSelectedKey(state)).get(config); - } catch (NoSuchFieldException | SecurityException | - IllegalAccessException | ClassCastException ex) { + final Field field = confClass.getDeclaredField(selectedSetting + .getSelectedKey(state)); + field.setAccessible(true); + values = (List) field.get(config); + } catch (NoSuchFieldException | + SecurityException | + IllegalAccessException | + ClassCastException ex) { LOGGER.warn("Failed to read setting {} from configuration {}", selectedSetting.getSelectedKey(state), selectedConf.getSelectedKey(state)); @@ -480,8 +496,10 @@ public class SettingEditorStringList extends BoxPanel { try { @SuppressWarnings("unchecked") - final List stringList = (List) confClass - .getField(selectedSetting.getSelectedKey(state)) + final Field field = confClass.getDeclaredField( + selectedSetting.getSelectedKey(state)); + field.setAccessible(true); + final List stringList = (List) field .get(config); final String str = stringList.get(Integer.parseInt( @@ -525,18 +543,21 @@ public class SettingEditorStringList extends BoxPanel { final List stringList; try { - final Object value = confClass.getField(selectedSetting - .getSelectedKey(state)).get(config); + final Field field = confClass.getDeclaredField( + selectedSetting.getSelectedKey(state)); + field.setAccessible(true); + final Object value = field.get(config); if (value == null) { stringList = new ArrayList<>(); - confClass.getField(selectedSetting.getSelectedKey( - state)).set(config, stringList); + field.set(config, stringList); } else { stringList = (List) value; } - } catch (NoSuchFieldException | SecurityException | - IllegalAccessException | ClassCastException ex) { + } catch (NoSuchFieldException | + SecurityException | + IllegalAccessException | + ClassCastException ex) { LOGGER.warn( "Failed to read setting {} from configuration {}", selectedSetting.getSelectedKey(state), @@ -559,6 +580,9 @@ public class SettingEditorStringList extends BoxPanel { confManager.saveConfiguration(config); } + + selectedValue.clearSelection(state); + valueField.setValue(state, null); }); } diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormBigDecimal.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormBigDecimal.java index 55ad60a8d..36df30144 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormBigDecimal.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormBigDecimal.java @@ -20,10 +20,14 @@ package com.arsdigita.ui.admin.configuration; import com.arsdigita.bebop.ParameterSingleSelectionModel; +import org.libreccm.configuration.BigDecimalSetting; + import java.math.BigDecimal; /** - * + * A subclass of {@link AbstractSettingFormSingleValue} for editing the value + * of a {@link BigDecimalSetting}. + * * @author Jens Pelzetter */ public class SettingFormBigDecimal diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormBoolean.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormBoolean.java index 98a34a7b1..9fa5cfe5b 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormBoolean.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormBoolean.java @@ -41,7 +41,9 @@ import org.libreccm.configuration.ConfigurationManager; import static com.arsdigita.ui.admin.AdminUiConstants.*; /** - * + * A subclass of {@link AbstractSettingFormSingleValue} for editing the value + * of a {@code boolean}. + * * @author Jens Pelzetter */ public class SettingFormBoolean extends Form { @@ -59,7 +61,9 @@ public class SettingFormBoolean extends Form { super("settingFormBoolean", new BoxPanel(BoxPanel.VERTICAL)); - add(new SettingFormHeader(selectedConf, selectedSetting)); + add(new SettingFormHeader(configurationTab, + selectedConf, + selectedSetting)); add(new SettingFormCurrentValuePanel(selectedConf, selectedSetting)); @@ -70,6 +74,7 @@ public class SettingFormBoolean extends Form { new Label(new GlobalizedMessage( "ui.admin.configuration.setting.edit.new_value", ADMIN_BUNDLE)))); + add(valueFieldGroup); final SaveCancelSection saveCancelSection = new SaveCancelSection(); add(saveCancelSection); @@ -93,10 +98,14 @@ public class SettingFormBoolean extends Form { final Boolean value; try { - value = (Boolean) confClass.getField(selectedSetting - .getSelectedKey(state)).get(config); - } catch (NoSuchFieldException | SecurityException | - IllegalAccessException | ClassCastException ex) { + final Field field = confClass.getDeclaredField(selectedSetting + .getSelectedKey(state)); + field.setAccessible(true); + value = (Boolean) field.get(config); + } catch (NoSuchFieldException | + SecurityException | + IllegalAccessException | + ClassCastException ex) { LOGGER.warn("Failed to read setting {} from configuration {}", selectedSetting.getSelectedKey(state), selectedConf.getSelectedKey(state)); @@ -111,63 +120,72 @@ public class SettingFormBoolean extends Form { addProcessListener(e -> { final PageState state = e.getPageState(); - final FormData data = e.getFormData(); - final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + if (saveCancelSection.getSaveButton().isSelected(state)) { + final FormData data = e.getFormData(); + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); - final Class confClass; - try { - confClass = Class - .forName(selectedConf.getSelectedKey(state)); - } catch (ClassNotFoundException ex) { - throw new UncheckedWrapperException(ex); - } + final Class confClass; + try { + confClass = Class + .forName(selectedConf.getSelectedKey(state)); + } catch (ClassNotFoundException ex) { + throw new UncheckedWrapperException(ex); + } - final ConfigurationManager confManager = cdiUtil.findBean( - ConfigurationManager.class); - final String settingName = selectedSetting.getSelectedKey(state); + final ConfigurationManager confManager = cdiUtil.findBean( + ConfigurationManager.class); + final String settingName = selectedSetting.getSelectedKey(state); - final Object config = confManager.findConfiguration(confClass); + final Object config = confManager.findConfiguration(confClass); - final Field field; - try { - field = confClass.getField(settingName); - } catch (NoSuchFieldException | SecurityException ex) { - throw new FormProcessException( - String.format( - "Failed to retrieve field \"%s\" " - + "from configuration class \"%s\".", - settingName, - confClass.getName()), - new GlobalizedMessage( - "ui.admin.configuration.setting.failed_to_set_value", - ADMIN_BUNDLE), - ex); - } + final Field field; + try { + field = confClass.getDeclaredField(settingName); + field.setAccessible(true); + } catch (NoSuchFieldException | + SecurityException ex) { + throw new FormProcessException( + String.format( + "Failed to retrieve field \"%s\" " + + "from configuration class \"%s\".", + settingName, + confClass.getName()), + new GlobalizedMessage( + "ui.admin.configuration.setting.failed_to_set_value", + ADMIN_BUNDLE), + ex); + } - try { - final String[] valueData = (String[]) data. - get(VALUE_FIELD_GROUP); - if (valueData != null && valueData.length > 0) { - if (VALUE_FIELD.equals(valueData[0])) { - field.set(config, Boolean.TRUE); + try { + final String[] valueData = (String[]) data. + get(VALUE_FIELD_GROUP); + if (valueData != null && valueData.length > 0) { + if (VALUE_FIELD.equals(valueData[0])) { + field.set(config, Boolean.TRUE); + } else { + field.set(config, Boolean.FALSE); + } } else { field.set(config, Boolean.FALSE); } + confManager.saveConfiguration(config); configurationTab.hideSettingForms(state); + } catch (IllegalArgumentException | IllegalAccessException ex) { + LOGGER.error(ex); + throw new FormProcessException( + String.format( + "Failed to change value of field \"%s\" " + + "of configuration class \"%s\".", + settingName, + confClass.getName()), + new GlobalizedMessage( + "ui.admin.configuration.setting.failed_to_set_value", + ADMIN_BUNDLE), + ex); } - } catch (IllegalArgumentException | IllegalAccessException ex) { - throw new FormProcessException( - String.format( - "Failed to change value of field \"%s\" " - + "of configuration class \"%s\".", - settingName, - confClass.getName()), - new GlobalizedMessage( - "ui.admin.configuration.setting.failed_to_set_value", - ADMIN_BUNDLE), - ex); } + configurationTab.hideSettingForms(state); }); } diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormCurrentValuePanel.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormCurrentValuePanel.java index ae7a4465e..92e53ccb1 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormCurrentValuePanel.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormCurrentValuePanel.java @@ -25,31 +25,36 @@ import com.arsdigita.bebop.ParameterSingleSelectionModel; import com.arsdigita.bebop.Text; import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.util.UncheckedWrapperException; + import java.util.Objects; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.libreccm.cdi.utils.CdiUtil; import org.libreccm.configuration.ConfigurationManager; +import java.lang.reflect.Field; + import static com.arsdigita.ui.admin.AdminUiConstants.*; /** - * + * A panel which show the current value of a (single value) setting. + * * @author Jens Pelzetter */ public class SettingFormCurrentValuePanel extends GridPanel { private final static Logger LOGGER = LogManager.getLogger( - SettingFormCurrentValuePanel.class); + SettingFormCurrentValuePanel.class); public SettingFormCurrentValuePanel( - final ParameterSingleSelectionModel selectedConf, - final ParameterSingleSelectionModel selectedSetting) { + final ParameterSingleSelectionModel selectedConf, + final ParameterSingleSelectionModel selectedSetting) { super(2); add(new Label(new GlobalizedMessage( - "ui.admin.configuration.setting.edit.current_value", - ADMIN_BUNDLE))); + "ui.admin.configuration.setting.edit.current_value", + ADMIN_BUNDLE))); add(new Text(e -> { final PageState state = e.getPageState(); @@ -60,21 +65,24 @@ public class SettingFormCurrentValuePanel extends GridPanel { final Class confClass; try { confClass = Class - .forName(selectedConf.getSelectedKey(state)); + .forName(selectedConf.getSelectedKey(state)); } catch (ClassNotFoundException ex) { throw new UncheckedWrapperException(ex); } final ConfigurationManager confManager = cdiUtil.findBean( - ConfigurationManager.class); + ConfigurationManager.class); final Object config = confManager.findConfiguration(confClass); final Object value; try { - value = confClass.getField(selectedSetting - .getSelectedKey(state)).get(config); - } catch (NoSuchFieldException | SecurityException | + final Field field = confClass.getDeclaredField(selectedSetting + .getSelectedKey(state)); + field.setAccessible(true); + value = field.get(config); + } catch (NoSuchFieldException | + SecurityException | IllegalAccessException ex) { LOGGER.warn("Failed to read setting {} from configuration {}", selectedSetting.getSelectedKey(state), diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormDouble.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormDouble.java index 0c2e8f4a3..d3bcbcbcd 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormDouble.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormDouble.java @@ -21,7 +21,9 @@ package com.arsdigita.ui.admin.configuration; import com.arsdigita.bebop.ParameterSingleSelectionModel; /** - * + * A subclass of {@link AbstractSettingFormSingleValue} for editing the value + * of a {@link DoubleSetting}. + * * @author Jens Pelzetter */ public class SettingFormDouble extends AbstractSettingFormSingleValue { diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormHeader.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormHeader.java index 284a4e329..48656e0f6 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormHeader.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormHeader.java @@ -18,6 +18,7 @@ */ package com.arsdigita.ui.admin.configuration; +import com.arsdigita.bebop.ActionLink; import com.arsdigita.bebop.BoxPanel; import com.arsdigita.bebop.Label; import com.arsdigita.bebop.PageState; @@ -38,17 +39,29 @@ import org.libreccm.l10n.GlobalizationHelper; import static com.arsdigita.ui.admin.AdminUiConstants.*; /** + * Header used by all setting forms/editors. The header contains a link to go + * back to the list of settings and heading for contains the title of the + * configuration class and the label of the setting which is edited. * * @author Jens Pelzetter */ public class SettingFormHeader extends BoxPanel { public SettingFormHeader( + final ConfigurationTab configurationTab, final ParameterSingleSelectionModel selectedConf, final ParameterSingleSelectionModel selectedSetting) { super(BoxPanel.VERTICAL); + final ActionLink backLink = new ActionLink(new GlobalizedMessage( + "ui.admin.configuration.setting.edit.back", ADMIN_BUNDLE)); + backLink.addActionListener(e -> { + final PageState state = e.getPageState(); + configurationTab.hideSettingForms(state); + }); + add(backLink); + final Label heading = new Label(new HeadingPrintListener( selectedConf, selectedSetting)); heading.setClassAttr("heading"); diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormLong.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormLong.java index dc286a7fb..39c24d053 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormLong.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormLong.java @@ -21,7 +21,9 @@ package com.arsdigita.ui.admin.configuration; import com.arsdigita.bebop.ParameterSingleSelectionModel; /** - * + * A subclass of {@link AbstractSettingFormSingleValue} for editing the value + * of a {@link LongSetting}. + * * @author Jens Pelzetter */ public class SettingFormLong extends AbstractSettingFormSingleValue { diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormString.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormString.java index aa7f13e58..d75d30b08 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormString.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/configuration/SettingFormString.java @@ -21,7 +21,9 @@ package com.arsdigita.ui.admin.configuration; import com.arsdigita.bebop.ParameterSingleSelectionModel; /** - * + * A subclass of {@link AbstractSettingFormSingleValue} for editing the value + * of a {@link StringSetting}. + * * @author Jens Pelzetter */ public class SettingFormString extends AbstractSettingFormSingleValue { diff --git a/ccm-core/src/main/java/org/libreccm/configuration/AbstractSetting.java b/ccm-core/src/main/java/org/libreccm/configuration/AbstractSetting.java index 9d2bd69b3..6e1be26ac 100644 --- a/ccm-core/src/main/java/org/libreccm/configuration/AbstractSetting.java +++ b/ccm-core/src/main/java/org/libreccm/configuration/AbstractSetting.java @@ -60,13 +60,16 @@ public abstract class AbstractSetting implements Serializable { private static final long serialVersionUID = 1631163618980178142L; + /** + * Database ID of the setting (primary key). + */ @Column(name = "SETTING_ID") @Id @GeneratedValue(strategy = GenerationType.AUTO) private long settingId; /** - * This configuration class this setting belongs to + * This configuration class this setting belongs to. */ @Column(name = "CONFIGURATION_CLASS", nullable = false, length = 512) @NotBlank diff --git a/ccm-core/src/main/java/org/libreccm/configuration/BigDecimalSetting.java b/ccm-core/src/main/java/org/libreccm/configuration/BigDecimalSetting.java index f74fd9b5f..c2af2c044 100644 --- a/ccm-core/src/main/java/org/libreccm/configuration/BigDecimalSetting.java +++ b/ccm-core/src/main/java/org/libreccm/configuration/BigDecimalSetting.java @@ -25,7 +25,9 @@ import javax.persistence.Column; import javax.persistence.Entity; /** - * + * Setting for values of type {@link BigDecimal}. Use this for rational numbers + * if precision is required. + * * @author Jens Pelzetter */ @Entity diff --git a/ccm-core/src/main/java/org/libreccm/configuration/BooleanSetting.java b/ccm-core/src/main/java/org/libreccm/configuration/BooleanSetting.java index 6d39fed18..d14e7c742 100644 --- a/ccm-core/src/main/java/org/libreccm/configuration/BooleanSetting.java +++ b/ccm-core/src/main/java/org/libreccm/configuration/BooleanSetting.java @@ -23,7 +23,8 @@ import javax.persistence.Column; import javax.persistence.Entity; /** - * + * Setting of boolean values. + * * @author Jens Pelzetter */ @Entity diff --git a/ccm-core/src/main/java/org/libreccm/configuration/ConfigurationException.java b/ccm-core/src/main/java/org/libreccm/configuration/ConfigurationException.java index c38a30f35..cd93673e5 100644 --- a/ccm-core/src/main/java/org/libreccm/configuration/ConfigurationException.java +++ b/ccm-core/src/main/java/org/libreccm/configuration/ConfigurationException.java @@ -19,10 +19,9 @@ package org.libreccm.configuration; -import org.libreccm.configuration.*; - /** - * + * Exception type which can be used in configuration classes to indicate errors. + * * @author Jens Pelzetter */ public class ConfigurationException extends RuntimeException { @@ -36,7 +35,6 @@ public class ConfigurationException extends RuntimeException { super(); } - /** * Constructs an instance of ConfigurationException with the specified detail message. * diff --git a/ccm-core/src/main/java/org/libreccm/configuration/ConfigurationManager.java b/ccm-core/src/main/java/org/libreccm/configuration/ConfigurationManager.java index f98a28d10..a2caf1584 100644 --- a/ccm-core/src/main/java/org/libreccm/configuration/ConfigurationManager.java +++ b/ccm-core/src/main/java/org/libreccm/configuration/ConfigurationManager.java @@ -55,7 +55,8 @@ public class ConfigurationManager { /** * Finds all configuration classes listed by the installed modules. * - * @return A sorted set containing all configuration classes. + * @return A sorted set (see {@link SortedSet}) containing all configuration + * classes. * * @see Module#configurations() */ @@ -256,43 +257,6 @@ public class ConfigurationManager { } } - /** - * Create a setting instance of a specific value type. - * - * @param Type variable. - * @param valueType The type of the value of the setting to create. - * - * @return An setting instance of the provided value type. - * - * @throws IllegalArgumentException If there is not setting type for the - * provided value type. - */ -// @SuppressWarnings("unchecked") -// AbstractSetting createSettingForValueType( -// final Class valueType) { -// -// final String valueTypeName = valueType.getName(); -// if (BigDecimal.class.getName().equals(valueTypeName)) { -// return (AbstractSetting) new BigDecimalSetting(); -// } else if (Boolean.class.getName().equals(valueTypeName)) { -// return (AbstractSetting) new BooleanSetting(); -// } else if (Double.class.getName().equals(valueTypeName)) { -// return (AbstractSetting) new DoubleSetting(); -// } else if (List.class.getName().equals(valueTypeName)) { -// return (AbstractSetting) new StringListSetting(); -// } else if (LocalizedString.class.getName().equals(valueTypeName)) { -// return (AbstractSetting) new LocalizedStringSetting(); -// } else if (Long.class.getName().equals(valueTypeName)) { -// return (AbstractSetting) new LongSetting(); -// } else if (Set.class.getName().equals(valueTypeName)) { -// return (AbstractSetting) new EnumSetting(); -// } else if (String.class.getName().equals(valueTypeName)) { -// return (AbstractSetting) new StringSetting(); -// } else { -// throw new IllegalArgumentException(String.format( -// "No setting type for value type \"%s\".", valueTypeName)); -// } -// } /** * Sets a value on a setting in the registry. * diff --git a/ccm-core/src/main/java/org/libreccm/configuration/DoubleSetting.java b/ccm-core/src/main/java/org/libreccm/configuration/DoubleSetting.java index c6302e78b..ac883186f 100644 --- a/ccm-core/src/main/java/org/libreccm/configuration/DoubleSetting.java +++ b/ccm-core/src/main/java/org/libreccm/configuration/DoubleSetting.java @@ -19,16 +19,22 @@ package org.libreccm.configuration; import java.io.Serializable; +import java.math.BigDecimal; + import javax.persistence.Column; import javax.persistence.Entity; /** + * Setting for values for type double (rational numbers). Be aware: Because how + * double values are handled by Java (and all other programming languages) the + * precision of a value of the type {@code double} can be guaranteed. If full + * precision is required use {@link BigDecimal} and {@link BigDecimalSetting}. * * @author Jens Pelzetter */ @Entity public class DoubleSetting - extends AbstractSetting implements Serializable { + extends AbstractSetting implements Serializable { private static final long serialVersionUID = 4698940335480821950L; @@ -70,7 +76,7 @@ public class DoubleSetting } return Double.doubleToLongBits(value) == Double.doubleToLongBits(other - .getValue()); + .getValue()); } @Override diff --git a/ccm-core/src/main/java/org/libreccm/configuration/EnumSetting.java b/ccm-core/src/main/java/org/libreccm/configuration/EnumSetting.java index fc603e193..4b4c90b97 100644 --- a/ccm-core/src/main/java/org/libreccm/configuration/EnumSetting.java +++ b/ccm-core/src/main/java/org/libreccm/configuration/EnumSetting.java @@ -29,11 +29,12 @@ import java.util.Objects; import javax.persistence.ElementCollection; import javax.persistence.Entity; +import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; /** - * A setting class for storing a list a strings. This can be used to generate + * A setting class for storing a set of strings. This can be used to generate * enums which can be configured by the administrator. * * @author Jens Pelzetter @@ -44,7 +45,7 @@ public class EnumSetting private static final long serialVersionUID = 1763168269981687340L; - @ElementCollection + @ElementCollection(fetch = FetchType.EAGER) @JoinTable(name = "SETTINGS_ENUM_VALUES", schema = DB_SCHEMA, joinColumns = { diff --git a/ccm-core/src/main/java/org/libreccm/configuration/ExampleConfiguration.java b/ccm-core/src/main/java/org/libreccm/configuration/ExampleConfiguration.java new file mode 100644 index 000000000..42989c244 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/configuration/ExampleConfiguration.java @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2016 LibreCCM Foundation. + * + * This library 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 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.configuration; + +import org.libreccm.l10n.LocalizedString; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.Set; + +/** + * Example of configuration with all available setting types. Not used anywhere + * else, only for testing. + * + * @author Jens Pelzetter + */ +@Configuration +public final class ExampleConfiguration { + + @Setting + private boolean enabled = false; + + @Setting + private long itemsPerPage = 42; + + @Setting + private double minTemperature = 23.42; + + @Setting + private BigDecimal price = new BigDecimal("10.42"); + + @Setting + private String hostname = "srv-01.example.org"; + + @Setting + private LocalizedString title = new LocalizedString(); + + @Setting + private List components = Arrays.asList(new String[]{"component1", + "component2", + "component3"}); + + @Setting + private Set supportedLanguages = new HashSet<>(Arrays.asList( + new String[]{"en", "de"})); + + public ExampleConfiguration() { + title.addValue(Locale.GERMAN, "Dies ist ein Test"); + title.addValue(Locale.ENGLISH, "This is a test"); + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(final boolean enabled) { + this.enabled = enabled; + } + + public long getItemsPerPage() { + return itemsPerPage; + } + + public void setItemsPerPage(final long itemsPerPage) { + this.itemsPerPage = itemsPerPage; + } + + public double getMinTemperature() { + return minTemperature; + } + + public void setMinTemperature(final double minTemperature) { + this.minTemperature = minTemperature; + } + + public BigDecimal getPrice() { + return price; + } + + public void setPrice(final BigDecimal price) { + this.price = price; + } + + public String getHostname() { + return hostname; + } + + public void setHostname(final String hostname) { + this.hostname = hostname; + } + + public LocalizedString getTitle() { + return title; + } + + public void setTitle(LocalizedString title) { + this.title = title; + } + + public List getComponents() { + return Collections.unmodifiableList(components); + } + + public void setComponents(final List components) { + this.components = components; + } + + public Set getSupportedLanguages() { + return Collections.unmodifiableSet(supportedLanguages); + } + + public void setSupportedLanguages(final Set supportedLanguages) { + this.supportedLanguages = supportedLanguages; + } + + @Override + public int hashCode() { + int hash = 3; + if (enabled) { + hash = 13 * hash + 1; + } else { + hash = 13 * hash; + } + hash + = 13 * hash + (int) (itemsPerPage ^ (itemsPerPage >>> 32)); + hash + = 13 * hash + (int) (Double.doubleToLongBits(minTemperature) + ^ (Double.doubleToLongBits(minTemperature) + >>> 32)); + hash = 13 * hash + Objects.hashCode(price); + hash = 13 * hash + Objects.hashCode(hostname); + hash = 13 * hash + Objects.hashCode(title); + hash = 13 * hash + Objects.hashCode(components); + hash = 13 * hash + Objects.hashCode(supportedLanguages); + return hash; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof ExampleConfiguration)) { + return false; + } + final ExampleConfiguration other = (ExampleConfiguration) obj; + if (enabled != other.isEnabled()) { + return false; + } + if (itemsPerPage != other.getItemsPerPage()) { + return false; + } + if (Double.doubleToLongBits(minTemperature) != Double.doubleToLongBits( + other.getMinTemperature())) { + return false; + } + if (!Objects.equals(hostname, other.getHostname())) { + return false; + } + if (!Objects.equals(price, other.getPrice())) { + return false; + } + if (!Objects.equals(title, other.getTitle())) { + return false; + } + if (!Objects.equals(components, other.getComponents())) { + return false; + } + return Objects.equals(supportedLanguages, other.getSupportedLanguages()); + } + + @Override + public String toString() { + return String.format("%s{ " + + "enabled = %b, " + + "itemsPerPage = %d, " + + "minTemperature = %f, " + + "hostname = %s, " + + "price = %f, " + + "title = %s, " + + "components = %s, " + + "supportedLanguages = %s" + + " }", + super.toString(), + enabled, + itemsPerPage, + minTemperature, + hostname, + price, + Objects.toString(title), + Objects.toString(components), + Objects.toString(supportedLanguages)); + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/configuration/LocalizedStringSetting.java b/ccm-core/src/main/java/org/libreccm/configuration/LocalizedStringSetting.java index 3a8ab0fd4..e3ea1ccbb 100644 --- a/ccm-core/src/main/java/org/libreccm/configuration/LocalizedStringSetting.java +++ b/ccm-core/src/main/java/org/libreccm/configuration/LocalizedStringSetting.java @@ -34,7 +34,7 @@ import javax.persistence.JoinTable; /** * A setting which stores a {@link LocalizedString} . This can be used for * storing values for text in the user interface which should be customisable by - * the administrator. + * the administrator. It is also useful for storing email templates. * * @author Jens Pelzetter */ diff --git a/ccm-core/src/main/java/org/libreccm/configuration/LongSetting.java b/ccm-core/src/main/java/org/libreccm/configuration/LongSetting.java index d5f95ec5a..c2047dd6c 100644 --- a/ccm-core/src/main/java/org/libreccm/configuration/LongSetting.java +++ b/ccm-core/src/main/java/org/libreccm/configuration/LongSetting.java @@ -18,13 +18,11 @@ */ package org.libreccm.configuration; -import static org.libreccm.core.CoreConstants.*; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; -import javax.persistence.Table; /** * Setting for storing a long value. diff --git a/ccm-core/src/main/java/org/libreccm/configuration/Setting.java b/ccm-core/src/main/java/org/libreccm/configuration/Setting.java index cb28b69ac..49c6360d8 100644 --- a/ccm-core/src/main/java/org/libreccm/configuration/Setting.java +++ b/ccm-core/src/main/java/org/libreccm/configuration/Setting.java @@ -18,7 +18,6 @@ */ package org.libreccm.configuration; -import org.libreccm.configuration.*; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/ccm-core/src/main/java/org/libreccm/configuration/SettingConverter.java b/ccm-core/src/main/java/org/libreccm/configuration/SettingConverter.java index 7baa7f601..1c9f7109c 100644 --- a/ccm-core/src/main/java/org/libreccm/configuration/SettingConverter.java +++ b/ccm-core/src/main/java/org/libreccm/configuration/SettingConverter.java @@ -18,6 +18,8 @@ */ package org.libreccm.configuration; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.libreccm.l10n.LocalizedString; import java.math.BigDecimal; @@ -29,24 +31,35 @@ import java.util.Set; import javax.enterprise.context.RequestScoped; /** - * Helper class for converting values to settings. + * Helper class for converting values to settings of the appropriate type. * * @author Jens Pelzetter */ @RequestScoped class SettingConverter { + private static final Logger LOGGER = LogManager.getLogger( + SettingConverter.class); + + /** + * Stores a map of the Java types and the corresponding subtypes + * {@link AbstractSetting}. We are using a map here to avoid a large if or + * switch statement. + */ private final Map>> typeMap; public SettingConverter() { typeMap = new HashMap<>(); typeMap.put(BigDecimal.class.getName(), BigDecimalSetting.class); typeMap.put(Boolean.class.getName(), BooleanSetting.class); + typeMap.put("boolean", BooleanSetting.class); typeMap.put(Double.class.getName(), DoubleSetting.class); + typeMap.put("double", DoubleSetting.class); typeMap.put(List.class.getName(), StringListSetting.class); typeMap.put(LocalizedString.class.getName(), LocalizedStringSetting.class); typeMap.put(Long.class.getName(), LongSetting.class); + typeMap.put("long", LongSetting.class); typeMap.put(Set.class.getName(), EnumSetting.class); typeMap.put(String.class.getName(), StringSetting.class); } @@ -68,14 +81,17 @@ class SettingConverter { final String valueTypeName = valueType.getName(); final Class> clazz = typeMap.get( valueTypeName); - + if (clazz == null) { - throw new IllegalArgumentException(String.format( + LOGGER.error("No setting type for value type \"{}\".", + valueTypeName); + throw new IllegalArgumentException(String.format( "No setting type for value type \"%s\".", valueTypeName)); } else { try { return (AbstractSetting) clazz.newInstance(); } catch (InstantiationException | IllegalAccessException ex) { + LOGGER.error("Failed to create setting instance.", ex); throw new IllegalStateException( "Failed to create setting instance.", ex); } diff --git a/ccm-core/src/main/java/org/libreccm/configuration/SettingManager.java b/ccm-core/src/main/java/org/libreccm/configuration/SettingManager.java index fe3c1e7fc..9ae4f65f1 100644 --- a/ccm-core/src/main/java/org/libreccm/configuration/SettingManager.java +++ b/ccm-core/src/main/java/org/libreccm/configuration/SettingManager.java @@ -192,6 +192,8 @@ public class SettingManager { * @return The requested setting if it exists in the registry, {@code null} * otherwise. */ + @Transactional(Transactional.TxType.REQUIRED) + @SuppressWarnings("unchecked") public AbstractSetting findSetting(final String confName, final String name, final Class clazz) { @@ -233,7 +235,7 @@ public class SettingManager { if (confAnnotation.descBundle() == null || confAnnotation.descBundle().isEmpty()) { return String.join("", - configuration.getClass().getName(), + configuration.getName(), "Description"); } else { return confAnnotation.descBundle(); diff --git a/ccm-core/src/main/java/org/libreccm/configuration/StringListSetting.java b/ccm-core/src/main/java/org/libreccm/configuration/StringListSetting.java index 90a3e9f12..0b00089e1 100644 --- a/ccm-core/src/main/java/org/libreccm/configuration/StringListSetting.java +++ b/ccm-core/src/main/java/org/libreccm/configuration/StringListSetting.java @@ -26,11 +26,14 @@ import java.util.Objects; import javax.persistence.ElementCollection; import javax.persistence.Entity; +import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; /** - * + * Setting for a list of strings. In contrast to the {@link EnumSetting} which + * uses a {@link java.util.Set} a list maintains the order of its elements. + * * @author Jens Pelzetter */ @Entity @@ -38,12 +41,15 @@ public class StringListSetting extends AbstractSetting> { private static final long serialVersionUID = 7093818804712916413L; - @ElementCollection + @ElementCollection(fetch = FetchType.EAGER) @JoinTable(name = "SETTINGS_STRING_LIST", schema = DB_SCHEMA, joinColumns = {@JoinColumn(name = "LIST_ID")}) private List value; + /** + * Returns a copy of the list managed by this setting. + */ @Override public List getValue() { if (value == null) { @@ -53,15 +59,30 @@ public class StringListSetting extends AbstractSetting> { } } + /** + * Replaces the list managed by this setting. + * + * @param value + */ @Override public void setValue(final List value) { this.value = value; } + /** + * Adds a value to the list. + * + * @param value The value to add. + */ public void addListValue(final String value) { this.value.add(value); } + /** + * Removes a value from the list. + * + * @param value the value to add. + */ public void removeListValue(final String value) { this.value.remove(value); } diff --git a/ccm-core/src/main/java/org/libreccm/core/CcmCore.java b/ccm-core/src/main/java/org/libreccm/core/CcmCore.java index 6ddd3e18a..19fe34b8e 100644 --- a/ccm-core/src/main/java/org/libreccm/core/CcmCore.java +++ b/ccm-core/src/main/java/org/libreccm/core/CcmCore.java @@ -18,18 +18,12 @@ */ package org.libreccm.core; -import com.arsdigita.bebop.BebopConfig; -import com.arsdigita.kernel.KernelConfig; -import com.arsdigita.mail.MailConfig; -import com.arsdigita.notification.NotificationConfig; import com.arsdigita.ui.admin.AdminApplicationCreator; import com.arsdigita.ui.admin.AdminServlet; import com.arsdigita.ui.admin.AdminApplicationSetup; import com.arsdigita.ui.login.LoginApplicationCreator; import com.arsdigita.ui.login.LoginServlet; import com.arsdigita.ui.login.LoginApplicationSetup; -import com.arsdigita.workflow.simple.WorkflowConfig; -import com.arsdigita.xml.XmlConfig; import org.libreccm.modules.CcmModule; import org.libreccm.modules.InitEvent; @@ -37,8 +31,6 @@ import org.libreccm.modules.InstallEvent; import org.libreccm.modules.Module; import org.libreccm.modules.ShutdownEvent; import org.libreccm.modules.UnInstallEvent; -import org.libreccm.security.EmailTemplates; -import org.libreccm.security.OneTimeAuthConfig; import org.libreccm.security.SystemUsersSetup; import org.libreccm.web.ApplicationType; @@ -72,6 +64,7 @@ import org.libreccm.web.ApplicationType; com.arsdigita.workflow.simple.WorkflowConfig.class, com.arsdigita.xml.XmlConfig.class, com.arsdigita.xml.formatters.DateFormatterConfig.class, + org.libreccm.configuration.ExampleConfiguration.class, org.libreccm.security.EmailTemplates.class, org.libreccm.security.OneTimeAuthConfig.class, }) diff --git a/ccm-core/src/main/java/org/libreccm/l10n/LocalizedString.java b/ccm-core/src/main/java/org/libreccm/l10n/LocalizedString.java index 1da900a57..0d1e7d288 100644 --- a/ccm-core/src/main/java/org/libreccm/l10n/LocalizedString.java +++ b/ccm-core/src/main/java/org/libreccm/l10n/LocalizedString.java @@ -180,15 +180,14 @@ public class LocalizedString implements Serializable { if (!other.canEqual(this)) { return false; } - + return Objects.equals(values, other.getValues()); } public boolean canEqual(final Object obj) { return obj instanceof LocalizedString; } - - + @Override public String toString() { return String.format( diff --git a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources.properties b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources.properties index 421296739..331f7f0a4 100644 --- a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources.properties +++ b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources.properties @@ -422,7 +422,7 @@ ui.admin.configuration.settings.table.col_edit_setting.header=Edit ui.admin.configuration.settings.edit=Edit ui.admin.configuration.settings.read_error=Failed to read setting value. ui.admin.configuration.setting.edit.heading=Edit setting {0}/{1} -ui.admin.configuration.setting.edit.current_value=Current value +ui.admin.configuration.setting.edit.current_value=Current value: ui.admin.configuration.setting.edit.new_value=New value ui.admin.configuration.setting.error.blank=New value can't be blank. ui.admin.configuration.setting.localized_string.no_values=No values for this setting. @@ -450,3 +450,12 @@ ui.admin.configuration.setting.enum.value.edit=Edit ui.admin.configuration.setting.enum.value.del=Delete ui.admin.configuration.setting.enum.value.label=Value ui.admin.configuration.back_to_configurations=Back to list of configurations +ui.admin.configuration.editing_configuration=Edit configuration {0} +ui.admin.configuration.setting.edit.back=Back to list of settings +ui.admin.configuration.setting.error.incorrect_format=The provided value is not in the correct format. +ui.admin.configuration.setting.stringlist.value.label=Value +ui.admin.configuration.setting.localized_string.value.label=Value +ui.admin.configuration.setting.localized_string.col_lang=Language +ui.admin.configuration.setting.localized_string.col_value=Value +ui.admin.configuration.setting.localized_string.col_del=Delete +ui.admin.configuration.setting.localized_string.col_edit=Edit diff --git a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_de.properties b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_de.properties index f347c2a4e..ad952c343 100644 --- a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_de.properties +++ b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_de.properties @@ -425,7 +425,7 @@ ui.admin.configuration.settings.table.col_edit_setting.header=Bearbeiten ui.admin.configuration.settings.edit=Bearbeiten ui.admin.configuration.settings.read_error=Fehler beim lesen des Parameters. ui.admin.configuration.setting.edit.heading=Parameter {0}/{1} bearbeiten -ui.admin.configuration.setting.edit.current_value=Aktueller Wert +ui.admin.configuration.setting.edit.current_value=Aktueller Wert: ui.admin.configuration.setting.edit.new_value=Neuer Wert ui.admin.configuration.setting.error.blank=Der neue Wert darf nicht leer sein. ui.admin.configuration.setting.localized_string.no_values=Keine Werte f\u00fcr diesen Parameter. @@ -453,3 +453,12 @@ ui.admin.configuration.setting.enum.value.edit=Bearbeiten ui.admin.configuration.setting.enum.value.del=L\u00f6schen ui.admin.configuration.setting.enum.value.label=Wert ui.admin.configuration.back_to_configurations=Zur\u00fcck zur Liste der Konfigurationen +ui.admin.configuration.editing_configuration=Konfiguration {0} bearbeiten +ui.admin.configuration.setting.edit.back=Zur\u00fcck zur Liste der Einstellungen +ui.admin.configuration.setting.error.incorrect_format=Der angegeben Wert ist nicht im korrekten Format angegeben. +ui.admin.configuration.setting.stringlist.value.label=Wert +ui.admin.configuration.setting.localized_string.value.label=Wert +ui.admin.configuration.setting.localized_string.col_lang=Sprache +ui.admin.configuration.setting.localized_string.col_value=Wert +ui.admin.configuration.setting.localized_string.col_del=L\u00f6schen +ui.admin.configuration.setting.localized_string.col_edit=Bearbeiten diff --git a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_en.properties b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_en.properties index ca74df499..010db66d8 100755 --- a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_en.properties +++ b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_en.properties @@ -398,7 +398,7 @@ ui.admin.configuration.settings.table.col_edit_setting.header=Edit ui.admin.configuration.settings.edit=Edit ui.admin.configuration.settings.read_error=Failed to read setting value. ui.admin.configuration.setting.edit.heading=Edit setting {0}/{1} -ui.admin.configuration.setting.edit.current_value=Current value +ui.admin.configuration.setting.edit.current_value=Current value: ui.admin.configuration.setting.edit.new_value=New value ui.admin.configuration.setting.error.blank=New value can't be blank. ui.admin.configuration.setting.localized_string.no_values=No values for this setting. @@ -426,3 +426,12 @@ ui.admin.configuration.setting.enum.value.edit=Edit ui.admin.configuration.setting.enum.value.del=Delete ui.admin.configuration.setting.enum.value.label=Value ui.admin.configuration.back_to_configurations=Back to list of configurations +ui.admin.configuration.editing_configuration=Edit configuration {0} +ui.admin.configuration.setting.edit.back=Back to list of settings +ui.admin.configuration.setting.error.incorrect_format=The provided value is not in the correct format. +ui.admin.configuration.setting.stringlist.value.label=Value +ui.admin.configuration.setting.localized_string.value.label=Value +ui.admin.configuration.setting.localized_string.col_lang=Language +ui.admin.configuration.setting.localized_string.col_value=Value +ui.admin.configuration.setting.localized_string.col_del=Delete +ui.admin.configuration.setting.localized_string.col_edit=Edit diff --git a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_fr.properties b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_fr.properties index dab60e153..d4ff2bea6 100755 --- a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_fr.properties +++ b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_fr.properties @@ -389,7 +389,7 @@ ui.admin.configuration.settings.table.col_edit_setting.header=Edit ui.admin.configuration.settings.edit=Edit ui.admin.configuration.settings.read_error=Failed to read setting value. ui.admin.configuration.setting.edit.heading=Edit setting {0}/{1} -ui.admin.configuration.setting.edit.current_value=Current value +ui.admin.configuration.setting.edit.current_value=Current value: ui.admin.configuration.setting.edit.new_value=New value ui.admin.configuration.setting.error.blank=New value can't be blank. ui.admin.configuration.setting.localized_string.no_values=No values for this setting. @@ -417,3 +417,12 @@ ui.admin.configuration.setting.enum.value.edit=Edit ui.admin.configuration.setting.enum.value.del=Delete ui.admin.configuration.setting.enum.value.label=Value ui.admin.configuration.back_to_configurations=Back to list of configurations +ui.admin.configuration.editing_configuration=Edit configuration {0} +ui.admin.configuration.setting.edit.back=Back to list of settings +ui.admin.configuration.setting.error.incorrect_format=The provided value is not in the correct format. +ui.admin.configuration.setting.stringlist.value.label=Value +ui.admin.configuration.setting.localized_string.value.label=Value +ui.admin.configuration.setting.localized_string.col_lang=Language +ui.admin.configuration.setting.localized_string.col_value=Value +ui.admin.configuration.setting.localized_string.col_del=Delete +ui.admin.configuration.setting.localized_string.col_edit=Edit