1/*****************************************************************************/ 2// TranslatorSettings 3// Written by Michael Wilber, Haiku Translation Kit Team 4// 5// TranslatorSettings.cpp 6// 7// This class manages (saves/loads/locks/unlocks) the settings 8// for a Translator. 9// 10// 11// Copyright (c) 2004 Haiku Project 12// 13// Permission is hereby granted, free of charge, to any person obtaining a 14// copy of this software and associated documentation files (the "Software"), 15// to deal in the Software without restriction, including without limitation 16// the rights to use, copy, modify, merge, publish, distribute, sublicense, 17// and/or sell copies of the Software, and to permit persons to whom the 18// Software is furnished to do so, subject to the following conditions: 19// 20// The above copyright notice and this permission notice shall be included 21// in all copies or substantial portions of the Software. 22// 23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 24// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 26// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 28// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 29// DEALINGS IN THE SOFTWARE. 30/*****************************************************************************/ 31 32#include <string.h> 33#include <File.h> 34#include <FindDirectory.h> 35#include <TranslatorFormats.h> 36 // for B_TRANSLATOR_EXT_* 37#include "TranslatorSettings.h" 38 39// --------------------------------------------------------------- 40// Constructor 41// 42// Sets the default settings, location for the settings file 43// and sets the reference count to 1 44// 45// Preconditions: 46// 47// Parameters: 48// 49// Postconditions: 50// 51// Returns: 52// --------------------------------------------------------------- 53TranslatorSettings::TranslatorSettings(const char *settingsFile, 54 const TranSetting *defaults, int32 defCount) 55 : fLock("TranslatorSettings Lock") 56{ 57 if (find_directory(B_USER_SETTINGS_DIRECTORY, &fSettingsPath)) 58 fSettingsPath.SetTo("/tmp"); 59 fSettingsPath.Append(settingsFile); 60 61 fRefCount = 1; 62 63 if (defCount > 0) { 64 fDefaults = defaults; 65 fDefCount = defCount; 66 } else { 67 fDefaults = NULL; 68 fDefCount = 0; 69 } 70 71 // Add Default Settings 72 // (Used when loading from the settings file or from 73 // a BMessage fails) 74 const TranSetting *defs = fDefaults; 75 for (int32 i = 0; i < fDefCount; i++) { 76 switch (defs[i].dataType) { 77 case TRAN_SETTING_BOOL: 78 fSettingsMsg.AddBool(defs[i].name, 79 static_cast<bool>(defs[i].defaultVal)); 80 break; 81 82 case TRAN_SETTING_INT32: 83 fSettingsMsg.AddInt32(defs[i].name, defs[i].defaultVal); 84 break; 85 86 default: 87 // ASSERT here? Erase the bogus setting entry instead? 88 break; 89 } 90 } 91} 92 93// --------------------------------------------------------------- 94// Acquire 95// 96// Returns a pointer to the TranslatorSettings and increments 97// the reference count. 98// 99// Preconditions: 100// 101// Parameters: 102// 103// Postconditions: 104// 105// Returns: pointer to this TranslatorSettings object 106// --------------------------------------------------------------- 107TranslatorSettings * 108TranslatorSettings::Acquire() 109{ 110 TranslatorSettings *psettings = NULL; 111 112 fLock.Lock(); 113 fRefCount++; 114 psettings = this; 115 fLock.Unlock(); 116 117 return psettings; 118} 119 120// --------------------------------------------------------------- 121// Release 122// 123// Decrements the reference count and deletes the 124// TranslatorSettings if the reference count is zero. 125// 126// Preconditions: 127// 128// Parameters: 129// 130// Postconditions: 131// 132// Returns: pointer to this TranslatorSettings object if 133// the reference count is greater than zero, returns NULL 134// if the reference count is zero and the TranslatorSettings 135// object has been deleted 136// --------------------------------------------------------------- 137TranslatorSettings * 138TranslatorSettings::Release() 139{ 140 TranslatorSettings *psettings = NULL; 141 142 fLock.Lock(); 143 fRefCount--; 144 if (fRefCount > 0) { 145 psettings = this; 146 fLock.Unlock(); 147 } else 148 delete this; 149 // delete this object and 150 // release locks 151 152 return psettings; 153} 154 155// --------------------------------------------------------------- 156// Destructor 157// 158// Does nothing! 159// 160// Preconditions: 161// 162// Parameters: 163// 164// Postconditions: 165// 166// Returns: 167// --------------------------------------------------------------- 168TranslatorSettings::~TranslatorSettings() 169{ 170} 171 172// --------------------------------------------------------------- 173// LoadSettings 174// 175// Loads the settings by reading them from the default 176// settings file. 177// 178// Preconditions: 179// 180// Parameters: 181// 182// Postconditions: 183// 184// Returns: B_OK if there were no errors or an error code from 185// BFile::SetTo() or BMessage::Unflatten() if there were errors 186// --------------------------------------------------------------- 187status_t 188TranslatorSettings::LoadSettings() 189{ 190 status_t result; 191 192 fLock.Lock(); 193 194 // Don't try to open the settings file if there are 195 // no settings that need to be loaded 196 if (fDefCount > 0) { 197 BFile settingsFile; 198 result = settingsFile.SetTo(fSettingsPath.Path(), B_READ_ONLY); 199 if (result == B_OK) { 200 BMessage msg; 201 result = msg.Unflatten(&settingsFile); 202 if (result == B_OK) 203 result = LoadSettings(&msg); 204 } 205 } else 206 result = B_OK; 207 208 fLock.Unlock(); 209 210 return result; 211} 212 213// --------------------------------------------------------------- 214// LoadSettings 215// 216// Loads the settings from a BMessage passed to the function. 217// 218// Preconditions: 219// 220// Parameters: pmsg pointer to BMessage that contains the 221// settings 222// 223// Postconditions: 224// 225// Returns: B_BAD_VALUE if pmsg is NULL or invalid options 226// have been found, B_OK if there were no 227// errors or an error code from BMessage::FindBool() or 228// BMessage::ReplaceBool() if there were other errors 229// --------------------------------------------------------------- 230status_t 231TranslatorSettings::LoadSettings(BMessage *pmsg) 232{ 233 if (pmsg == NULL) 234 return B_BAD_VALUE; 235 236 fLock.Lock(); 237 const TranSetting *defaults = fDefaults; 238 for (int32 i = 0; i < fDefCount; i++) { 239 switch (defaults[i].dataType) { 240 case TRAN_SETTING_BOOL: 241 { 242 bool value; 243 if (pmsg->FindBool(defaults[i].name, &value) != B_OK) { 244 if (fSettingsMsg.HasBool(defaults[i].name)) 245 break; 246 else 247 value = static_cast<bool>(defaults[i].defaultVal); 248 } 249 250 fSettingsMsg.ReplaceBool(defaults[i].name, value); 251 break; 252 } 253 254 case TRAN_SETTING_INT32: 255 { 256 int32 value; 257 if (pmsg->FindInt32(defaults[i].name, &value) != B_OK) { 258 if (fSettingsMsg.HasInt32(defaults[i].name)) 259 break; 260 else 261 value = defaults[i].defaultVal; 262 } 263 264 fSettingsMsg.ReplaceInt32(defaults[i].name, value); 265 break; 266 } 267 268 default: 269 // TODO: ASSERT here? Erase the bogus setting entry instead? 270 break; 271 } 272 } 273 274 fLock.Unlock(); 275 return B_OK; 276} 277 278// --------------------------------------------------------------- 279// SaveSettings 280// 281// Saves the settings as a flattened BMessage to the default 282// settings file 283// 284// Preconditions: 285// 286// Parameters: 287// 288// Postconditions: 289// 290// Returns: B_OK if no errors or an error code from BFile::SetTo() 291// or BMessage::Flatten() if there were errors 292// --------------------------------------------------------------- 293status_t 294TranslatorSettings::SaveSettings() 295{ 296 status_t result; 297 298 fLock.Lock(); 299 300 // Only write out settings file if there are 301 // actual settings stored by this object 302 if (fDefCount > 0) { 303 BFile settingsFile; 304 result = settingsFile.SetTo(fSettingsPath.Path(), 305 B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 306 if (result == B_OK) 307 result = fSettingsMsg.Flatten(&settingsFile); 308 } else 309 result = B_OK; 310 311 fLock.Unlock(); 312 313 return result; 314} 315 316// --------------------------------------------------------------- 317// GetConfigurationMessage 318// 319// Saves the current settings to the BMessage passed to the 320// function 321// 322// Preconditions: 323// 324// Parameters: pmsg pointer to BMessage where the settings 325// will be stored 326// 327// Postconditions: 328// 329// Returns: B_OK if there were no errors or an error code from 330// BMessage::RemoveName() or BMessage::AddBool() if there were 331// errors 332// --------------------------------------------------------------- 333status_t 334TranslatorSettings::GetConfigurationMessage(BMessage *pmsg) 335{ 336 status_t result = B_BAD_VALUE; 337 338 if (pmsg) { 339 int32 i; 340 for (i = 0; i < fDefCount; i++) { 341 result = pmsg->RemoveName(fDefaults[i].name); 342 if (result != B_OK && result != B_NAME_NOT_FOUND) 343 break; 344 } 345 if (i == fDefCount) { 346 fLock.Lock(); 347 result = B_OK; 348 349 const TranSetting *defs = fDefaults; 350 for (i = 0; i < fDefCount && result >= B_OK; i++) { 351 switch (defs[i].dataType) { 352 case TRAN_SETTING_BOOL: 353 result = pmsg->AddBool(defs[i].name, 354 SetGetBool(defs[i].name)); 355 break; 356 357 case TRAN_SETTING_INT32: 358 result = pmsg->AddInt32(defs[i].name, 359 SetGetInt32(defs[i].name)); 360 break; 361 362 default: 363 // ASSERT here? Erase the bogus setting entry instead? 364 break; 365 } 366 } 367 368 fLock.Unlock(); 369 } 370 } 371 372 return result; 373} 374 375// --------------------------------------------------------------- 376// FindTranSetting 377// 378// Returns a pointer to the TranSetting with the given name 379// 380// 381// Preconditions: 382// 383// Parameters: name name of the TranSetting to find 384// 385// 386// Postconditions: 387// 388// Returns: NULL if the TranSetting cannot be found, or a pointer 389// to the desired TranSetting if it is found 390// --------------------------------------------------------------- 391const TranSetting * 392TranslatorSettings::FindTranSetting(const char *name) 393{ 394 for (int32 i = 0; i < fDefCount; i++) { 395 if (!strcmp(fDefaults[i].name, name)) 396 return fDefaults + i; 397 } 398 return NULL; 399} 400 401// --------------------------------------------------------------- 402// SetGetBool 403// 404// Sets the state of the bool setting identified by the given name 405// 406// 407// Preconditions: 408// 409// Parameters: name identifies the setting to set or get 410// 411// pbool the new value for the bool, or, if null, 412// it indicates that the caller wants to Get 413// rather than Set 414// 415// Postconditions: 416// 417// Returns: the prior value of the setting 418// --------------------------------------------------------------- 419bool 420TranslatorSettings::SetGetBool(const char *name, bool *pbool) 421{ 422 bool bprevValue; 423 424 fLock.Lock(); 425 426 const TranSetting *def = FindTranSetting(name); 427 if (def) { 428 fSettingsMsg.FindBool(def->name, &bprevValue); 429 if (pbool) 430 fSettingsMsg.ReplaceBool(def->name, *pbool); 431 } else 432 bprevValue = false; 433 434 fLock.Unlock(); 435 436 return bprevValue; 437} 438 439// --------------------------------------------------------------- 440// SetGetInt32 441// 442// Sets the state of the int32 setting identified by the given name 443// 444// 445// Preconditions: 446// 447// Parameters: name identifies the setting to set or get 448// 449// pint32 the new value for the setting, or, if null, 450// it indicates that the caller wants to Get 451// rather than Set 452// 453// Postconditions: 454// 455// Returns: the prior value of the setting 456// --------------------------------------------------------------- 457int32 458TranslatorSettings::SetGetInt32(const char *name, int32 *pint32) 459{ 460 int32 prevValue; 461 462 fLock.Lock(); 463 464 const TranSetting *def = FindTranSetting(name); 465 if (def) { 466 fSettingsMsg.FindInt32(def->name, &prevValue); 467 if (pint32) 468 fSettingsMsg.ReplaceInt32(def->name, *pint32); 469 } else 470 prevValue = 0; 471 472 fLock.Unlock(); 473 474 return prevValue; 475} 476 477