annotate Libs/AceDB-3.0/AceDB-3.0.lua @ 11:371e14cd2feb

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