--[[ Name: AceDB-2.0 Revision: $Rev: 10447 $ Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) Inspired By: Ace 1.x by Turan (turan@gryphon.com) Website: http://www.wowace.com/ Documentation: http://www.wowace.com/index.php/AceDB-2.0 SVN: http://svn.wowace.com/root/trunk/Ace2/AceDB-2.0 Description: Mixin to allow for fast, clean, and featureful saved variable access. Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0 ]] local MAJOR_VERSION = "AceDB-2.0" local MINOR_VERSION = "$Revision: 10447 $" if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end -- localize -- local ACTIVE = "Active" local ENABLED = "Enabled" local STATE = "State" local TOGGLE_ACTIVE = "Suspend/resume this addon" local MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Active|r", [false] = "|cffff0000Suspended|r" } local SET_PROFILE = "Set profile for this addon" local SET_PROFILE_USAGE = "{char || class || realm || }" local PROFILE = "Profile" local PLAYER_OF_REALM = "%s of %s" -- localize -- local AceOO = AceLibrary("AceOO-2.0") local AceEvent local Mixin = AceOO.Mixin local AceDB = Mixin { "RegisterDB", "RegisterDefaults", "ResetDB", "SetProfile", "GetProfile", "ToggleActive", "IsActive", "AcquireDBNamespace", } local Dewdrop = AceLibrary:HasInstance("Dewdrop-2.0") and AceLibrary("Dewdrop-2.0") local _G = getfenv(0) local function inheritDefaults(t, defaults) if not defaults then return t end for k,v in pairs(defaults) do if k == "*" then local v = v if type(v) == "table" then setmetatable(t, { __index = function(self, key) if key == nil then return nil end self[key] = {} inheritDefaults(self[key], v) return self[key] end } ) else setmetatable(t, { __index = function(self, key) if key == nil then return nil end self[key] = v return self[key] end } ) end for key in pairs(t) do if (defaults[key] == nil or key == "*") and type(t[key]) == "table" then inheritDefaults(t[key], v) end end else if type(v) == "table" then if type(t[k]) ~= "table" then t[k] = {} end inheritDefaults(t[k], v) elseif t[k] == nil then t[k] = v end end end return t end local _,race = UnitRace("player") local faction if race == "Orc" or race == "Scourge" or race == "Troll" or race == "Tauren" then faction = FACTION_HORDE else faction = FACTION_ALLIANCE end local charID = string.format(PLAYER_OF_REALM, UnitName("player"), (string.gsub(GetRealmName(), "^%s*(.-)%s*$", "%1"))) local realm = string.gsub(GetRealmName(), "^%s*(.-)%s*$", "%1") local realmID = realm .. " - " .. faction local classID = UnitClass("player") AceDB.CHAR_ID = charID AceDB.REALM_ID = realmID AceDB.CLASS_ID = classID AceDB.FACTION = faction AceDB.REALM = realm AceDB.NAME = UnitName("player") local new, del do local list = setmetatable({}, {__mode="k"}) function new() local t = next(list) if t then list[t] = nil return t else return {} end end function del(t) setmetatable(t, nil) for k in pairs(t) do t[k] = nil end table.setn(t, 0) list[t] = true end end local caseInsensitive_mt = { __index = function(self, key) if type(key) ~= "string" then return nil end local lowerKey = string.lower(key) for k,v in pairs(self) do if string.lower(k) == lowerKey then return self[k] end end end, __newindex = function(self, key, value) if type(key) ~= "string" then return error("table index is nil", 2) end local lowerKey = string.lower(key) for k in pairs(self) do if string.lower(k) == lowerKey then rawset(self, k, nil) rawset(self, key, value) return end end rawset(self, key, value) end } local db_mt = { __index = function(db, key) if key == "char" then if db.charName then if type(_G[db.charName]) ~= "table" then _G[db.charName] = {} end if type(_G[db.charName].global) ~= "table" then _G[db.charName].global = {} end rawset(db, 'char', _G[db.charName].global) else if type(db.raw.chars) ~= "table" then db.raw.chars = {} end local id = charID if type(db.raw.chars[id]) ~= "table" then db.raw.chars[id] = {} end rawset(db, 'char', db.raw.chars[id]) end if db.defaults and db.defaults.char then inheritDefaults(db.char, db.defaults.char) end return db.char elseif key == "realm" then if type(db.raw.realms) ~= "table" then db.raw.realms = {} end local id = realmID if type(db.raw.realms[id]) ~= "table" then db.raw.realms[id] = {} end rawset(db, 'realm', db.raw.realms[id]) if db.defaults and db.defaults.realm then inheritDefaults(db.realm, db.defaults.realm) end return db.realm elseif key == "account" then if type(db.raw.account) ~= "table" then db.raw.account = {} end rawset(db, 'account', db.raw.account) if db.defaults and db.defaults.account then inheritDefaults(db.account, db.defaults.account) end return db.account elseif key == "class" then if type(db.raw.classes) ~= "table" then db.raw.classes = {} end local id = classID if type(db.raw.classes[id]) ~= "table" then db.raw.classes[id] = {} end rawset(db, 'class', db.raw.classes[id]) if db.defaults and db.defaults.class then inheritDefaults(db.class, db.defaults.class) end return db.class elseif key == "profile" then if type(db.raw.profiles) ~= "table" then db.raw.profiles = setmetatable({}, caseInsensitive_mt) else setmetatable(db.raw.profiles, caseInsensitive_mt) end local id = db.raw.currentProfile[charID] if id == "char" then id = "char/" .. charID elseif id == "class" then id = "class/" .. classID elseif id == "realm" then id = "realm/" .. realmID end if type(db.raw.profiles[id]) ~= "table" then db.raw.profiles[id] = {} end rawset(db, 'profile', db.raw.profiles[id]) if db.defaults and db.defaults.profile then inheritDefaults(db.profile, db.defaults.profile) end return db.profile elseif key == "raw" or key == "defaults" or key == "name" or key == "charName" or key == "namespaces" then return nil end error(string.format('Cannot access key %q in db table. You may want to use db.profile[%q]', tostring(key), tostring(key)), 2) end, __newindex = function(db, key, value) error(string.format('Cannot access key %q in db table. You may want to use db.profile[%q]', tostring(key), tostring(key)), 2) end } local CrawlForSerialization local CrawlForDeserialization local function SerializeObject(o) local t = { o:Serialize() } t[0] = o.class:GetLibraryVersion() CrawlForSerialization(t) return t end local function DeserializeObject(t) CrawlForDeserialization(t) local className = t[0] for i = 20, 1, -1 do if t[i] then t.n = i break end end local o = AceLibrary(className):Deserialize(unpack(t)) t.n = 0 return o end local function IsSerializable(t) return AceOO.inherits(t, AceOO.Class) and t.class and type(t.class.Deserialize) == "function" and type(t.Serialize) == "function" and type(t.class.GetLibraryVersion) == "function" end function CrawlForSerialization(t) local tmp = new() for k,v in pairs(t) do tmp[k] = v end for k,v in pairs(tmp) do if type(v) == "table" and type(v[0]) ~= "userdata" then if IsSerializable(v) then v = SerializeObject(v) t[k] = v else CrawlForSerialization(v) end end if type(k) == "table" and type(k[0]) ~= "userdata" then if IsSerializable(k) then t[k] = nil t[SerializeObject(k)] = v else CrawlForSerialization(k) end end tmp[k] = nil k = nil end tmp = del(tmp) end local function IsDeserializable(t) return type(t[0]) == "string" and AceLibrary:HasInstance(t[0]) end function CrawlForDeserialization(t) local tmp = new() for k,v in pairs(t) do tmp[k] = v end for k,v in pairs(tmp) do if type(v) == "table" then if IsDeserializable(v) then t[k] = DeserializeObject(v) del(v) v = t[k] elseif type(v[0]) ~= "userdata" then CrawlForDeserialization(v) end end if type(k) == "table" then if IsDeserializable(k) then t[k] = nil t[DeserializeObject(k)] = v del(k) elseif type(k[0]) ~= "userdata" then CrawlForDeserialization(k) end end tmp[k] = nil k = nil end tmp = del(tmp) end local namespace_mt = { __index = function(namespace, key) local db = namespace.db local name = namespace.name if key == "char" then if db.charName then if type(_G[db.charName]) ~= "table" then _G[db.charName] = {} end if type(_G[db.charName].namespaces) ~= "table" then _G[db.charName].namespaces = {} end if type(_G[db.charName].namespaces[name]) ~= "table" then _G[db.charName].namespaces[name] = {} end rawset(namespace, 'char', _G[db.charName].namespaces[name]) else if type(db.raw.namespaces) ~= "table" then db.raw.namespaces = {} end if type(db.raw.namespaces[name]) ~= "table" then db.raw.namespaces[name] = {} end if type(db.raw.namespaces[name].chars) ~= "table" then db.raw.namespaces[name].chars = {} end local id = charID if type(db.raw.namespaces[name].chars[id]) ~= "table" then db.raw.namespaces[name].chars[id] = {} end rawset(namespace, 'char', db.raw.namespaces[name].chars[id]) end if namespace.defaults and namespace.defaults.char then inheritDefaults(namespace.char, namespace.defaults.char) end return namespace.char elseif key == "realm" then if type(db.raw.namespaces) ~= "table" then db.raw.namespaces = {} end if type(db.raw.namespaces[name]) ~= "table" then db.raw.namespaces[name] = {} end if type(db.raw.namespaces[name].realms) ~= "table" then db.raw.namespaces[name].realms = {} end local id = realmID if type(db.raw.namespaces[name].realms[id]) ~= "table" then db.raw.namespaces[name].realms[id] = {} end rawset(namespace, 'realm', db.raw.namespaces[name].realms[id]) if namespace.defaults and namespace.defaults.realm then inheritDefaults(namespace.realm, namespace.defaults.realm) end return namespace.realm elseif key == "account" then if type(db.raw.namespaces) ~= "table" then db.raw.namespaces = {} end if type(db.raw.namespaces[name]) ~= "table" then db.raw.namespaces[name] = {} end if type(db.raw.namespaces[name].account) ~= "table" then db.raw.namespaces[name].account = {} end rawset(namespace, 'account', db.raw.namespaces[name].account) if namespace.defaults and namespace.defaults.account then inheritDefaults(namespace.account, namespace.defaults.account) end return namespace.account elseif key == "class" then if type(db.raw.namespaces) ~= "table" then db.raw.namespaces = {} end if type(db.raw.namespaces[name]) ~= "table" then db.raw.namespaces[name] = {} end if type(db.raw.namespaces[name].classes) ~= "table" then db.raw.namespaces[name].classes = {} end local id = classID if type(db.raw.namespaces[name].classes[id]) ~= "table" then db.raw.namespaces[name].classes[id] = {} end rawset(namespace, 'class', db.raw.namespaces[name].classes[id]) if namespace.defaults and namespace.defaults.class then inheritDefaults(namespace.class, namespace.defaults.class) end return namespace.class elseif key == "profile" then if type(db.raw.namespaces) ~= "table" then db.raw.namespaces = {} end if type(db.raw.namespaces[name]) ~= "table" then db.raw.namespaces[name] = {} end if type(db.raw.namespaces[name].profiles) ~= "table" then db.raw.namespaces[name].profiles = setmetatable({}, caseInsensitive_mt) else setmetatable(db.raw.namespaces[name].profiles, caseInsensitive_mt) end local id = db.raw.currentProfile[charID] if id == "char" then id = "char/" .. charID elseif id == "class" then id = "class/" .. classID elseif id == "realm" then id = "realm/" .. realmID end if type(db.raw.namespaces[name].profiles[id]) ~= "table" then db.raw.namespaces[name].profiles[id] = {} end rawset(namespace, 'profile', db.raw.namespaces[name].profiles[id]) if namespace.defaults and namespace.defaults.profile then inheritDefaults(namespace.profile, namespace.defaults.profile) end return namespace.profile elseif key == "defaults" or key == "name" or key == "db" then return nil end error(string.format('Cannot access key %q in db table. You may want to use db.profile[%q]', tostring(key), tostring(key)), 2) end, __newindex = function(db, key, value) error(string.format('Cannot access key %q in db table. You may want to use db.profile[%q]', tostring(key), tostring(key)), 2) end } function AceDB:InitializeDB(addonName) local db = self.db if not db then if addonName then AceDB.addonsLoaded[addonName] = true end return end if db.raw then -- someone manually initialized return end if type(_G[db.name]) ~= "table" then _G[db.name] = {} else CrawlForDeserialization(_G[db.name]) end if type(_G[db.charName]) == "table" then CrawlForDeserialization(_G[db.charName]) end rawset(db, 'raw', _G[db.name]) if not db.raw.currentProfile then db.raw.currentProfile = {} end if not db.raw.currentProfile[charID] then db.raw.currentProfile[charID] = "Default" end if db.raw.disabled then setmetatable(db.raw.disabled, caseInsensitive_mt) end if self['acedb-profile-copylist'] then local t = self['acedb-profile-copylist'] for k,v in pairs(t) do t[k] = nil end if db.raw.profiles then for k in pairs(db.raw.profiles) do if string.find(k, '^char/') then local name = string.sub(k, 6) if name ~= charID then t[k] = 'Character: ' .. name end elseif string.find(k, '^realm/') then local name = string.sub(k, 7) if name ~= realmID then t[k] = 'Realm: ' .. name end elseif string.find(k, '^class/') then local name = string.sub(k, 7) if name ~= classID then t[k] = 'Class: ' .. name end end end end end if self['acedb-profile-list'] then local t = self['acedb-profile-list'] for k,v in pairs(t) do t[k] = nil end t.char = 'Character: ' .. charID t.realm = 'Realm: ' .. realmID t.class = 'Class: ' .. classID t.Default = "Default" if db.raw.profiles then for k in pairs(db.raw.profiles) do if not string.find(k, '^char/') and not string.find(k, '^realm/') and not string.find(k, '^class/') then t[k] = k end end end end setmetatable(db, db_mt) end function AceDB:OnEmbedInitialize(target, name) if name then self:ADDON_LOADED(name) end self.InitializeDB(target, name) end function AceDB:RegisterDB(name, charName) AceDB:argCheck(name, 2, "string") AceDB:argCheck(charName, 3, "string", "nil") if self.db then AceDB:error("Cannot call \"RegisterDB\" if self.db is set.") end local stack = debugstack() local addonName = string.gsub(stack, ".-\n.-\\AddOns\\(.-)\\.*", "%1") self.db = { name = name, charName = charName } if AceDB.addonsLoaded[addonName] then AceDB.InitializeDB(self, addonName) else AceDB.addonsToBeInitialized[self] = addonName end AceDB.registry[self] = true end function AceDB:RegisterDefaults(kind, defaults, a3) local name if a3 then name, kind, defaults = kind, defaults, a3 AceDB:argCheck(name, 2, "string") AceDB:argCheck(kind, 3, "string") AceDB:argCheck(defaults, 4, "table") if kind ~= "char" and kind ~= "class" and kind ~= "profile" and kind ~= "account" and kind ~= "realm" then AceDB:error("Bad argument #3 to `RegisterDefaults' (\"char\", \"class\", \"profile\", \"account\", or \"realm\" expected, got %q)", kind) end else AceDB:argCheck(kind, 2, "string") AceDB:argCheck(defaults, 3, "table") if kind ~= "char" and kind ~= "class" and kind ~= "profile" and kind ~= "account" and kind ~= "realm" then AceDB:error("Bad argument #2 to `RegisterDefaults' (\"char\", \"class\", \"profile\", \"account\", or \"realm\" expected, got %q)", kind) end end if type(self.db) ~= "table" or type(self.db.name) ~= "string" then AceDB:error("Cannot call \"RegisterDefaults\" unless \"RegisterDB\" has been previously called.") end local db if name then local namespace = self:AcquireDBNamespace(name) if namespace.defaults and namespace.defaults[kind] then AceDB:error("\"RegisterDefaults\" has already been called for %q::%q.", name, kind) end db = namespace else if self.db.defaults and self.db.defaults[kind] then AceDB:error("\"RegisterDefaults\" has already been called for %q.", kind) end db = self.db end if not db.defaults then rawset(db, 'defaults', {}) end db.defaults[kind] = defaults if rawget(db, kind) then inheritDefaults(db[kind], defaults) end end function AceDB:ResetDB(kind) AceDB:argCheck(kind, 2, "nil", "string") if not self.db or not self.db.raw then AceDB:error("Cannot call \"ResetDB\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.") end local db = self.db if kind == nil then if db.charName then _G[db.charName] = nil end _G[db.name] = nil rawset(db, 'raw', nil) AceDB.InitializeDB(self) if db.namespaces then for name,v in pairs(db.namespaces) do rawset(v, 'account', nil) rawset(v, 'char', nil) rawset(v, 'class', nil) rawset(v, 'profile', nil) rawset(v, 'realm', nil) end end elseif kind == "account" then db.raw.account = nil rawset(db, 'account', nil) if db.namespaces then for name,v in pairs(db.namespaces) do rawset(v, 'account', nil) end end elseif kind == "char" then if db.charName then _G[db.charName] = nil else if db.raw.chars then db.raw.chars[charID] = nil end if db.raw.namespaces then for name,v in pairs(db.raw.namespaces) do if v.chars then v.chars[charID] = nil end end end end rawset(db, 'char', nil) if db.namespaces then for name,v in pairs(db.namespaces) do rawset(v, 'char', nil) end end elseif kind == "realm" then if db.raw.realms then db.raw.realms[realmID] = nil end rawset(db, 'realm', nil) if db.raw.namespaces then for name,v in pairs(db.raw.namespaces) do if v.realms then v.realms[realmID] = nil end end end if db.namespaces then for name,v in pairs(db.namespaces) do rawset(v, 'realm', nil) end end elseif kind == "class" then if db.raw.realms then db.raw.realms[classID] = nil end rawset(db, 'class', nil) if db.raw.namespaces then for name,v in pairs(db.raw.namespaces) do if v.classes then v.classes[classID] = nil end end end if db.namespaces then for name,v in pairs(db.namespaces) do rawset(v, 'class', nil) end end elseif kind == "profile" then local id = db.raw.currentProfile and db.raw.currentProfile[charID] or "Default" if id == "char" then id = "char/" .. charID elseif id == "class" then id = "class/" .. classID elseif id == "realm" then id = "realm/" .. realmID end if db.raw.profiles then db.raw.profiles[id] = nil end rawset(db, 'profile', nil) if db.raw.namespaces then for name,v in pairs(db.raw.namespaces) do if v.profiles then v.profiles[id] = nil end end end if db.namespaces then for name,v in pairs(db.namespaces) do rawset(v, 'profile', nil) end end end end local function cleanDefaults(t, defaults) if defaults then for k,v in pairs(defaults) do if k == "*" then if type(v) == "table" then for k in pairs(t) do if (defaults[k] == nil or k == "*") and type(t[k]) == "table" then if cleanDefaults(t[k], v) then t[k] = nil end end end else for k in pairs(t) do if (defaults[k] == nil or k == "*") and t[k] == v then t[k] = nil end end end else if type(v) == "table" then if type(t[k]) == "table" then if cleanDefaults(t[k], v) then t[k] = nil end end elseif t[k] == v then t[k] = nil end end end end return t and not next(t) end function AceDB:GetProfile() if not self.db or not self.db.raw then return nil end if not self.db.raw.currentProfile then self.db.raw.currentProfile = {} end if not self.db.raw.currentProfile[charID] then self.db.raw.currentProfile[charID] = "Default" end local profile = self.db.raw.currentProfile[charID] if profile == "char" then return "char", "char/" .. charID elseif profile == "class" then return "class", "class/" .. classID elseif profile == "realm" then return "realm", "realm/" .. realmID end return profile, profile end local function copyTable(to, from) setmetatable(to, nil) for k,v in pairs(from) do if type(k) == "table" then k = copyTable({}, k) end if type(v) == "table" then v = copyTable({}, v) end to[k] = v end table.setn(to, table.getn(from)) setmetatable(to, from) return to end function AceDB:SetProfile(name, copyFrom) AceDB:argCheck(name, 2, "string") AceDB:argCheck(copyFrom, 3, "string", "nil") if not self.db or not self.db.raw then AceDB:error("Cannot call \"SetProfile\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.") end local db = self.db local copy = false local lowerName = string.lower(name) local lowerCopyFrom = copyFrom and string.lower(copyFrom) if string.sub(lowerName, 1, 5) == "char/" or string.sub(lowerName, 1, 6) == "realm/" or string.sub(lowerName, 1, 6) == "class/" then if string.sub(lowerName, 1, 5) == "char/" then name, copyFrom = "char", name else name, copyFrom = string.sub(lowerName, 1, 5), name end lowerName = string.lower(name) lowerCopyFrom = string.lower(copyFrom) end if copyFrom then if string.sub(lowerCopyFrom, 1, 5) == "char/" then AceDB:assert(lowerName == "char", "If argument #3 starts with `char/', argument #2 must be `char'") elseif string.sub(lowerCopyFrom, 1, 6) == "realm/" then AceDB:assert(lowerName == "realm", "If argument #3 starts with `realm/', argument #2 must be `realm'") elseif string.sub(lowerCopyFrom, 1, 6) == "class/" then AceDB:assert(lowerName == "class", "If argument #3 starts with `class/', argument #2 must be `class'") else AceDB:assert(lowerName ~= "char" and lowerName ~= "realm" and lowerName ~= "class", "If argument #3 does not start with a special prefix, that prefix cannot be copied to.") end if not db.raw.profiles or not db.raw.profiles[copyFrom] then AceDB:error("Cannot copy profile %q, it does not exist.", copyFrom) elseif (string.sub(lowerName, 1, 5) == "char/" and string.sub(lowerName, 6) == string.lower(charID)) or (string.sub(lowerName, 1, 6) == "realm/" and string.sub(lowerName, 7) == string.lower(realmID)) or (string.sub(lowerName, 1, 6) == "class/" and string.sub(lowerName, 7) == string.lower(classID)) then AceDB:error("Cannot copy profile %q, it is currently in use.", name) end end local oldName = db.raw.currentProfile[charID] if string.lower(oldName) == string.lower(name) then return end local current = self.class while current and current ~= AceOO.Class do if current.mixins then for mixin in pairs(current.mixins) do if type(mixin.OnEmbedProfileDisable) == "function" then mixin:OnEmbedProfileDisable(self) end end end current = current.super end if type(self.OnProfileDisable) == "function" then self:OnProfileDisable() end local oldProfileData = db.profile local realName = name if lowerName == "char" then realName = name .. "/" .. charID elseif lowerName == "realm/" then realName = name .. "/" .. realmID elseif lowerName == "class/" then realName = name .. "/" .. classID end local active = self:IsActive() db.raw.currentProfile[charID] = name rawset(db, 'profile', nil) if copyFrom then for k,v in pairs(db.profile) do db.profile[k] = nil end copyTable(db.profile, db.raw.profiles[copyFrom]) inheritDefaults(db.profile, db.defaults and db.defaults.profile) end local current = self.class while current and current ~= AceOO.Class do if current.mixins then for mixin in pairs(current.mixins) do if type(mixin.OnEmbedProfileEnable) == "function" then mixin:OnEmbedProfileEnable(self, oldName, oldProfileData, copyFrom) end end end current = current.super end if type(self.OnProfileEnable) == "function" then self:OnProfileEnable(oldName, oldProfileData, copyFrom) end if cleanDefaults(oldProfileData, db.defaults and db.defaults.profile) then db.raw.profiles[oldName] = nil if not next(db.raw.profiles) then db.raw.profiles = nil end end local newactive = self:IsActive() if active ~= newactive then if AceOO.inherits(self, "AceAddon-2.0") then local AceAddon = AceLibrary("AceAddon-2.0") if not AceAddon.addonsStarted[self] then return end end if newactive then local current = self.class while current and current ~= AceOO.Class do if current.mixins then for mixin in pairs(current.mixins) do if type(mixin.OnEmbedEnable) == "function" then mixin:OnEmbedEnable(self) end end end current = current.super end if type(self.OnEnable) == "function" then self:OnEnable() end else local current = self.class while current and current ~= AceOO.Class do if current.mixins then for mixin in pairs(current.mixins) do if type(mixin.OnEmbedDisable) == "function" then mixin:OnEmbedDisable(self) end end end current = current.super end if type(self.OnDisable) == "function" then self:OnDisable() end end end if self['acedb-profile-list'] then if not self['acedb-profile-list'][name] then self['acedb-profile-list'][name] = name end end if Dewdrop then Dewdrop:Refresh(1) Dewdrop:Refresh(2) Dewdrop:Refresh(3) Dewdrop:Refresh(4) Dewdrop:Refresh(5) end end function AceDB:IsActive() return not self.db or not self.db.raw or not self.db.raw.disabled or not self.db.raw.disabled[self.db.raw.currentProfile[charID]] end function AceDB:ToggleActive(state) AceDB:argCheck(state, 2, "boolean", "nil") if not self.db or not self.db.raw then AceDB:error("Cannot call \"ToggleActive\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.") end local db = self.db if not db.raw.disabled then db.raw.disabled = setmetatable({}, caseInsensitive_mt) end local profile = db.raw.currentProfile[charID] local disable if state == nil then disable = not db.raw.disabled[profile] else disable = not state if disable == db.raw.disabled[profile] then return end end db.raw.disabled[profile] = disable or nil if AceOO.inherits(self, "AceAddon-2.0") then local AceAddon = AceLibrary("AceAddon-2.0") if not AceAddon.addonsStarted[self] then return end end if not disable then local current = self.class while current and current ~= AceOO.Class do if current.mixins then for mixin in pairs(current.mixins) do if type(mixin.OnEmbedEnable) == "function" then mixin:OnEmbedEnable(self) end end end current = current.super end if type(self.OnEnable) == "function" then self:OnEnable() end else local current = self.class while current and current ~= AceOO.Class do if current.mixins then for mixin in pairs(current.mixins) do if type(mixin.OnEmbedDisable) == "function" then mixin:OnEmbedDisable(self) end end end current = current.super end if type(self.OnDisable) == "function" then self:OnDisable() end end return not disable end function AceDB:embed(target) self.super.embed(self, target) if not AceEvent then AceDB:error(MAJOR_VERSION .. " requires AceEvent-2.0") end end function AceDB:ADDON_LOADED(name) AceDB.addonsLoaded[name] = true for addon, addonName in pairs(AceDB.addonsToBeInitialized) do if name == addonName then AceDB.InitializeDB(addon, name) AceDB.addonsToBeInitialized[addon] = nil end end end function AceDB:PLAYER_LOGOUT() for addon in pairs(AceDB.registry) do local db = addon.db if db then setmetatable(db, nil) CrawlForSerialization(db.raw) if type(_G[db.charName]) == "table" then CrawlForSerialization(_G[db.charName]) end if db.char and cleanDefaults(db.char, db.defaults and db.defaults.char) then if db.charName and _G[db.charName] and _G[db.charName].global == db.char then _G[db.charName].global = nil if not next(_G[db.charName]) then _G[db.charName] = nil end else if db.raw.chars then db.raw.chars[charID] = nil if not next(db.raw.chars) then db.raw.chars = nil end end end end if db.realm and cleanDefaults(db.realm, db.defaults and db.defaults.realm) then if db.raw.realms then db.raw.realms[realmID] = nil if not next(db.raw.realms) then db.raw.realms = nil end end end if db.class and cleanDefaults(db.class, db.defaults and db.defaults.class) then if db.raw.classes then db.raw.classes[classID] = nil if not next(db.raw.classes) then db.raw.classes = nil end end end if db.account and cleanDefaults(db.account, db.defaults and db.defaults.account) then db.raw.account = nil end if db.profile and cleanDefaults(db.profile, db.defaults and db.defaults.profile) then if db.raw.profiles then db.raw.profiles[db.raw.currentProfile and db.raw.currentProfile[charID] or "Default"] = nil if not next(db.raw.profiles) then db.raw.profiles = nil end end end if db.namespaces and db.raw.namespaces then for name,v in pairs(db.namespaces) do if db.raw.namespaces[name] then setmetatable(v, nil) if v.char and cleanDefaults(v.char, v.defaults and v.defaults.char) then if db.charName and _G[db.charName] and _G[db.charName].namespaces and _G[db.charName].namespaces[name] == v then _G[db.charName].namespaces[name] = nil if not next(_G[db.charName].namespaces) then _G[db.charName].namespaces = nil if not next(_G[db.charName]) then _G[db.charName] = nil end end else if db.raw.namespaces[name].chars then db.raw.namespaces[name].chars[charID] = nil if not next(db.raw.namespaces[name].chars) then db.raw.namespaces[name].chars = nil end end end end if v.realm and cleanDefaults(v.realm, v.defaults and v.defaults.realm) then if db.raw.namespaces[name].realms then db.raw.namespaces[name].realms[realmID] = nil if not next(db.raw.namespaces[name].realms) then db.raw.namespaces[name].realms = nil end end end if v.class and cleanDefaults(v.class, v.defaults and v.defaults.class) then if db.raw.namespaces[name].classes then db.raw.namespaces[name].classes[classID] = nil if not next(db.raw.namespaces[name].classes) then db.raw.namespaces[name].classes = nil end end end if v.account and cleanDefaults(v.account, v.defaults and v.defaults.account) then db.raw.namespaces[name].account = nil end if v.profile and cleanDefaults(v.profile, v.defaults and v.defaults.profile) then if db.raw.namespaces[name].profiles then db.raw.namespaces[name].profiles[db.raw.currentProfile and db.raw.currentProfile[charID] or "Default"] = nil if not next(db.raw.namespaces[name].profiles) then db.raw.namespaces[name].profiles = nil end end end if not next(db.raw.namespaces[name]) then db.raw.namespaces[name] = nil end end end if not next(db.raw.namespaces) then db.raw.namespaces = nil end end if db.raw.disabled and not next(db.raw.disabled) then db.raw.disabled = nil end if db.raw.currentProfile then for k,v in pairs(db.raw.currentProfile) do if string.lower(v) == "default" then db.raw.currentProfile[k] = nil end end if not next(db.raw.currentProfile) then db.raw.currentProfile = nil end end if _G[db.name] and not next(_G[db.name]) then _G[db.name] = nil end end end end function AceDB:AcquireDBNamespace(name) AceDB:argCheck(name, 2, "string") local db = self.db if not db then AceDB:error("Cannot call `AcquireDBNamespace' before `RegisterDB' has been called.", 2) end if not db.namespaces then rawset(db, 'namespaces', {}) end if not db.namespaces[name] then local namespace = {} db.namespaces[name] = namespace namespace.db = db namespace.name = name setmetatable(namespace, namespace_mt) end return db.namespaces[name] end local options function AceDB:GetAceOptionsDataTable(target) if not target['acedb-profile-list'] then target['acedb-profile-list'] = setmetatable({}, caseInsensitive_mt) local t = target['acedb-profile-list'] for k,v in pairs(t) do t[k] = nil end t.char = 'Character: ' .. charID t.realm = 'Realm: ' .. realmID t.class = 'Class: ' .. classID t.Default = "Default" if target.db and target.db.raw then local db = target.db if db.raw.profiles then for k in pairs(db.raw.profiles) do if not string.find(k, '^char/') and not string.find(k, '^realm/') and not string.find(k, '^class/') then t[k] = k end end end end end if not target['acedb-profile-copylist'] then target['acedb-profile-copylist'] = setmetatable({}, caseInsensitive_mt) if target.db and target.db.raw then local t = target['acedb-profile-copylist'] local db = target.db if db.raw.profiles then for k in pairs(db.raw.profiles) do if string.find(k, '^char/') then local name = string.sub(k, 6) if name ~= charID then t[k] = 'Character: ' .. name end elseif string.find(k, '^realm/') then local name = string.sub(k, 7) if name ~= realmID then t[k] = 'Realm: ' .. name end elseif string.find(k, '^class/') then local name = string.sub(k, 7) if name ~= classID then t[k] = 'Class: ' .. name end end end end end end if not options then options = { standby = { cmdName = STATE, guiName = ENABLED, name = ACTIVE, desc = TOGGLE_ACTIVE, type = "toggle", get = "IsActive", set = "ToggleActive", map = MAP_ACTIVESUSPENDED, order = -3, }, profile = { type = 'group', name = PROFILE, desc = SET_PROFILE, order = -3.5, get = "GetProfile", args = { choose = { guiName = "Choose", cmdName = PROFILE, desc = "Choose a profile", type = 'text', get = "GetProfile", set = "SetProfile", validate = target['acedb-profile-list'] }, copy = { guiName = "Copy from", cmdName = PROFILE, desc = "Copy settings from another profile", type = 'text', get = "GetProfile", set = "SetProfile", validate = target['acedb-profile-copylist'], disabled = function() return not next(target['acedb-profile-copylist']) end, }, other = { guiName = "Other", cmdName = PROFILE, desc = "Choose another profile", usage = "", type = 'text', get = "GetProfile", set = "SetProfile", } } }, } end return options end local function activate(self, oldLib, oldDeactivate) AceDB = self AceEvent = AceLibrary:HasInstance("AceEvent-2.0") and AceLibrary("AceEvent-2.0") self.super.activate(self, oldLib, oldDeactivate) for t in pairs(self.embedList) do if t.db then rawset(t.db, 'char', nil) rawset(t.db, 'realm', nil) rawset(t.db, 'class', nil) rawset(t.db, 'account', nil) rawset(t.db, 'profile', nil) setmetatable(t.db, db_mt) end end if oldLib then self.addonsToBeInitialized = oldLib.addonsToBeInitialized self.addonsLoaded = oldLib.addonsLoaded self.registry = oldLib.registry end if not self.addonsToBeInitialized then self.addonsToBeInitialized = {} end if not self.addonsLoaded then self.addonsLoaded = {} end if not self.registry then self.registry = {} end if oldLib then oldDeactivate(oldLib) end end local function external(self, major, instance) if major == "AceEvent-2.0" then AceEvent = instance AceEvent:embed(self) self:RegisterEvent("ADDON_LOADED") self:RegisterEvent("PLAYER_LOGOUT") elseif major == "Dewdrop-2.0" then Dewdrop = instance end end AceLibrary:Register(AceDB, MAJOR_VERSION, MINOR_VERSION, activate, nil, external) AceDB = AceLibrary(MAJOR_VERSION)