settings.cpp
Engine/source/util/settings.cpp
Public Functions
ConsoleDocClass(Settings , "@brief Class used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> writing out preferences and settings <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">editors\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> editors or internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a> " " @internal" )
DefineEngineMethod(Settings , beginGroup , void , (const char *groupName, bool includeDefaults) , (false) , "settingObj.beginGroup(groupName, fromStart = false);" )
DefineEngineMethod(Settings , clearGroups , void , () , "settingObj.clearGroups();" )
DefineEngineMethod(Settings , endGroup , void , () , "settingObj.endGroup();" )
DefineEngineMethod(Settings , findFirstValue , const char * , (const char *pattern, bool deepSearch, bool includeDefaults) , ("", false, false) , "settingObj.findFirstValue();" )
DefineEngineMethod(Settings , findNextValue , const char * , () , "settingObj.findNextValue();" )
DefineEngineMethod(Settings , getCurrentGroups , const char * , () , "settingObj.getCurrentGroups();" )
DefineEngineMethod(Settings , read , bool , () )
DefineEngineMethod(Settings , remove , void , (const char *settingName, bool includeDefaults) , (false) , "settingObj.remove(settingName, includeDefaults = false);" )
DefineEngineMethod(Settings , value , const char * , (const char *settingName, const char *defaultValue) , ("") , "settingObj.value(settingName, <a href="/coding/file/pointer_8h/#pointer_8h_1a3db30c1795eb39d4452f8698f4a67f05">defaultValue</a>);" )
DefineEngineMethod(Settings , write , bool , () )
Detailed Description
Public Functions
ConsoleDocClass(Settings , "@brief Class used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> writing out preferences and settings <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">editors\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> editors or internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a> " " @internal" )
DefineEngineMethod(Settings , beginGroup , void , (const char *groupName, bool includeDefaults) , (false) , "settingObj.beginGroup(groupName, fromStart = false);" )
DefineEngineMethod(Settings , clearGroups , void , () , "settingObj.clearGroups();" )
DefineEngineMethod(Settings , endGroup , void , () , "settingObj.endGroup();" )
DefineEngineMethod(Settings , findFirstValue , const char * , (const char *pattern, bool deepSearch, bool includeDefaults) , ("", false, false) , "settingObj.findFirstValue();" )
DefineEngineMethod(Settings , findNextValue , const char * , () , "settingObj.findNextValue();" )
DefineEngineMethod(Settings , getCurrentGroups , const char * , () , "settingObj.getCurrentGroups();" )
DefineEngineMethod(Settings , read , bool , () )
DefineEngineMethod(Settings , remove , void , (const char *settingName, bool includeDefaults) , (false) , "settingObj.remove(settingName, includeDefaults = false);" )
DefineEngineMethod(Settings , setDefaultValue , void , (const char *settingName, const char *value) , "settingObj.setDefaultValue(settingName, <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a>);" )
DefineEngineMethod(Settings , setValue , void , (const char *settingName, const char *value) , ("") , "settingObj.setValue(settingName, <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a>);" )
DefineEngineMethod(Settings , value , const char * , (const char *settingName, const char *defaultValue) , ("") , "settingObj.value(settingName, <a href="/coding/file/pointer_8h/#pointer_8h_1a3db30c1795eb39d4452f8698f4a67f05">defaultValue</a>);" )
DefineEngineMethod(Settings , write , bool , () )
IMPLEMENT_CONOBJECT(Settings )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "util/settings.h" 25#include "console/engineAPI.h" 26#include "console/consoleTypes.h" 27#include "console/SimXMLDocument.h" 28 29IMPLEMENT_CONOBJECT(Settings); 30 31ConsoleDocClass( Settings, 32 "@brief Class used for writing out preferences and settings for editors\n\n" 33 "Not intended for game development, for editors or internal use only.\n\n " 34 "@internal"); 35 36Settings::Settings() 37{ 38 mFile = ""; 39 mSearchPos = 0; 40} 41 42Settings::~Settings() 43{ 44 45} 46 47void Settings::initPersistFields() 48{ 49 addField("file", TypeStringFilename, Offset(mFile, Settings), "The file path and name to be saved to and loaded from."); 50 51 Parent::initPersistFields(); 52} 53 54void Settings::setDefaultValue(const UTF8 *settingName, const UTF8 *settingValue, const UTF8 *settingType) 55{ 56 String baseName; 57 buildGroupString(baseName, settingName); 58 String name = baseName + "_default"; 59 StringTableEntry nameEntry = StringTable->insert(name.c_str()); 60 String type = baseName + "_type"; 61 StringTableEntry typeEntry = StringTable->insert(type.c_str()); 62 63 setModStaticFields(false); 64 setDataField(nameEntry, NULL, settingValue); 65 setDataField(typeEntry, NULL, settingType); 66 setModStaticFields(true); 67} 68 69void Settings::setValue(const UTF8 *settingName, const UTF8 *settingValue) 70{ 71 String name; 72 buildGroupString(name, settingName); 73 StringTableEntry nameEntry = StringTable->insert(name.c_str()); 74 75 setModStaticFields(false); 76 setDataField(nameEntry, NULL, settingValue); 77 setModStaticFields(true); 78} 79 80const UTF8 *Settings::value(const UTF8 *settingName, const UTF8 *defaultValue) 81{ 82 String name; 83 buildGroupString(name, settingName); 84 85 StringTableEntry nameEntry = StringTable->insert(name.c_str()); 86 name += "_default"; 87 StringTableEntry defaultNameEntry = StringTable->insert(name.c_str()); 88 89 // we do this setModStaticFields call to make sure our get/set calls 90 // don't grab a regular field, don't want to stomp anything 91 setModStaticFields(false); 92 const UTF8 *value = getDataField(nameEntry, NULL); 93 const UTF8 *storedDefaultValue = getDataField(defaultNameEntry, NULL); 94 setModStaticFields(true); 95 96 if(String::compare(value, "") != 0) 97 return value; 98 else if(String::compare(storedDefaultValue, "") != 0) 99 return storedDefaultValue; 100 else 101 return defaultValue; 102} 103 104void Settings::remove(const UTF8 *settingName, bool includeDefaults) 105{ 106 // Fetch Dynamic-Field Dictionary. 107 SimFieldDictionary* pFieldDictionary = getFieldDictionary(); 108 109 // Any Field Dictionary? 110 if ( pFieldDictionary == NULL ) 111 { 112 // No, so we're done. 113 return; 114 } 115 116 String name; 117 buildGroupString(name, settingName); 118 StringTableEntry nameEntry = StringTable->insert(name.c_str()); 119 StringTableEntry nameEntryDefault = StringTable->insert( String::ToString("%s%s",name.c_str(), "_default") ); 120 121 // Iterate fields. 122 for ( SimFieldDictionaryIterator itr(pFieldDictionary); *itr; ++itr ) 123 { 124 // Fetch Field Entry. 125 SimFieldDictionary::Entry* fieldEntry = *itr; 126 127 // is this a field of our current group 128 if ( (String::compare(nameEntry, "") == 0) || 129 String::compare( nameEntry, fieldEntry->slotName ) == 0 || 130 (includeDefaults && String::compare( nameEntryDefault, fieldEntry->slotName ) == 0) ) 131 { 132 // Yes, so remove it. 133 pFieldDictionary->setFieldValue( fieldEntry->slotName, "" ); 134 } 135 } 136} 137 138void Settings::buildGroupString(String &name, const UTF8 *settingName) 139{ 140 // here we want to loop through the stack and build a "/" seperated string 141 // representing the entire current group stack that gets pre-pended to the 142 // setting name passed in 143 if(mGroupStack.size() > 0) 144 { 145 for(S32 i=0; i < mGroupStack.size(); i++) 146 { 147 S32 pos = 0; 148 if(name.size() > 0) 149 pos = name.size()-1; 150 151 // tack on the "/" in front if this isn't the first 152 if(i == 0) 153 { 154 name.insert(pos, mGroupStack[i]); 155 } 156 else 157 { 158 name.insert(pos, "/"); 159 name.insert(pos+1, mGroupStack[i]); 160 } 161 } 162 163 // tack on a final "/" 164 name.insert(name.size()-1, "/"); 165 if(dStrlen(settingName) > 0) 166 name.insert(name.size()-1, settingName); 167 } 168 else 169 { 170 name = settingName; 171 } 172} 173 174void Settings::clearAllFields() 175{ 176 // Fetch Dynamic-Field Dictionary. 177 SimFieldDictionary* pFieldDictionary = getFieldDictionary(); 178 179 // Any Field Dictionary? 180 if ( pFieldDictionary == NULL ) 181 { 182 // No, so we're done. 183 return; 184 } 185 186 // Iterate fields. 187 for ( SimFieldDictionaryIterator itr(pFieldDictionary); *itr; ++itr ) 188 { 189 // Fetch Field Entry. 190 SimFieldDictionary::Entry* fieldEntry = *itr; 191 192 // don't remove default field values 193 if (dStrEndsWith(fieldEntry->slotName, "_default")) 194 continue; 195 196 // remove it. 197 pFieldDictionary->setFieldValue( fieldEntry->slotName, "" ); 198 } 199} 200 201bool Settings::write() 202{ 203 // Fetch Dynamic-Field Dictionary. 204 SimFieldDictionary* pFieldDictionary = getFieldDictionary(); 205 206 // Any Field Dictionary? 207 if ( pFieldDictionary == NULL ) 208 { 209 // No, so we're done. 210 return false; 211 } 212 213/* 214 // Iterate fields. 215 for ( SimFieldDictionaryIterator itr(pFieldDictionary); *itr; ++itr ) 216 { 217 // Fetch Field Entry. 218 SimFieldDictionary::Entry* fieldEntry = *itr; 219 220 String check(fieldEntry->slotName); 221 String::SizeType pos = check.find("_default"); 222 if(pos != String::NPos) 223 continue; 224 225 // let's build our XML doc 226 document->pushNewElement("dynamicField"); 227 document->setAttribute("name", fieldEntry->slotName); 228 document->addText(fieldEntry->value); 229 document->popElement(); 230 } 231*/ 232 SimXMLDocument *document = new SimXMLDocument(); 233 document->registerObject(); 234 document->addHeader(); 235 236 document->pushNewElement(getName()); 237 238 SettingSaveNode *node = new SettingSaveNode(); 239 // Iterate fields. 240 for ( SimFieldDictionaryIterator itr(pFieldDictionary); *itr; ++itr ) 241 { 242 // Fetch Field Entry. 243 SimFieldDictionary::Entry* fieldEntry = *itr; 244 245 String check(fieldEntry->slotName); 246 if(check.find("_default") != String::NPos || check.find("_type") != String::NPos) 247 continue; 248 249 node->addValue(fieldEntry->slotName, fieldEntry->value); 250 } 251 252 node->buildDocument(document, true); 253 node->clear(); 254 delete node; 255 256 bool saved = document->saveFile(mFile.c_str()); 257 document->deleteObject(); 258 259 if(saved) 260 return true; 261 else 262 return false; 263} 264 265bool Settings::read() 266{ 267 SimXMLDocument *document = new SimXMLDocument(); 268 document->registerObject(); 269 270 bool success = true; 271 if(document->loadFile(mFile.c_str())) 272 { 273 clearAllFields(); 274 275 // set our base element 276 if(document->pushFirstChildElement(getName())) 277 { 278 setModStaticFields(false); 279 readLayer(document); 280 setModStaticFields(true); 281 } 282 else 283 success = false; 284 } 285 else 286 success = false; 287 288 document->deleteObject(); 289 290 return success; 291} 292 293void Settings::readLayer(SimXMLDocument *document, String groupStack) 294{ 295 for(S32 i=0; document->pushChildElement(i); i++) 296 { 297 const UTF8 *type = document->elementValue(); 298 const UTF8 *name = document->attribute("name"); 299 const UTF8 *value = document->getText(); 300 301 if(String::compare(type, "Group") == 0) 302 { 303 String newStack = groupStack; 304 305 if(!groupStack.isEmpty()) 306 newStack += "/"; 307 308 newStack += name; 309 readLayer(document, newStack); 310 } else if(String::compare(type, "Setting") == 0) 311 { 312 String nameString = groupStack; 313 314 if(!groupStack.isEmpty()) 315 nameString += "/"; 316 317 nameString += name; 318 setDataField(StringTable->insert(nameString.c_str()), NULL, value); 319 } 320 321 document->popElement(); 322 } 323} 324 325void Settings::beginGroup(const UTF8 *groupName, bool fromStart) 326{ 327 // check if we want to clear the stack 328 if(fromStart) 329 clearGroups(); 330 331 mGroupStack.push_back(String(groupName)); 332} 333 334void Settings::endGroup() 335{ 336 if(mGroupStack.size() > 0) 337 mGroupStack.pop_back(); 338} 339 340void Settings::clearGroups() 341{ 342 mGroupStack.clear(); 343} 344 345const UTF8 *Settings::getCurrentGroups() 346{ 347 // we want to return a string with our group setup 348 String returnString; 349 for(S32 i=0; i<mGroupStack.size(); i++) 350 { 351 S32 pos = returnString.size() - 1; 352 if(pos < 0) 353 pos = 0; 354 355 if(i == 0) 356 { 357 returnString.insert(pos, mGroupStack[i]); 358 } else 359 { 360 returnString.insert(pos, "/"); 361 returnString.insert(pos+1, mGroupStack[i]); 362 } 363 } 364 365 return StringTable->insert(returnString.c_str()); 366} 367/* 368S32 Settings::buildSearchList( const char* pattern, bool deepSearch, bool includeDefaults ) 369{ 370 mSearchResults.clear(); 371 372 SimFieldDictionary* fieldDictionary = getFieldDictionary(); 373 // Get the dynamic field count 374 if ( !fieldDictionary ) 375 return -1; 376 377 for (SimFieldDictionaryIterator itr(fieldDictionary); *itr; ++itr) 378 { 379 // Fetch Field Entry. 380 SimFieldDictionary::Entry* fieldEntry = *itr; 381 382 // Compare strings, store proper results in vector 383 String extendedPath = String::ToString(fieldEntry->slotName); 384 String::SizeType start(0); 385 String::SizeType slashPos = extendedPath.find('/', 0, String::Right); 386 String shortPath = extendedPath.substr( start, slashPos ); 387 388 if( deepSearch ) 389 { 390 if( shortPath.find( pattern ) != -1 ) 391 { 392 if( !includeDefaults && extendedPath.find("_default") != -1 ) 393 continue; 394 395 String listMember = String::ToString(fieldEntry->value); 396 listMember.insert(start, " " ); 397 listMember.insert(start, String::ToString(fieldEntry->slotName) ); 398 399 mSearchResults.push_back( listMember ); 400 } 401 } 402 else 403 { 404 if( shortPath.compare( pattern ) == 0 ) 405 { 406 if( !includeDefaults && extendedPath.find("_default") != -1 ) 407 continue; 408 409 String listMember = String::ToString(fieldEntry->value); 410 listMember.insert(start, " " ); 411 listMember.insert(start, String::ToString(fieldEntry->slotName) ); 412 413 mSearchResults.push_back( listMember ); 414 } 415 } 416 } 417 418 return mSearchResults.size(); 419} 420*/ 421const char* Settings::findFirstValue( const char* pattern, bool deepSearch, bool includeDefaults ) 422{ 423 mSearchResults.clear(); 424 425 SimFieldDictionary* fieldDictionary = getFieldDictionary(); 426 // Get the dynamic field count 427 if ( !fieldDictionary ) 428 return ""; 429 430 for (SimFieldDictionaryIterator itr(fieldDictionary); *itr; ++itr) 431 { 432 // Fetch Field Entry. 433 SimFieldDictionary::Entry* fieldEntry = *itr; 434 435 // Compare strings, store proper results in vector 436 String extendedPath = String::ToString(fieldEntry->slotName); 437 String::SizeType start(0); 438 String::SizeType slashPos = extendedPath.find('/', 0, String::Right); 439 String shortPath = extendedPath.substr( start, slashPos ); 440 441 if( deepSearch ) 442 { 443 if( shortPath.find( pattern ) != -1 ) 444 { 445 if( !includeDefaults && extendedPath.find("_default") != -1 ) 446 continue; 447 448 String listMember = String::ToString(fieldEntry->slotName); 449 //listMember.insert(start, " " ); 450 //listMember.insert(start, String::ToString(fieldEntry->slotName) ); 451 452 mSearchResults.push_back( listMember ); 453 } 454 } 455 else 456 { 457 if( shortPath.compare( pattern ) == 0 ) 458 { 459 if( !includeDefaults && extendedPath.find("_default") != -1 ) 460 continue; 461 462 String listMember = String::ToString(fieldEntry->slotName); 463 //listMember.insert(start, " " ); 464 //listMember.insert(start, String::ToString(fieldEntry->slotName) ); 465 466 mSearchResults.push_back( listMember ); 467 } 468 } 469 } 470 471 if( mSearchResults.size() < 1 ) 472 { 473 Con::errorf("findFirstValue() : Pattern not found"); 474 return ""; 475 } 476 477 mSearchPos = 0; 478 return mSearchResults[mSearchPos]; 479} 480 481const char* Settings::findNextValue() 482{ 483 if ( mSearchPos + 1 >= mSearchResults.size() ) 484 return ""; 485 mSearchPos++; 486 return mSearchResults[mSearchPos]; 487} 488 489// make sure to replace the strings 490DefineEngineMethod(Settings, findFirstValue, const char*, ( const char* pattern, bool deepSearch, bool includeDefaults ), ("", false, false), "settingObj.findFirstValue();") 491{ 492 return object->findFirstValue( pattern, deepSearch, includeDefaults ); 493} 494 495DefineEngineMethod(Settings, findNextValue, const char*, (), , "settingObj.findNextValue();") 496{ 497 return object->findNextValue(); 498} 499/* 500ConsoleMethod(Settings, buildSearchList, void, 2, 2, "settingObj.buildSearchList();") 501{ 502 object->buildSearchList( "foobar" ); 503} 504*/ 505void SettingSaveNode::addValue(const UTF8 *name, const UTF8 *value) 506{ 507 String nameString(name); 508 S32 groupCount = getGroupCount(nameString); 509 SettingSaveNode *parentNode = this; 510 511 // let's check to make sure all these groups exist already 512 for(S32 i=0; i<groupCount; i++) 513 { 514 String groupName = getGroup(nameString, i); 515 if(!groupName.isEmpty()) 516 { 517 bool found = false; 518 // loop through all of our nodes to find if this one exists, 519 // if it does we want to use it 520 for(S32 j=0; j<parentNode->mGroupNodes.size(); j++) 521 { 522 SettingSaveNode *node = parentNode->mGroupNodes[j]; 523 524 if(!node->mIsGroup) 525 continue; 526 527 if(node->mName.compare(groupName) == 0) 528 { 529 parentNode = node; 530 found = true; 531 break; 532 } 533 } 534 535 // not found, so we create it 536 if(!found) 537 { 538 SettingSaveNode *node = new SettingSaveNode(groupName, true); 539 parentNode->mGroupNodes.push_back(node); 540 parentNode = node; 541 } 542 } 543 } 544 545 // now we can properly set our actual value 546 String settingNameString = getSettingName(name); 547 String valueString(value); 548 SettingSaveNode *node = new SettingSaveNode(settingNameString, valueString); 549 parentNode->mSettingNodes.push_back(node); 550} 551 552S32 SettingSaveNode::getGroupCount(const String &name) 553{ 554 String::SizeType pos = 0; 555 S32 count = 0; 556 557 // loop through and count our exiting groups 558 while(pos != String::NPos) 559 { 560 pos = name.find("/", pos + 1); 561 if(pos != String::NPos) 562 count++; 563 } 564 565 return count; 566} 567 568String SettingSaveNode::getGroup(const String &name, S32 num) 569{ 570 String::SizeType pos = 0; 571 String::SizeType lastPos = 0; 572 S32 count = 0; 573 574 while(pos != String::NPos) 575 { 576 lastPos = pos; 577 pos = name.find("/", pos + 1); 578 579 if(count == num) 580 { 581 String::SizeType startPos = lastPos; 582 583 if(count > 0) 584 startPos++; 585 586 if(pos == String::NPos) 587 return name.substr(startPos, name.length() - (startPos)); 588 else 589 return name.substr(startPos, pos - startPos); 590 } 591 592 count++; 593 } 594 595 return String(""); 596} 597 598String SettingSaveNode::getSettingName(const String &name) 599{ 600 String::SizeType pos = name.find("/", 0, String::Right); 601 602 if(pos == String::NPos) 603 return String(name); 604 else 605 return name.substr(pos+1, name.length() - (pos+1)); 606} 607 608void SettingSaveNode::clear() 609{ 610 for( U32 i = 0, num = mGroupNodes.size(); i < num; ++ i ) 611 delete mGroupNodes[ i ]; 612 for( U32 i = 0, num = mSettingNodes.size(); i < num; ++ i ) 613 delete mSettingNodes[ i ]; 614 615 mGroupNodes.clear(); 616 mSettingNodes.clear(); 617} 618 619void SettingSaveNode::buildDocument(SimXMLDocument *document, bool skipWrite) 620{ 621 // let's build our XML doc 622 if(mIsGroup && !skipWrite) 623 { 624 document->pushNewElement("Group"); 625 document->setAttribute("name", mName); 626 } 627 628 if(!mIsGroup && !skipWrite) 629 { 630 document->pushNewElement("Setting"); 631 document->setAttribute("name", mName); 632 document->addText(mValue); 633 } 634 else 635 { 636 mSettingNodes.sort(_NodeCompare); 637 mGroupNodes.sort(_NodeCompare); 638 639 for(S32 i=0; i<mSettingNodes.size(); i++) 640 { 641 SettingSaveNode *node = mSettingNodes[i]; 642 node->buildDocument(document); 643 } 644 645 for(S32 i=0; i<mGroupNodes.size(); i++) 646 { 647 SettingSaveNode *node = mGroupNodes[i]; 648 node->buildDocument(document); 649 } 650 } 651 652 if(!skipWrite) 653 document->popElement(); 654} 655 656S32 QSORT_CALLBACK SettingSaveNode::_NodeCompare(SettingSaveNode* const* a, SettingSaveNode* const* b) 657{ 658 S32 result = dStrnatcasecmp((*a)->mName.c_str(), (*b)->mName.c_str()); 659 return result; 660} 661 662DefineEngineMethod(Settings, setValue, void, (const char * settingName, const char * value), (""), "settingObj.setValue(settingName, value);") 663{ 664 StringTableEntry fieldName = StringTable->insert( settingName ); 665 666 if (!String::isEmpty(value)) 667 object->setValue( fieldName, value ); 668 else 669 object->setValue( fieldName ); 670} 671 672DefineEngineMethod(Settings, setDefaultValue, void, (const char * settingName, const char * value), , "settingObj.setDefaultValue(settingName, value);") 673{ 674 StringTableEntry fieldName = StringTable->insert( settingName ); 675 object->setDefaultValue( fieldName, value ); 676} 677 678DefineEngineMethod(Settings, value, const char*, (const char * settingName, const char * defaultValue), (""), "settingObj.value(settingName, defaultValue);") 679{ 680 StringTableEntry fieldName = StringTable->insert( settingName ); 681 682 if (String::compare(defaultValue, "") != 0) 683 return object->value( fieldName, defaultValue ); 684 else if (String::compare(settingName, "") != 0) 685 return object->value( fieldName ); 686 687 return ""; 688} 689 690DefineEngineMethod(Settings, remove, void, (const char * settingName, bool includeDefaults), (false), "settingObj.remove(settingName, includeDefaults = false);") 691{ 692 // there's a problem with some fields not being removed properly, but works if you run it twice, 693 // a temporary solution for now is simply to call the remove twice 694 695 object->remove( settingName, includeDefaults ); 696 object->remove( settingName, includeDefaults ); 697} 698 699DefineEngineMethod(Settings, write, bool, (),, "%success = settingObj.write();") 700{ 701 return object->write(); 702} 703 704DefineEngineMethod(Settings, read, bool, (), , "%success = settingObj.read();") 705{ 706 return object->read(); 707} 708 709DefineEngineMethod(Settings, beginGroup, void, (const char * groupName, bool includeDefaults), (false), "settingObj.beginGroup(groupName, fromStart = false);") 710{ 711 object->beginGroup( groupName, includeDefaults ); 712} 713 714DefineEngineMethod(Settings, endGroup, void, (), , "settingObj.endGroup();") 715{ 716 object->endGroup(); 717} 718 719DefineEngineMethod(Settings, clearGroups, void, (), , "settingObj.clearGroups();") 720{ 721 object->clearGroups(); 722} 723 724DefineEngineMethod(Settings, getCurrentGroups, const char*, (), , "settingObj.getCurrentGroups();") 725{ 726 return object->getCurrentGroups(); 727} 728