package net.frontlinesms.ui.handler.settings;
import java.util.ArrayList;
import java.util.List;
import net.frontlinesms.AppProperties;
import net.frontlinesms.settings.BaseSectionHandler;
import net.frontlinesms.settings.DatabaseSettings;
import net.frontlinesms.settings.FrontlineValidationMessage;
import net.frontlinesms.ui.ThinletUiEventHandler;
import net.frontlinesms.ui.UiGeneratorController;
import net.frontlinesms.ui.i18n.InternationalisationUtils;
import net.frontlinesms.ui.settings.UiSettingsSectionHandler;
/**
* UI Handler for the "General/Database" section of the Core Settings
* @author Morgan Belkadi <morgan@frontlinesms.com>
*/
public class SettingsDatabaseSectionHandler extends BaseSectionHandler implements UiSettingsSectionHandler, ThinletUiEventHandler {
private static final String UI_SECTION_DATABASE = "/ui/core/settings/general/pnDatabaseSettings.xml";
private static final String UI_SECTION_DATABASE_AS_DIALOG = "/ui/core/database/pnSettings.xml";
private static final String I18N_SETTINGS_MENU_DATABASE_SETTINGS = "menuitem.edit.db.settings";
/** The combobox containing the different databases */
private static final String COMPONENT_SETTINGS_SELECTION = "cbConfigFile";
/** The panel containing individual settings controls */
private static final String COMPONENT_PN_DATABASE_SETTINGS = "pnSettings";
/** The constant property key for database passwords */
private static final String PASSWORD_PROPERTY_KEY = "password";
private static final String I18N_MESSAGE_DATABASE_SETTINGS_CHANGED = "message.database.settings.changed";
private static final String SECTION_ITEM_DATABASE_CONFIG_PATH = "GENERAL_DATABASE_CONFIG_PATH";
private static final String SECTION_ITEM_DATABASE_CONFIG = "GENERAL_DATABASE_CONFIG_";
/** The settings currently selected in the combobox */
private DatabaseSettings selectedSettings;
private Object dialogComponent;
public SettingsDatabaseSectionHandler (UiGeneratorController ui) {
super(ui);
}
protected void init() {
this.panel = uiController.loadComponentFromFile(UI_SECTION_DATABASE, this);
// Populate combobox
String selectedDatabaseConfigPath = AppProperties.getInstance().getDatabaseConfigPath();
List<DatabaseSettings> databaseSettings = DatabaseSettings.getSettings();
Object settingsSelection = find(COMPONENT_SETTINGS_SELECTION);
for(int settingsIndex = 0; settingsIndex < databaseSettings.size(); ++settingsIndex) {
DatabaseSettings settings = databaseSettings.get(settingsIndex);
Object comboBox = createComboBoxChoice(settings);
this.uiController.add(settingsSelection, comboBox);
// if appropriate, choose the combobox selection
if(settings.getFilePath().equals(selectedDatabaseConfigPath)) {
this.selectedSettings = settings;
this.uiController.setSelectedIndex(settingsSelection, settingsIndex);
}
}
this.originalValues.put(SECTION_ITEM_DATABASE_CONFIG_PATH, selectedDatabaseConfigPath);
// populate settings panel
refreshSettingsPanel();
}
private Object createComboBoxChoice(DatabaseSettings settings) {
Object cb = this.uiController.createComboboxChoice(settings.getName(), settings);
// TODO perhaps we could set a settings-specific icon here
return cb;
}
/** Refresh the panel containing settings specific to the currently-selected {@link DatabaseSettings}. */
private void refreshSettingsPanel() {
// populate the settings panel
Object settingsPanel = find(COMPONENT_PN_DATABASE_SETTINGS);
this.uiController.removeAll(settingsPanel);
this.selectedSettings.loadProperties();
for(String key : this.selectedSettings.getPropertyKeys()) {
// TODO would be nice to set icons for the different settings
this.uiController.add(settingsPanel, this.uiController.createLabel(key));
// TODO may want to set the types of these, e.g. password, number etc.
String value = this.selectedSettings.getPropertyValue(key);
Object field;
if (key.equals(PASSWORD_PROPERTY_KEY)) {
field = this.uiController.createPasswordfield(key, value);
} else {
field = this.uiController.createTextfield(key, value);
}
if (this.selectedSettings.getFilePath().equals(this.originalValues.get(SECTION_ITEM_DATABASE_CONFIG_PATH))) {
if (this.originalValues.get(SECTION_ITEM_DATABASE_CONFIG + key) == null) {
// Let's save those settings for the first time
this.originalValues.put(SECTION_ITEM_DATABASE_CONFIG + key, value);
} else {
/**
* The original config path has been reselected.
* The fields are crecreated, so potential previous changes have been lost
* Let's call the fields "unchanged" for the {@link FrontlineSettingsHandler}
**/
this.settingChanged(SECTION_ITEM_DATABASE_CONFIG + key, value);
}
}
this.uiController.setAttachedObject(field, key);
this.uiController.setAction(field, "configFieldChanged(this)", null, this);
this.uiController.add(settingsPanel, field);
}
}
/**
* A new database type has been selected in the ComboBox
*/
public void configFileChanged() {
String selected = this.uiController.getText(this.uiController.getSelectedItem(find(COMPONENT_SETTINGS_SELECTION)));
int selectedIndex = this.uiController.getSelectedIndex(find(COMPONENT_SETTINGS_SELECTION));
if (selected != null) {
this.selectedSettings = DatabaseSettings.getSettings().get(selectedIndex);
this.refreshSettingsPanel();
super.settingChanged(SECTION_ITEM_DATABASE_CONFIG_PATH, selectedSettings.getFilePath());
}
}
/**
* A database configuration field has been modified
* @param databaseConfigField The component having been modified.
*/
public void configFieldChanged(Object databaseConfigField) {
if (selectedSettings.getFilePath().equals(this.originalValues.get(SECTION_ITEM_DATABASE_CONFIG_PATH))) {
this.settingChanged(SECTION_ITEM_DATABASE_CONFIG + this.uiController.getAttachedObject(databaseConfigField, String.class), this.uiController.getText(databaseConfigField));
}
}
public void save() {
// get the settings we are modifying
DatabaseSettings selectedSettings = this.selectedSettings;
// check if the settings file has changed
AppProperties appProperties = AppProperties.getInstance();
boolean settingsFileChanged = !selectedSettings.getFilePath().equals(appProperties.getDatabaseConfigPath());
// If settings file has NOT changed, check if individual settings have changed
boolean updateIndividualSettings = false;
List<Setting> displayedSettings = getDisplayedSettingValues();
// We are modifying the current settings rather than changing to a whole new database config, so check if the
// settings have changed at all
for(Setting displayed : displayedSettings) {
String originalValue = this.selectedSettings.getPropertyValue(displayed.getKey());
if(!originalValue.equals(displayed.getValue())) {
updateIndividualSettings = true;
break;
}
}
if(settingsFileChanged || updateIndividualSettings) {
if(settingsFileChanged) {
appProperties.setDatabaseConfigPath(selectedSettings.getFilePath());
appProperties.saveToDisk();
}
if(updateIndividualSettings) {
for(Setting displayed : displayedSettings) {
this.selectedSettings.setPropertyValue(displayed.getKey(), displayed.getValue());
}
this.selectedSettings.saveProperties();
}
this.uiController.alert(InternationalisationUtils.getI18nString(I18N_MESSAGE_DATABASE_SETTINGS_CHANGED));
}
}
/** @return the settings and values that are currently displayed on the UI */
private List<Setting> getDisplayedSettingValues() {
Object settingsPanel = find(COMPONENT_PN_DATABASE_SETTINGS);
Object[] settingsComponents = this.uiController.getItems(settingsPanel);
ArrayList<Setting> settings = new ArrayList<Setting>();
for (int settingIndex=1; settingIndex<settingsComponents.length; settingIndex+=2) {
// This code assumes that all settings are in TEXTFIELDS; this may change in the future.
Object tf = settingsComponents[settingIndex];
String key = this.uiController.getName(tf);
String value = this.uiController.getText(tf);
settings.add(new Setting(key, value));
}
return settings;
}
/**
* Show this panel as a dialog. The dialog will be removed by default by the removeDialog method.
* @param titleI18nKey
*/
public void showAsDialog() {
Object dialogComponent = this.uiController.createDialog("Pwals");
this.panel = this.uiController.loadComponentFromFile(UI_SECTION_DATABASE_AS_DIALOG, this);
this.init();
this.uiController.add(dialogComponent, panel);
this.uiController.setCloseAction(dialogComponent, "removeDialog", dialogComponent, this);
this.uiController.add(dialogComponent);
this.dialogComponent = dialogComponent;
}
public void removeDialog() {
this.uiController.remove(this.dialogComponent);
}
public List<FrontlineValidationMessage> validateFields() {
return null;
}
public String getTitle() {
return InternationalisationUtils.getI18nString(I18N_SETTINGS_MENU_DATABASE_SETTINGS);
}
public Object getSectionNode() {
return createSectionNode(InternationalisationUtils.getI18nString(I18N_SETTINGS_MENU_DATABASE_SETTINGS), this, "/icons/database_edit.png");
}
}
class Setting {
private final String key;
private final String value;
public Setting(String key, String value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
}