annotate Libs/AceDB-3.0/AceDB-3.0.lua @ 106:e635cd648e01 v49

7.2 update
author yellowfive
date Tue, 28 Mar 2017 16:10:00 -0700
parents 01b63b8ed811
children
rev   line source
yellowfive@57 1 --- **AceDB-3.0** manages the SavedVariables of your addon.
yellowfive@57 2 -- It offers profile management, smart defaults and namespaces for modules.\\
yellowfive@57 3 -- Data can be saved in different data-types, depending on its intended usage.
yellowfive@57 4 -- The most common data-type is the `profile` type, which allows the user to choose
yellowfive@57 5 -- the active profile, and manage the profiles of all of his characters.\\
yellowfive@57 6 -- The following data types are available:
yellowfive@57 7 -- * **char** Character-specific data. Every character has its own database.
yellowfive@57 8 -- * **realm** Realm-specific data. All of the players characters on the same realm share this database.
yellowfive@57 9 -- * **class** Class-specific data. All of the players characters of the same class share this database.
yellowfive@57 10 -- * **race** Race-specific data. All of the players characters of the same race share this database.
yellowfive@57 11 -- * **faction** Faction-specific data. All of the players characters of the same faction share this database.
yellowfive@57 12 -- * **factionrealm** Faction and realm specific data. All of the players characters on the same realm and of the same faction share this database.
yellowfive@106 13 -- * **locale** Locale specific data, based on the locale of the players game client.
yellowfive@57 14 -- * **global** Global Data. All characters on the same account share this database.
yellowfive@57 15 -- * **profile** Profile-specific data. All characters using the same profile share this database. The user can control which profile should be used.
yellowfive@57 16 --
yellowfive@57 17 -- Creating a new Database using the `:New` function will return a new DBObject. A database will inherit all functions
yellowfive@57 18 -- of the DBObjectLib listed here. \\
yellowfive@57 19 -- If you create a new namespaced child-database (`:RegisterNamespace`), you'll get a DBObject as well, but note
yellowfive@57 20 -- that the child-databases cannot individually change their profile, and are linked to their parents profile - and because of that,
yellowfive@57 21 -- the profile related APIs are not available. Only `:RegisterDefaults` and `:ResetProfile` are available on child-databases.
yellowfive@57 22 --
yellowfive@57 23 -- For more details on how to use AceDB-3.0, see the [[AceDB-3.0 Tutorial]].
yellowfive@57 24 --
yellowfive@57 25 -- You may also be interested in [[libdualspec-1-0|LibDualSpec-1.0]] to do profile switching automatically when switching specs.
yellowfive@57 26 --
yellowfive@57 27 -- @usage
yellowfive@57 28 -- MyAddon = LibStub("AceAddon-3.0"):NewAddon("DBExample")
yellowfive@57 29 --
yellowfive@57 30 -- -- declare defaults to be used in the DB
yellowfive@57 31 -- local defaults = {
yellowfive@57 32 -- profile = {
yellowfive@57 33 -- setting = true,
yellowfive@57 34 -- }
yellowfive@57 35 -- }
yellowfive@57 36 --
yellowfive@57 37 -- function MyAddon:OnInitialize()
yellowfive@57 38 -- -- Assuming the .toc says ## SavedVariables: MyAddonDB
yellowfive@57 39 -- self.db = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true)
yellowfive@57 40 -- end
yellowfive@57 41 -- @class file
yellowfive@57 42 -- @name AceDB-3.0.lua
yellowfive@106 43 -- @release $Id: AceDB-3.0.lua 1142 2016-07-11 08:36:19Z nevcairiel $
yellowfive@57 44 local ACEDB_MAJOR, ACEDB_MINOR = "AceDB-3.0", 26
yellowfive@57 45 local AceDB, oldminor = LibStub:NewLibrary(ACEDB_MAJOR, ACEDB_MINOR)
yellowfive@57 46
yellowfive@57 47 if not AceDB then return end -- No upgrade needed
yellowfive@57 48
yellowfive@57 49 -- Lua APIs
yellowfive@57 50 local type, pairs, next, error = type, pairs, next, error
yellowfive@57 51 local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget
yellowfive@57 52
yellowfive@57 53 -- WoW APIs
yellowfive@57 54 local _G = _G
yellowfive@57 55
yellowfive@57 56 -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
yellowfive@57 57 -- List them here for Mikk's FindGlobals script
yellowfive@57 58 -- GLOBALS: LibStub
yellowfive@57 59
yellowfive@57 60 AceDB.db_registry = AceDB.db_registry or {}
yellowfive@57 61 AceDB.frame = AceDB.frame or CreateFrame("Frame")
yellowfive@57 62
yellowfive@57 63 local CallbackHandler
yellowfive@57 64 local CallbackDummy = { Fire = function() end }
yellowfive@57 65
yellowfive@57 66 local DBObjectLib = {}
yellowfive@57 67
yellowfive@57 68 --[[-------------------------------------------------------------------------
yellowfive@57 69 AceDB Utility Functions
yellowfive@57 70 ---------------------------------------------------------------------------]]
yellowfive@57 71
yellowfive@57 72 -- Simple shallow copy for copying defaults
yellowfive@57 73 local function copyTable(src, dest)
yellowfive@57 74 if type(dest) ~= "table" then dest = {} end
yellowfive@57 75 if type(src) == "table" then
yellowfive@57 76 for k,v in pairs(src) do
yellowfive@57 77 if type(v) == "table" then
yellowfive@57 78 -- try to index the key first so that the metatable creates the defaults, if set, and use that table
yellowfive@57 79 v = copyTable(v, dest[k])
yellowfive@57 80 end
yellowfive@57 81 dest[k] = v
yellowfive@57 82 end
yellowfive@57 83 end
yellowfive@57 84 return dest
yellowfive@57 85 end
yellowfive@57 86
yellowfive@57 87 -- Called to add defaults to a section of the database
yellowfive@57 88 --
yellowfive@57 89 -- When a ["*"] default section is indexed with a new key, a table is returned
yellowfive@57 90 -- and set in the host table. These tables must be cleaned up by removeDefaults
yellowfive@57 91 -- in order to ensure we don't write empty default tables.
yellowfive@57 92 local function copyDefaults(dest, src)
yellowfive@57 93 -- this happens if some value in the SV overwrites our default value with a non-table
yellowfive@57 94 --if type(dest) ~= "table" then return end
yellowfive@57 95 for k, v in pairs(src) do
yellowfive@57 96 if k == "*" or k == "**" then
yellowfive@57 97 if type(v) == "table" then
yellowfive@57 98 -- This is a metatable used for table defaults
yellowfive@57 99 local mt = {
yellowfive@57 100 -- This handles the lookup and creation of new subtables
yellowfive@57 101 __index = function(t,k)
yellowfive@57 102 if k == nil then return nil end
yellowfive@57 103 local tbl = {}
yellowfive@57 104 copyDefaults(tbl, v)
yellowfive@57 105 rawset(t, k, tbl)
yellowfive@57 106 return tbl
yellowfive@57 107 end,
yellowfive@57 108 }
yellowfive@57 109 setmetatable(dest, mt)
yellowfive@57 110 -- handle already existing tables in the SV
yellowfive@57 111 for dk, dv in pairs(dest) do
yellowfive@57 112 if not rawget(src, dk) and type(dv) == "table" then
yellowfive@57 113 copyDefaults(dv, v)
yellowfive@57 114 end
yellowfive@57 115 end
yellowfive@57 116 else
yellowfive@57 117 -- Values are not tables, so this is just a simple return
yellowfive@57 118 local mt = {__index = function(t,k) return k~=nil and v or nil end}
yellowfive@57 119 setmetatable(dest, mt)
yellowfive@57 120 end
yellowfive@57 121 elseif type(v) == "table" then
yellowfive@57 122 if not rawget(dest, k) then rawset(dest, k, {}) end
yellowfive@57 123 if type(dest[k]) == "table" then
yellowfive@57 124 copyDefaults(dest[k], v)
yellowfive@57 125 if src['**'] then
yellowfive@57 126 copyDefaults(dest[k], src['**'])
yellowfive@57 127 end
yellowfive@57 128 end
yellowfive@57 129 else
yellowfive@57 130 if rawget(dest, k) == nil then
yellowfive@57 131 rawset(dest, k, v)
yellowfive@57 132 end
yellowfive@57 133 end
yellowfive@57 134 end
yellowfive@57 135 end
yellowfive@57 136
yellowfive@57 137 -- Called to remove all defaults in the default table from the database
yellowfive@57 138 local function removeDefaults(db, defaults, blocker)
yellowfive@57 139 -- remove all metatables from the db, so we don't accidentally create new sub-tables through them
yellowfive@57 140 setmetatable(db, nil)
yellowfive@57 141 -- loop through the defaults and remove their content
yellowfive@57 142 for k,v in pairs(defaults) do
yellowfive@57 143 if k == "*" or k == "**" then
yellowfive@57 144 if type(v) == "table" then
yellowfive@57 145 -- Loop through all the actual k,v pairs and remove
yellowfive@57 146 for key, value in pairs(db) do
yellowfive@57 147 if type(value) == "table" then
yellowfive@57 148 -- if the key was not explicitly specified in the defaults table, just strip everything from * and ** tables
yellowfive@57 149 if defaults[key] == nil and (not blocker or blocker[key] == nil) then
yellowfive@57 150 removeDefaults(value, v)
yellowfive@57 151 -- if the table is empty afterwards, remove it
yellowfive@57 152 if next(value) == nil then
yellowfive@57 153 db[key] = nil
yellowfive@57 154 end
yellowfive@57 155 -- if it was specified, only strip ** content, but block values which were set in the key table
yellowfive@57 156 elseif k == "**" then
yellowfive@57 157 removeDefaults(value, v, defaults[key])
yellowfive@57 158 end
yellowfive@57 159 end
yellowfive@57 160 end
yellowfive@57 161 elseif k == "*" then
yellowfive@57 162 -- check for non-table default
yellowfive@57 163 for key, value in pairs(db) do
yellowfive@57 164 if defaults[key] == nil and v == value then
yellowfive@57 165 db[key] = nil
yellowfive@57 166 end
yellowfive@57 167 end
yellowfive@57 168 end
yellowfive@57 169 elseif type(v) == "table" and type(db[k]) == "table" then
yellowfive@57 170 -- if a blocker was set, dive into it, to allow multi-level defaults
yellowfive@57 171 removeDefaults(db[k], v, blocker and blocker[k])
yellowfive@57 172 if next(db[k]) == nil then
yellowfive@57 173 db[k] = nil
yellowfive@57 174 end
yellowfive@57 175 else
yellowfive@57 176 -- check if the current value matches the default, and that its not blocked by another defaults table
yellowfive@57 177 if db[k] == defaults[k] and (not blocker or blocker[k] == nil) then
yellowfive@57 178 db[k] = nil
yellowfive@57 179 end
yellowfive@57 180 end
yellowfive@57 181 end
yellowfive@57 182 end
yellowfive@57 183
yellowfive@57 184 -- This is called when a table section is first accessed, to set up the defaults
yellowfive@57 185 local function initSection(db, section, svstore, key, defaults)
yellowfive@57 186 local sv = rawget(db, "sv")
yellowfive@57 187
yellowfive@57 188 local tableCreated
yellowfive@57 189 if not sv[svstore] then sv[svstore] = {} end
yellowfive@57 190 if not sv[svstore][key] then
yellowfive@57 191 sv[svstore][key] = {}
yellowfive@57 192 tableCreated = true
yellowfive@57 193 end
yellowfive@57 194
yellowfive@57 195 local tbl = sv[svstore][key]
yellowfive@57 196
yellowfive@57 197 if defaults then
yellowfive@57 198 copyDefaults(tbl, defaults)
yellowfive@57 199 end
yellowfive@57 200 rawset(db, section, tbl)
yellowfive@57 201
yellowfive@57 202 return tableCreated, tbl
yellowfive@57 203 end
yellowfive@57 204
yellowfive@57 205 -- Metatable to handle the dynamic creation of sections and copying of sections.
yellowfive@57 206 local dbmt = {
yellowfive@57 207 __index = function(t, section)
yellowfive@57 208 local keys = rawget(t, "keys")
yellowfive@57 209 local key = keys[section]
yellowfive@57 210 if key then
yellowfive@57 211 local defaultTbl = rawget(t, "defaults")
yellowfive@57 212 local defaults = defaultTbl and defaultTbl[section]
yellowfive@57 213
yellowfive@57 214 if section == "profile" then
yellowfive@57 215 local new = initSection(t, section, "profiles", key, defaults)
yellowfive@57 216 if new then
yellowfive@57 217 -- Callback: OnNewProfile, database, newProfileKey
yellowfive@57 218 t.callbacks:Fire("OnNewProfile", t, key)
yellowfive@57 219 end
yellowfive@57 220 elseif section == "profiles" then
yellowfive@57 221 local sv = rawget(t, "sv")
yellowfive@57 222 if not sv.profiles then sv.profiles = {} end
yellowfive@57 223 rawset(t, "profiles", sv.profiles)
yellowfive@57 224 elseif section == "global" then
yellowfive@57 225 local sv = rawget(t, "sv")
yellowfive@57 226 if not sv.global then sv.global = {} end
yellowfive@57 227 if defaults then
yellowfive@57 228 copyDefaults(sv.global, defaults)
yellowfive@57 229 end
yellowfive@57 230 rawset(t, section, sv.global)
yellowfive@57 231 else
yellowfive@57 232 initSection(t, section, section, key, defaults)
yellowfive@57 233 end
yellowfive@57 234 end
yellowfive@57 235
yellowfive@57 236 return rawget(t, section)
yellowfive@57 237 end
yellowfive@57 238 }
yellowfive@57 239
yellowfive@57 240 local function validateDefaults(defaults, keyTbl, offset)
yellowfive@57 241 if not defaults then return end
yellowfive@57 242 offset = offset or 0
yellowfive@57 243 for k in pairs(defaults) do
yellowfive@57 244 if not keyTbl[k] or k == "profiles" then
yellowfive@57 245 error(("Usage: AceDBObject:RegisterDefaults(defaults): '%s' is not a valid datatype."):format(k), 3 + offset)
yellowfive@57 246 end
yellowfive@57 247 end
yellowfive@57 248 end
yellowfive@57 249
yellowfive@57 250 local preserve_keys = {
yellowfive@57 251 ["callbacks"] = true,
yellowfive@57 252 ["RegisterCallback"] = true,
yellowfive@57 253 ["UnregisterCallback"] = true,
yellowfive@57 254 ["UnregisterAllCallbacks"] = true,
yellowfive@57 255 ["children"] = true,
yellowfive@57 256 }
yellowfive@57 257
yellowfive@57 258 local realmKey = GetRealmName()
yellowfive@57 259 local charKey = UnitName("player") .. " - " .. realmKey
yellowfive@57 260 local _, classKey = UnitClass("player")
yellowfive@57 261 local _, raceKey = UnitRace("player")
yellowfive@57 262 local factionKey = UnitFactionGroup("player")
yellowfive@57 263 local factionrealmKey = factionKey .. " - " .. realmKey
yellowfive@57 264 local localeKey = GetLocale():lower()
yellowfive@57 265
yellowfive@57 266 local regionTable = { "US", "KR", "EU", "TW", "CN" }
yellowfive@57 267 local regionKey = regionTable[GetCurrentRegion()]
yellowfive@57 268 local factionrealmregionKey = factionrealmKey .. " - " .. regionKey
yellowfive@57 269
yellowfive@57 270 -- Actual database initialization function
yellowfive@57 271 local function initdb(sv, defaults, defaultProfile, olddb, parent)
yellowfive@57 272 -- Generate the database keys for each section
yellowfive@57 273
yellowfive@57 274 -- map "true" to our "Default" profile
yellowfive@57 275 if defaultProfile == true then defaultProfile = "Default" end
yellowfive@57 276
yellowfive@57 277 local profileKey
yellowfive@57 278 if not parent then
yellowfive@57 279 -- Make a container for profile keys
yellowfive@57 280 if not sv.profileKeys then sv.profileKeys = {} end
yellowfive@57 281
yellowfive@57 282 -- Try to get the profile selected from the char db
yellowfive@57 283 profileKey = sv.profileKeys[charKey] or defaultProfile or charKey
yellowfive@57 284
yellowfive@57 285 -- save the selected profile for later
yellowfive@57 286 sv.profileKeys[charKey] = profileKey
yellowfive@57 287 else
yellowfive@57 288 -- Use the profile of the parents DB
yellowfive@57 289 profileKey = parent.keys.profile or defaultProfile or charKey
yellowfive@57 290
yellowfive@57 291 -- clear the profileKeys in the DB, namespaces don't need to store them
yellowfive@57 292 sv.profileKeys = nil
yellowfive@57 293 end
yellowfive@57 294
yellowfive@57 295 -- This table contains keys that enable the dynamic creation
yellowfive@57 296 -- of each section of the table. The 'global' and 'profiles'
yellowfive@57 297 -- have a key of true, since they are handled in a special case
yellowfive@57 298 local keyTbl= {
yellowfive@57 299 ["char"] = charKey,
yellowfive@57 300 ["realm"] = realmKey,
yellowfive@57 301 ["class"] = classKey,
yellowfive@57 302 ["race"] = raceKey,
yellowfive@57 303 ["faction"] = factionKey,
yellowfive@57 304 ["factionrealm"] = factionrealmKey,
yellowfive@57 305 ["factionrealmregion"] = factionrealmregionKey,
yellowfive@57 306 ["profile"] = profileKey,
yellowfive@57 307 ["locale"] = localeKey,
yellowfive@57 308 ["global"] = true,
yellowfive@57 309 ["profiles"] = true,
yellowfive@57 310 }
yellowfive@57 311
yellowfive@57 312 validateDefaults(defaults, keyTbl, 1)
yellowfive@57 313
yellowfive@57 314 -- This allows us to use this function to reset an entire database
yellowfive@57 315 -- Clear out the old database
yellowfive@57 316 if olddb then
yellowfive@57 317 for k,v in pairs(olddb) do if not preserve_keys[k] then olddb[k] = nil end end
yellowfive@57 318 end
yellowfive@57 319
yellowfive@57 320 -- Give this database the metatable so it initializes dynamically
yellowfive@57 321 local db = setmetatable(olddb or {}, dbmt)
yellowfive@57 322
yellowfive@57 323 if not rawget(db, "callbacks") then
yellowfive@57 324 -- try to load CallbackHandler-1.0 if it loaded after our library
yellowfive@57 325 if not CallbackHandler then CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0", true) end
yellowfive@57 326 db.callbacks = CallbackHandler and CallbackHandler:New(db) or CallbackDummy
yellowfive@57 327 end
yellowfive@57 328
yellowfive@57 329 -- Copy methods locally into the database object, to avoid hitting
yellowfive@57 330 -- the metatable when calling methods
yellowfive@57 331
yellowfive@57 332 if not parent then
yellowfive@57 333 for name, func in pairs(DBObjectLib) do
yellowfive@57 334 db[name] = func
yellowfive@57 335 end
yellowfive@57 336 else
yellowfive@57 337 -- hack this one in
yellowfive@57 338 db.RegisterDefaults = DBObjectLib.RegisterDefaults
yellowfive@57 339 db.ResetProfile = DBObjectLib.ResetProfile
yellowfive@57 340 end
yellowfive@57 341
yellowfive@57 342 -- Set some properties in the database object
yellowfive@57 343 db.profiles = sv.profiles
yellowfive@57 344 db.keys = keyTbl
yellowfive@57 345 db.sv = sv
yellowfive@57 346 --db.sv_name = name
yellowfive@57 347 db.defaults = defaults
yellowfive@57 348 db.parent = parent
yellowfive@57 349
yellowfive@57 350 -- store the DB in the registry
yellowfive@57 351 AceDB.db_registry[db] = true
yellowfive@57 352
yellowfive@57 353 return db
yellowfive@57 354 end
yellowfive@57 355
yellowfive@57 356 -- handle PLAYER_LOGOUT
yellowfive@57 357 -- strip all defaults from all databases
yellowfive@57 358 -- and cleans up empty sections
yellowfive@57 359 local function logoutHandler(frame, event)
yellowfive@57 360 if event == "PLAYER_LOGOUT" then
yellowfive@57 361 for db in pairs(AceDB.db_registry) do
yellowfive@57 362 db.callbacks:Fire("OnDatabaseShutdown", db)
yellowfive@57 363 db:RegisterDefaults(nil)
yellowfive@57 364
yellowfive@57 365 -- cleanup sections that are empty without defaults
yellowfive@57 366 local sv = rawget(db, "sv")
yellowfive@57 367 for section in pairs(db.keys) do
yellowfive@57 368 if rawget(sv, section) then
yellowfive@57 369 -- global is special, all other sections have sub-entrys
yellowfive@57 370 -- also don't delete empty profiles on main dbs, only on namespaces
yellowfive@57 371 if section ~= "global" and (section ~= "profiles" or rawget(db, "parent")) then
yellowfive@57 372 for key in pairs(sv[section]) do
yellowfive@57 373 if not next(sv[section][key]) then
yellowfive@57 374 sv[section][key] = nil
yellowfive@57 375 end
yellowfive@57 376 end
yellowfive@57 377 end
yellowfive@57 378 if not next(sv[section]) then
yellowfive@57 379 sv[section] = nil
yellowfive@57 380 end
yellowfive@57 381 end
yellowfive@57 382 end
yellowfive@57 383 end
yellowfive@57 384 end
yellowfive@57 385 end
yellowfive@57 386
yellowfive@57 387 AceDB.frame:RegisterEvent("PLAYER_LOGOUT")
yellowfive@57 388 AceDB.frame:SetScript("OnEvent", logoutHandler)
yellowfive@57 389
yellowfive@57 390
yellowfive@57 391 --[[-------------------------------------------------------------------------
yellowfive@57 392 AceDB Object Method Definitions
yellowfive@57 393 ---------------------------------------------------------------------------]]
yellowfive@57 394
yellowfive@57 395 --- Sets the defaults table for the given database object by clearing any
yellowfive@57 396 -- that are currently set, and then setting the new defaults.
yellowfive@57 397 -- @param defaults A table of defaults for this database
yellowfive@57 398 function DBObjectLib:RegisterDefaults(defaults)
yellowfive@57 399 if defaults and type(defaults) ~= "table" then
yellowfive@57 400 error("Usage: AceDBObject:RegisterDefaults(defaults): 'defaults' - table or nil expected.", 2)
yellowfive@57 401 end
yellowfive@57 402
yellowfive@57 403 validateDefaults(defaults, self.keys)
yellowfive@57 404
yellowfive@57 405 -- Remove any currently set defaults
yellowfive@57 406 if self.defaults then
yellowfive@57 407 for section,key in pairs(self.keys) do
yellowfive@57 408 if self.defaults[section] and rawget(self, section) then
yellowfive@57 409 removeDefaults(self[section], self.defaults[section])
yellowfive@57 410 end
yellowfive@57 411 end
yellowfive@57 412 end
yellowfive@57 413
yellowfive@57 414 -- Set the DBObject.defaults table
yellowfive@57 415 self.defaults = defaults
yellowfive@57 416
yellowfive@57 417 -- Copy in any defaults, only touching those sections already created
yellowfive@57 418 if defaults then
yellowfive@57 419 for section,key in pairs(self.keys) do
yellowfive@57 420 if defaults[section] and rawget(self, section) then
yellowfive@57 421 copyDefaults(self[section], defaults[section])
yellowfive@57 422 end
yellowfive@57 423 end
yellowfive@57 424 end
yellowfive@57 425 end
yellowfive@57 426
yellowfive@57 427 --- Changes the profile of the database and all of it's namespaces to the
yellowfive@57 428 -- supplied named profile
yellowfive@57 429 -- @param name The name of the profile to set as the current profile
yellowfive@57 430 function DBObjectLib:SetProfile(name)
yellowfive@57 431 if type(name) ~= "string" then
yellowfive@57 432 error("Usage: AceDBObject:SetProfile(name): 'name' - string expected.", 2)
yellowfive@57 433 end
yellowfive@57 434
yellowfive@57 435 -- changing to the same profile, dont do anything
yellowfive@57 436 if name == self.keys.profile then return end
yellowfive@57 437
yellowfive@57 438 local oldProfile = self.profile
yellowfive@57 439 local defaults = self.defaults and self.defaults.profile
yellowfive@57 440
yellowfive@57 441 -- Callback: OnProfileShutdown, database
yellowfive@57 442 self.callbacks:Fire("OnProfileShutdown", self)
yellowfive@57 443
yellowfive@57 444 if oldProfile and defaults then
yellowfive@57 445 -- Remove the defaults from the old profile
yellowfive@57 446 removeDefaults(oldProfile, defaults)
yellowfive@57 447 end
yellowfive@57 448
yellowfive@57 449 self.profile = nil
yellowfive@57 450 self.keys["profile"] = name
yellowfive@57 451
yellowfive@57 452 -- if the storage exists, save the new profile
yellowfive@57 453 -- this won't exist on namespaces.
yellowfive@57 454 if self.sv.profileKeys then
yellowfive@57 455 self.sv.profileKeys[charKey] = name
yellowfive@57 456 end
yellowfive@57 457
yellowfive@57 458 -- populate to child namespaces
yellowfive@57 459 if self.children then
yellowfive@57 460 for _, db in pairs(self.children) do
yellowfive@57 461 DBObjectLib.SetProfile(db, name)
yellowfive@57 462 end
yellowfive@57 463 end
yellowfive@57 464
yellowfive@57 465 -- Callback: OnProfileChanged, database, newProfileKey
yellowfive@57 466 self.callbacks:Fire("OnProfileChanged", self, name)
yellowfive@57 467 end
yellowfive@57 468
yellowfive@57 469 --- Returns a table with the names of the existing profiles in the database.
yellowfive@57 470 -- You can optionally supply a table to re-use for this purpose.
yellowfive@57 471 -- @param tbl A table to store the profile names in (optional)
yellowfive@57 472 function DBObjectLib:GetProfiles(tbl)
yellowfive@57 473 if tbl and type(tbl) ~= "table" then
yellowfive@57 474 error("Usage: AceDBObject:GetProfiles(tbl): 'tbl' - table or nil expected.", 2)
yellowfive@57 475 end
yellowfive@57 476
yellowfive@57 477 -- Clear the container table
yellowfive@57 478 if tbl then
yellowfive@57 479 for k,v in pairs(tbl) do tbl[k] = nil end
yellowfive@57 480 else
yellowfive@57 481 tbl = {}
yellowfive@57 482 end
yellowfive@57 483
yellowfive@57 484 local curProfile = self.keys.profile
yellowfive@57 485
yellowfive@57 486 local i = 0
yellowfive@57 487 for profileKey in pairs(self.profiles) do
yellowfive@57 488 i = i + 1
yellowfive@57 489 tbl[i] = profileKey
yellowfive@57 490 if curProfile and profileKey == curProfile then curProfile = nil end
yellowfive@57 491 end
yellowfive@57 492
yellowfive@57 493 -- Add the current profile, if it hasn't been created yet
yellowfive@57 494 if curProfile then
yellowfive@57 495 i = i + 1
yellowfive@57 496 tbl[i] = curProfile
yellowfive@57 497 end
yellowfive@57 498
yellowfive@57 499 return tbl, i
yellowfive@57 500 end
yellowfive@57 501
yellowfive@57 502 --- Returns the current profile name used by the database
yellowfive@57 503 function DBObjectLib:GetCurrentProfile()
yellowfive@57 504 return self.keys.profile
yellowfive@57 505 end
yellowfive@57 506
yellowfive@57 507 --- Deletes a named profile. This profile must not be the active profile.
yellowfive@57 508 -- @param name The name of the profile to be deleted
yellowfive@57 509 -- @param silent If true, do not raise an error when the profile does not exist
yellowfive@57 510 function DBObjectLib:DeleteProfile(name, silent)
yellowfive@57 511 if type(name) ~= "string" then
yellowfive@57 512 error("Usage: AceDBObject:DeleteProfile(name): 'name' - string expected.", 2)
yellowfive@57 513 end
yellowfive@57 514
yellowfive@57 515 if self.keys.profile == name then
yellowfive@57 516 error("Cannot delete the active profile in an AceDBObject.", 2)
yellowfive@57 517 end
yellowfive@57 518
yellowfive@57 519 if not rawget(self.profiles, name) and not silent then
yellowfive@57 520 error("Cannot delete profile '" .. name .. "'. It does not exist.", 2)
yellowfive@57 521 end
yellowfive@57 522
yellowfive@57 523 self.profiles[name] = nil
yellowfive@57 524
yellowfive@57 525 -- populate to child namespaces
yellowfive@57 526 if self.children then
yellowfive@57 527 for _, db in pairs(self.children) do
yellowfive@57 528 DBObjectLib.DeleteProfile(db, name, true)
yellowfive@57 529 end
yellowfive@57 530 end
yellowfive@57 531
yellowfive@57 532 -- switch all characters that use this profile back to the default
yellowfive@57 533 if self.sv.profileKeys then
yellowfive@57 534 for key, profile in pairs(self.sv.profileKeys) do
yellowfive@57 535 if profile == name then
yellowfive@57 536 self.sv.profileKeys[key] = nil
yellowfive@57 537 end
yellowfive@57 538 end
yellowfive@57 539 end
yellowfive@57 540
yellowfive@57 541 -- Callback: OnProfileDeleted, database, profileKey
yellowfive@57 542 self.callbacks:Fire("OnProfileDeleted", self, name)
yellowfive@57 543 end
yellowfive@57 544
yellowfive@57 545 --- Copies a named profile into the current profile, overwriting any conflicting
yellowfive@57 546 -- settings.
yellowfive@57 547 -- @param name The name of the profile to be copied into the current profile
yellowfive@57 548 -- @param silent If true, do not raise an error when the profile does not exist
yellowfive@57 549 function DBObjectLib:CopyProfile(name, silent)
yellowfive@57 550 if type(name) ~= "string" then
yellowfive@57 551 error("Usage: AceDBObject:CopyProfile(name): 'name' - string expected.", 2)
yellowfive@57 552 end
yellowfive@57 553
yellowfive@57 554 if name == self.keys.profile then
yellowfive@57 555 error("Cannot have the same source and destination profiles.", 2)
yellowfive@57 556 end
yellowfive@57 557
yellowfive@57 558 if not rawget(self.profiles, name) and not silent then
yellowfive@57 559 error("Cannot copy profile '" .. name .. "'. It does not exist.", 2)
yellowfive@57 560 end
yellowfive@57 561
yellowfive@57 562 -- Reset the profile before copying
yellowfive@57 563 DBObjectLib.ResetProfile(self, nil, true)
yellowfive@57 564
yellowfive@57 565 local profile = self.profile
yellowfive@57 566 local source = self.profiles[name]
yellowfive@57 567
yellowfive@57 568 copyTable(source, profile)
yellowfive@57 569
yellowfive@57 570 -- populate to child namespaces
yellowfive@57 571 if self.children then
yellowfive@57 572 for _, db in pairs(self.children) do
yellowfive@57 573 DBObjectLib.CopyProfile(db, name, true)
yellowfive@57 574 end
yellowfive@57 575 end
yellowfive@57 576
yellowfive@57 577 -- Callback: OnProfileCopied, database, sourceProfileKey
yellowfive@57 578 self.callbacks:Fire("OnProfileCopied", self, name)
yellowfive@57 579 end
yellowfive@57 580
yellowfive@57 581 --- Resets the current profile to the default values (if specified).
yellowfive@57 582 -- @param noChildren if set to true, the reset will not be populated to the child namespaces of this DB object
yellowfive@57 583 -- @param noCallbacks if set to true, won't fire the OnProfileReset callback
yellowfive@57 584 function DBObjectLib:ResetProfile(noChildren, noCallbacks)
yellowfive@57 585 local profile = self.profile
yellowfive@57 586
yellowfive@57 587 for k,v in pairs(profile) do
yellowfive@57 588 profile[k] = nil
yellowfive@57 589 end
yellowfive@57 590
yellowfive@57 591 local defaults = self.defaults and self.defaults.profile
yellowfive@57 592 if defaults then
yellowfive@57 593 copyDefaults(profile, defaults)
yellowfive@57 594 end
yellowfive@57 595
yellowfive@57 596 -- populate to child namespaces
yellowfive@57 597 if self.children and not noChildren then
yellowfive@57 598 for _, db in pairs(self.children) do
yellowfive@57 599 DBObjectLib.ResetProfile(db, nil, noCallbacks)
yellowfive@57 600 end
yellowfive@57 601 end
yellowfive@57 602
yellowfive@57 603 -- Callback: OnProfileReset, database
yellowfive@57 604 if not noCallbacks then
yellowfive@57 605 self.callbacks:Fire("OnProfileReset", self)
yellowfive@57 606 end
yellowfive@57 607 end
yellowfive@57 608
yellowfive@57 609 --- Resets the entire database, using the string defaultProfile as the new default
yellowfive@57 610 -- profile.
yellowfive@57 611 -- @param defaultProfile The profile name to use as the default
yellowfive@57 612 function DBObjectLib:ResetDB(defaultProfile)
yellowfive@57 613 if defaultProfile and type(defaultProfile) ~= "string" then
yellowfive@57 614 error("Usage: AceDBObject:ResetDB(defaultProfile): 'defaultProfile' - string or nil expected.", 2)
yellowfive@57 615 end
yellowfive@57 616
yellowfive@57 617 local sv = self.sv
yellowfive@57 618 for k,v in pairs(sv) do
yellowfive@57 619 sv[k] = nil
yellowfive@57 620 end
yellowfive@57 621
yellowfive@57 622 local parent = self.parent
yellowfive@57 623
yellowfive@57 624 initdb(sv, self.defaults, defaultProfile, self)
yellowfive@57 625
yellowfive@57 626 -- fix the child namespaces
yellowfive@57 627 if self.children then
yellowfive@57 628 if not sv.namespaces then sv.namespaces = {} end
yellowfive@57 629 for name, db in pairs(self.children) do
yellowfive@57 630 if not sv.namespaces[name] then sv.namespaces[name] = {} end
yellowfive@57 631 initdb(sv.namespaces[name], db.defaults, self.keys.profile, db, self)
yellowfive@57 632 end
yellowfive@57 633 end
yellowfive@57 634
yellowfive@57 635 -- Callback: OnDatabaseReset, database
yellowfive@57 636 self.callbacks:Fire("OnDatabaseReset", self)
yellowfive@57 637 -- Callback: OnProfileChanged, database, profileKey
yellowfive@57 638 self.callbacks:Fire("OnProfileChanged", self, self.keys["profile"])
yellowfive@57 639
yellowfive@57 640 return self
yellowfive@57 641 end
yellowfive@57 642
yellowfive@57 643 --- Creates a new database namespace, directly tied to the database. This
yellowfive@57 644 -- is a full scale database in it's own rights other than the fact that
yellowfive@57 645 -- it cannot control its profile individually
yellowfive@57 646 -- @param name The name of the new namespace
yellowfive@57 647 -- @param defaults A table of values to use as defaults
yellowfive@57 648 function DBObjectLib:RegisterNamespace(name, defaults)
yellowfive@57 649 if type(name) ~= "string" then
yellowfive@57 650 error("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - string expected.", 2)
yellowfive@57 651 end
yellowfive@57 652 if defaults and type(defaults) ~= "table" then
yellowfive@57 653 error("Usage: AceDBObject:RegisterNamespace(name, defaults): 'defaults' - table or nil expected.", 2)
yellowfive@57 654 end
yellowfive@57 655 if self.children and self.children[name] then
yellowfive@57 656 error ("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - a namespace with that name already exists.", 2)
yellowfive@57 657 end
yellowfive@57 658
yellowfive@57 659 local sv = self.sv
yellowfive@57 660 if not sv.namespaces then sv.namespaces = {} end
yellowfive@57 661 if not sv.namespaces[name] then
yellowfive@57 662 sv.namespaces[name] = {}
yellowfive@57 663 end
yellowfive@57 664
yellowfive@57 665 local newDB = initdb(sv.namespaces[name], defaults, self.keys.profile, nil, self)
yellowfive@57 666
yellowfive@57 667 if not self.children then self.children = {} end
yellowfive@57 668 self.children[name] = newDB
yellowfive@57 669 return newDB
yellowfive@57 670 end
yellowfive@57 671
yellowfive@57 672 --- Returns an already existing namespace from the database object.
yellowfive@57 673 -- @param name The name of the new namespace
yellowfive@57 674 -- @param silent if true, the addon is optional, silently return nil if its not found
yellowfive@57 675 -- @usage
yellowfive@57 676 -- local namespace = self.db:GetNamespace('namespace')
yellowfive@57 677 -- @return the namespace object if found
yellowfive@57 678 function DBObjectLib:GetNamespace(name, silent)
yellowfive@57 679 if type(name) ~= "string" then
yellowfive@57 680 error("Usage: AceDBObject:GetNamespace(name): 'name' - string expected.", 2)
yellowfive@57 681 end
yellowfive@57 682 if not silent and not (self.children and self.children[name]) then
yellowfive@57 683 error ("Usage: AceDBObject:GetNamespace(name): 'name' - namespace does not exist.", 2)
yellowfive@57 684 end
yellowfive@57 685 if not self.children then self.children = {} end
yellowfive@57 686 return self.children[name]
yellowfive@57 687 end
yellowfive@57 688
yellowfive@57 689 --[[-------------------------------------------------------------------------
yellowfive@57 690 AceDB Exposed Methods
yellowfive@57 691 ---------------------------------------------------------------------------]]
yellowfive@57 692
yellowfive@57 693 --- Creates a new database object that can be used to handle database settings and profiles.
yellowfive@57 694 -- By default, an empty DB is created, using a character specific profile.
yellowfive@57 695 --
yellowfive@57 696 -- You can override the default profile used by passing any profile name as the third argument,
yellowfive@57 697 -- or by passing //true// as the third argument to use a globally shared profile called "Default".
yellowfive@57 698 --
yellowfive@57 699 -- Note that there is no token replacement in the default profile name, passing a defaultProfile as "char"
yellowfive@57 700 -- will use a profile named "char", and not a character-specific profile.
yellowfive@57 701 -- @param tbl The name of variable, or table to use for the database
yellowfive@57 702 -- @param defaults A table of database defaults
yellowfive@57 703 -- @param defaultProfile The name of the default profile. If not set, a character specific profile will be used as the default.
yellowfive@57 704 -- You can also pass //true// to use a shared global profile called "Default".
yellowfive@57 705 -- @usage
yellowfive@57 706 -- -- Create an empty DB using a character-specific default profile.
yellowfive@57 707 -- self.db = LibStub("AceDB-3.0"):New("MyAddonDB")
yellowfive@57 708 -- @usage
yellowfive@57 709 -- -- Create a DB using defaults and using a shared default profile
yellowfive@57 710 -- self.db = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true)
yellowfive@57 711 function AceDB:New(tbl, defaults, defaultProfile)
yellowfive@57 712 if type(tbl) == "string" then
yellowfive@57 713 local name = tbl
yellowfive@57 714 tbl = _G[name]
yellowfive@57 715 if not tbl then
yellowfive@57 716 tbl = {}
yellowfive@57 717 _G[name] = tbl
yellowfive@57 718 end
yellowfive@57 719 end
yellowfive@57 720
yellowfive@57 721 if type(tbl) ~= "table" then
yellowfive@57 722 error("Usage: AceDB:New(tbl, defaults, defaultProfile): 'tbl' - table expected.", 2)
yellowfive@57 723 end
yellowfive@57 724
yellowfive@57 725 if defaults and type(defaults) ~= "table" then
yellowfive@57 726 error("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaults' - table expected.", 2)
yellowfive@57 727 end
yellowfive@57 728
yellowfive@57 729 if defaultProfile and type(defaultProfile) ~= "string" and defaultProfile ~= true then
yellowfive@57 730 error("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaultProfile' - string or true expected.", 2)
yellowfive@57 731 end
yellowfive@57 732
yellowfive@57 733 return initdb(tbl, defaults, defaultProfile)
yellowfive@57 734 end
yellowfive@57 735
yellowfive@57 736 -- upgrade existing databases
yellowfive@57 737 for db in pairs(AceDB.db_registry) do
yellowfive@57 738 if not db.parent then
yellowfive@57 739 for name,func in pairs(DBObjectLib) do
yellowfive@57 740 db[name] = func
yellowfive@57 741 end
yellowfive@57 742 else
yellowfive@57 743 db.RegisterDefaults = DBObjectLib.RegisterDefaults
yellowfive@57 744 db.ResetProfile = DBObjectLib.ResetProfile
yellowfive@57 745 end
yellowfive@57 746 end