/*****************************************************************************/// TranslatorSettings// Written by Michael Wilber, Haiku Translation Kit Team//// TranslatorSettings.cpp//// This class manages (saves/loads/locks/unlocks) the settings// for a Translator.////// Copyright (c) 2004 Haiku Project//// Permission is hereby granted, free of charge, to any person obtaining a// copy of this software and associated documentation files (the "Software"),// to deal in the Software without restriction, including without limitation// the rights to use, copy, modify, merge, publish, distribute, sublicense,// and/or sell copies of the Software, and to permit persons to whom the// Software is furnished to do so, subject to the following conditions://// The above copyright notice and this permission notice shall be included// in all copies or substantial portions of the Software.//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER// DEALINGS IN THE SOFTWARE./*****************************************************************************/#include <string.h>#include <File.h>#include <FindDirectory.h>#include <TranslatorFormats.h>// for B_TRANSLATOR_EXT_*#include "TranslatorSettings.h"// ---------------------------------------------------------------// Constructor//// Sets the default settings, location for the settings file// and sets the reference count to 1//// Preconditions://// Parameters://// Postconditions://// Returns:// ---------------------------------------------------------------TranslatorSettings::TranslatorSettings(const char *settingsFile,const TranSetting *defaults, int32 defCount): fLock("TranslatorSettings Lock"){if (find_directory(B_USER_SETTINGS_DIRECTORY, &fSettingsPath))fSettingsPath.SetTo("/tmp");fSettingsPath.Append(settingsFile);fRefCount = 1;if (defCount > 0) {fDefaults = defaults;fDefCount = defCount;} else {fDefaults = NULL;fDefCount = 0;}// Add Default Settings// (Used when loading from the settings file or from// a BMessage fails)const TranSetting *defs = fDefaults;for (int32 i = 0; i < fDefCount; i++) {switch (defs[i].dataType) {case TRAN_SETTING_BOOL:fSettingsMsg.AddBool(defs[i].name,static_cast<bool>(defs[i].defaultVal));break;case TRAN_SETTING_INT32:fSettingsMsg.AddInt32(defs[i].name, defs[i].defaultVal);break;default:// ASSERT here? Erase the bogus setting entry instead?break;}}}// ---------------------------------------------------------------// Acquire//// Returns a pointer to the TranslatorSettings and increments// the reference count.//// Preconditions://// Parameters://// Postconditions://// Returns: pointer to this TranslatorSettings object// ---------------------------------------------------------------TranslatorSettings *TranslatorSettings::Acquire(){TranslatorSettings *psettings = NULL;fLock.Lock();fRefCount++;psettings = this;fLock.Unlock();return psettings;}// ---------------------------------------------------------------// Release//// Decrements the reference count and deletes the// TranslatorSettings if the reference count is zero.//// Preconditions://// Parameters://// Postconditions://// Returns: pointer to this TranslatorSettings object if// the reference count is greater than zero, returns NULL// if the reference count is zero and the TranslatorSettings// object has been deleted// ---------------------------------------------------------------TranslatorSettings *TranslatorSettings::Release(){TranslatorSettings *psettings = NULL;fLock.Lock();fRefCount--;if (fRefCount > 0) {psettings = this;fLock.Unlock();} elsedelete this;// delete this object and// release locksreturn psettings;}// ---------------------------------------------------------------// Destructor//// Does nothing!//// Preconditions://// Parameters://// Postconditions://// Returns:// ---------------------------------------------------------------TranslatorSettings::~TranslatorSettings(){}// ---------------------------------------------------------------// LoadSettings//// Loads the settings by reading them from the default// settings file.//// Preconditions://// Parameters://// Postconditions://// Returns: B_OK if there were no errors or an error code from// BFile::SetTo() or BMessage::Unflatten() if there were errors// ---------------------------------------------------------------status_tTranslatorSettings::LoadSettings(){status_t result;fLock.Lock();// Don't try to open the settings file if there are// no settings that need to be loadedif (fDefCount > 0) {BFile settingsFile;result = settingsFile.SetTo(fSettingsPath.Path(), B_READ_ONLY);if (result == B_OK) {BMessage msg;result = msg.Unflatten(&settingsFile);if (result == B_OK)result = LoadSettings(&msg);}} elseresult = B_OK;fLock.Unlock();return result;}// ---------------------------------------------------------------// LoadSettings//// Loads the settings from a BMessage passed to the function.//// Preconditions://// Parameters: pmsg pointer to BMessage that contains the// settings//// Postconditions://// Returns: B_BAD_VALUE if pmsg is NULL or invalid options// have been found, B_OK if there were no// errors or an error code from BMessage::FindBool() or// BMessage::ReplaceBool() if there were other errors// ---------------------------------------------------------------status_tTranslatorSettings::LoadSettings(BMessage *pmsg){if (pmsg == NULL)return B_BAD_VALUE;fLock.Lock();const TranSetting *defaults = fDefaults;for (int32 i = 0; i < fDefCount; i++) {switch (defaults[i].dataType) {case TRAN_SETTING_BOOL:{bool value;if (pmsg->FindBool(defaults[i].name, &value) != B_OK) {if (fSettingsMsg.HasBool(defaults[i].name))break;elsevalue = static_cast<bool>(defaults[i].defaultVal);}fSettingsMsg.ReplaceBool(defaults[i].name, value);break;}case TRAN_SETTING_INT32:{int32 value;if (pmsg->FindInt32(defaults[i].name, &value) != B_OK) {if (fSettingsMsg.HasInt32(defaults[i].name))break;elsevalue = defaults[i].defaultVal;}fSettingsMsg.ReplaceInt32(defaults[i].name, value);break;}default:// TODO: ASSERT here? Erase the bogus setting entry instead?break;}}fLock.Unlock();return B_OK;}// ---------------------------------------------------------------// SaveSettings//// Saves the settings as a flattened BMessage to the default// settings file//// Preconditions://// Parameters://// Postconditions://// Returns: B_OK if no errors or an error code from BFile::SetTo()// or BMessage::Flatten() if there were errors// ---------------------------------------------------------------status_tTranslatorSettings::SaveSettings(){status_t result;fLock.Lock();// Only write out settings file if there are// actual settings stored by this objectif (fDefCount > 0) {BFile settingsFile;result = settingsFile.SetTo(fSettingsPath.Path(),B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);if (result == B_OK)result = fSettingsMsg.Flatten(&settingsFile);} elseresult = B_OK;fLock.Unlock();return result;}// ---------------------------------------------------------------// GetConfigurationMessage//// Saves the current settings to the BMessage passed to the// function//// Preconditions://// Parameters: pmsg pointer to BMessage where the settings// will be stored//// Postconditions://// Returns: B_OK if there were no errors or an error code from// BMessage::RemoveName() or BMessage::AddBool() if there were// errors// ---------------------------------------------------------------status_tTranslatorSettings::GetConfigurationMessage(BMessage *pmsg){status_t result = B_BAD_VALUE;if (pmsg) {int32 i;for (i = 0; i < fDefCount; i++) {result = pmsg->RemoveName(fDefaults[i].name);if (result != B_OK && result != B_NAME_NOT_FOUND)break;}if (i == fDefCount) {fLock.Lock();result = B_OK;const TranSetting *defs = fDefaults;for (i = 0; i < fDefCount && result >= B_OK; i++) {switch (defs[i].dataType) {case TRAN_SETTING_BOOL:result = pmsg->AddBool(defs[i].name,SetGetBool(defs[i].name));break;case TRAN_SETTING_INT32:result = pmsg->AddInt32(defs[i].name,SetGetInt32(defs[i].name));break;default:// ASSERT here? Erase the bogus setting entry instead?break;}}fLock.Unlock();}}return result;}// ---------------------------------------------------------------// FindTranSetting//// Returns a pointer to the TranSetting with the given name////// Preconditions://// Parameters: name name of the TranSetting to find////// Postconditions://// Returns: NULL if the TranSetting cannot be found, or a pointer// to the desired TranSetting if it is found// ---------------------------------------------------------------const TranSetting *TranslatorSettings::FindTranSetting(const char *name){for (int32 i = 0; i < fDefCount; i++) {if (!strcmp(fDefaults[i].name, name))return fDefaults + i;}return NULL;}// ---------------------------------------------------------------// SetGetBool//// Sets the state of the bool setting identified by the given name////// Preconditions://// Parameters: name identifies the setting to set or get//// pbool the new value for the bool, or, if null,// it indicates that the caller wants to Get// rather than Set//// Postconditions://// Returns: the prior value of the setting// ---------------------------------------------------------------boolTranslatorSettings::SetGetBool(const char *name, bool *pbool){bool bprevValue;fLock.Lock();const TranSetting *def = FindTranSetting(name);if (def) {fSettingsMsg.FindBool(def->name, &bprevValue);if (pbool)fSettingsMsg.ReplaceBool(def->name, *pbool);} elsebprevValue = false;fLock.Unlock();return bprevValue;}// ---------------------------------------------------------------// SetGetInt32//// Sets the state of the int32 setting identified by the given name////// Preconditions://// Parameters: name identifies the setting to set or get//// pint32 the new value for the setting, or, if null,// it indicates that the caller wants to Get// rather than Set//// Postconditions://// Returns: the prior value of the setting// ---------------------------------------------------------------int32TranslatorSettings::SetGetInt32(const char *name, int32 *pint32){int32 prevValue;fLock.Lock();const TranSetting *def = FindTranSetting(name);if (def) {fSettingsMsg.FindInt32(def->name, &prevValue);if (pint32)fSettingsMsg.ReplaceInt32(def->name, *pint32);} elseprevValue = 0;fLock.Unlock();return prevValue;}