Mercurial > wow > libmoduledbshare-1-0
view LibModuleDBShare-1.0/LibModuleDBShare-1.0.lua @ 37:f971130a84bb v1.2 release
Timestamps should now be recorded even if dual spec is not used.
Profile options tables should now update immediately when dual spec is enabled.
Incremented minor version number.
| author | Andrew Knoll <andrewtknoll@gmail.com> |
|---|---|
| date | Thu, 04 Apr 2013 20:10:20 -0400 |
| parents | 328df380892c |
| children | c6d1b0d7f8f9 |
line wrap: on
line source
--- **LibModuleDBShare-1.0** provides a shared profile manager for addons without a central core. -- A basic options panel for the group is added to the Blizzard options panel, as well as a -- standard profile manager as a subpanel. Changes through the profiles panel are propagated -- to member databases. The root panel can be used as a parent for your module config panels, -- to keep all your addon's config in one place. The root panel's name is the same as the group's -- name.\\ -- \\ -- A group can be created using the ':NewGroup' library method. The returned object inherits all -- methods of the DBGroup object described below.\\ -- \\ -- **LibDualSpec Support**\\ -- LibModuleDBShare can use LibDualSpec to manage automatic profile switching with talent spec -- changes. This integration is handled by the library; there is no need to use LibDualSpec -- on member databases directly. -- -- @usage -- local database; -- -- this function is called after the ADDON_LOADED event fires -- function initializeDB() -- database = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true); -- local group = LibStub("LibModuleDBShare-1.0"):GetGroup("Group Name"); -- if not group then -- group = LibStub("LibModuleDBShare-1.0"):NewGroup("Group Name", "A description for this group.", database); -- else -- group:AddDB(database); -- end -- end -- @class file -- @name LibModuleDBShare-1.0 local MAJOR, MINOR = "LibModuleDBShare-1.0", 4 local LibModuleDBShare, oldminor = LibStub:NewLibrary(MAJOR, MINOR) if not LibModuleDBShare then return end -- No upgrade needed -- Lua functions local error, type, pairs, time = error, type, pairs, time; -- Required Libraries local AceDB = LibStub("AceDB-3.0"); local AceDBOptions = LibStub("AceDBOptions-3.0"); local AceConfigRegistry = LibStub("AceConfigRegistry-3.0"); local AceConfigDialog = LibStub("AceConfigDialog-3.0"); -- Optional Libraries local LibDualSpec = LibStub("LibDualSpec-1.0", true); LibModuleDBShare.groups = LibModuleDBShare.groups or {}; local DBGroup = {}; --- Creates a new DB group. -- @param groupName The name of the new DB group, as shown in the options panel. -- @param groupDescription A description of the group to be shown in the root options panel. -- @param initialDB The first DB to add to the group. -- @param usesDualSpec True if this group should use LibDualSpec, false otherwise. -- @usage -- local myDB = LibStub("AceDB-3.0"):New("MySavedVar"); -- local myAddonDBGroup = LibStub("LibModuleDBShare-1.0"):NewGroup("MyAddonGroupName", "MyDescription", myDB, true) -- @return the new DB group object -- @name LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB[, usesDualSpec]); function LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec) -- check to see if LibDualSpec has been loaded if not LibDualSpec then LibDualSpec = LibStub("LibDualSpec-1.0", true); end -- verify parameters if type(groupName) ~= "string" then error("Usage: LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): 'groupName' must be a string.", 2); elseif type(groupDescription) ~= "string" then error("Usage: LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): 'groupDescription' must be a string.", 2); elseif type(LibModuleDBShare.groups[groupName]) ~= "nil" then error("Usage: LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): group '"..groupName.."' already exists.", 2); elseif type(initialDB) ~= "table" or not AceDB.db_registry[initialDB] then error("Usage: LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): 'initialDB' must be an AceDB-3.0 database.", 2); elseif initialDB.parent then error("Usage: LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): 'initialDB' must not be a namespace.", 2) elseif type(usesDualSpec) ~= "boolean" and type(usesDualSpec) ~= "nil" then error("Usage: LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): 'usesDualSpec' must be a boolean or nil.", 2); elseif usesDualSpec and not LibDualSpec then error("Usage: LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): 'usesDualSpec' cannot be true without LibDualSpec-1.0 installed.", 2); end -- create group local group = {} group.name = groupName; group.members = {}; -- create root option panel for group group.rootOptionsTable = { type = "group", name = groupName, args = { text = { type = "description", name = groupDescription, }, }, }; AceConfigRegistry:RegisterOptionsTable(groupName, group.rootOptionsTable); AceConfigDialog:AddToBlizOptions(groupName); -- create sync DB and profile options page group.syncDBTable = {}; group.syncDB = AceDB:New(group.syncDBTable, nil, initialDB:GetCurrentProfile()); group.profileOptionsTable = AceDBOptions:GetOptionsTable(group.syncDB, false); if usesDualSpec then group.usesDualSpec = true; LibDualSpec:EnhanceDatabase(group.syncDB, groupName); LibDualSpec:EnhanceOptions(group.profileOptionsTable, group.syncDB); else group.usesDualSpec = false; end AceConfigRegistry:RegisterOptionsTable(groupName.."Profiles", group.profileOptionsTable); AceConfigDialog:AddToBlizOptions(groupName.."Profiles", group.profileOptionsTable.name, groupName); -- add all profiles from initialDB to syncDB for i, profile in pairs(initialDB:GetProfiles()) do group.syncDB:SetProfile(profile); end -- load profile info from initialDB group.syncDB:SetProfile(initialDB:GetCurrentProfile()); group.members[initialDB] = initialDB:GetNamespace(MAJOR, true) or initialDB:RegisterNamespace(MAJOR); local storedData = group.members[initialDB].char; if type(storedData.logoutTimestamp) == "number" then group.profileTimestamp = storedData.logoutTimestamp; else group.profileTimestamp = 0; end if usesDualSpec then local LDSnamespace = group.syncDB:GetNamespace("LibDualSpec-1.0"); LDSnamespace.char.enabled = storedData.dualSpecEnabled; LDSnamespace.char.profile = storedData.altProfile; LDSnamespace.char.specGroup = storedData.activeSpecGroup; group.syncDB:CheckDualSpecState(); else group.syncDB.char.enabled = storedData.dualSpecEnabled; group.syncDB.char.profile = storedData.altProfile; group.syncDB.char.specGroup = storedData.activeSpecGroup; end -- add methods and callbacks for k, v in pairs(DBGroup) do group[k] = v; end group.syncDB.RegisterCallback(group, "OnProfileChanged", "OnProfileChanged"); group.syncDB.RegisterCallback(group, "OnProfileDeleted", "OnProfileDeleted"); group.syncDB.RegisterCallback(group, "OnProfileCopied", "OnProfileCopied"); group.syncDB.RegisterCallback(group, "OnProfileReset", "OnProfileReset"); group.syncDB.RegisterCallback(group, "OnDatabaseShutdown", "OnSyncShutdown"); initialDB.RegisterCallback(group, "OnDatabaseShutdown", "OnMemberShutdown"); group.squelchCallbacks = false; LibModuleDBShare.groups[groupName] = group; return group; end --- Retrieves an existing DB group. -- @param groupName The name of the DB group to retrieve. -- @usage -- local myAddonDBGroup = LibStub("LibModuleDBShare-1.0"):GetGroup("MyAddonGroupName") -- @return the DB group object, or ##nil## if not found function LibModuleDBShare:GetGroup(groupName) if type(groupName) ~= "string" then error("Usage: LibModuleDBShare:GetGroup(groupName): 'groupName' must be a string.", 2); end return LibModuleDBShare.groups[groupName]; end --- Adds a database to the group. -- @param newDB The database to add. -- @usage -- myAddonDBGroup:AddDB(MyAddon.db) function DBGroup:AddDB(newDB) -- verify parameters if type(newDB) ~= "table" or not AceDB.db_registry[newDB] then error("Usage: DBGroup:AddDB(newDB): 'newDB' must be an AceDB-3.0 database.", 2); elseif newDB.parent then error("Usage: DBGroup:AddDB(newDB): 'newDB' must not be a namespace.", 2) elseif type(self.members[newDB]) ~= "nil" then error("Usage: DBGroup:AddDB(newDB): 'newDB' is already a member of DBGroup.", 2); end for groupName, group in pairs(LibModuleDBShare.groups) do if group.members[newDB] ~= nil then error("Usage: DBGroup:AddDB(newDB): 'newDB' is already a member of group '"..groupName.."'.", 2); end end -- record current profile local syncProfile = self.syncDB:GetCurrentProfile(); -- add new profiles to syncDB self.squelchCallbacks = true; for i, profile in pairs(newDB:GetProfiles()) do self.syncDB:SetProfile(profile); end -- set current profile based on timestamps local namespace = newDB:GetNamespace(MAJOR, true) or newDB:RegisterNamespace(MAJOR); local storedData = namespace.char; if type(storedData.logoutTimestamp) == "number" and storedData.logoutTimestamp > self.profileTimestamp then self.squelchCallbacks = false; self.syncDB:SetProfile(newDB:GetCurrentProfile()); self.profileTimestamp = storedData.logoutTimestamp; if self.usesDualSpec and storedData.altProfile then local LDSnamespace = group.syncDB:GetNamespace("LibDualSpec-1.0"); LDSnamespace.char.enabled = storedData.dualSpecEnabled; LDSnamespace.char.profile = storedData.altProfile; LDSnamespace.char.specGroup = storedData.activeSpecGroup; group.syncDB:CheckDualSpecState(); elseif storedData.altProfile then self.syncDB.char.enabled = storedData.dualSpecEnabled; self.syncDB.char.profile = storedData.altProfile; self.syncDB.char.specGroup = storedData.activeSpecGroup; end else self.syncDB:SetProfile(syncProfile); newDB:SetProfile(syncProfile); self.squelchCallbacks = false; end -- add to members list self.members[newDB] = namespace; newDB.RegisterCallback(self, "OnDatabaseShutdown", "OnMemberShutdown"); end --- Checks to see if this group uses LibDualSpec. -- @return ##true## if this group uses LibDualSpec, ##false## otherwise function DBGroup:IsUsingDualSpec() return self.usesDualSpec; end --- Enables dual spec support if not already enabled. function DBGroup:EnableDualSpec() if not LibDualSpec then LibDualSpec = LibStub("LibDualSpec-1.0"); -- this will error if LDS isn't found end if not self.usesDualSpec then LibDualSpec:EnhanceDatabase(self.syncDB, self.name); LibDualSpec:EnhanceOptions(self.profileOptionsTable, self.syncDB); AceConfigRegistry:NotifyChange(self.name.."Profiles"); self.usesDualSpec = true; local namespace = self.syncDB:GetNamespace("LibDualSpec-1.0"); namespace.char.enabled = self.syncDB.char.enabled; namespace.char.profile = self.syncDB.char.profile; namespace.char.specGroup = self.syncDB.char.specGroup; self.syncDB:CheckDualSpecState(); end end -- callback handlers (new profiles are handled by OnProfileChanged) function DBGroup:OnProfileChanged(callback, syncDB, profile) if not self.squelchCallbacks then for db, _ in pairs(self.members) do db:SetProfile(profile); end end end function DBGroup:OnProfileDeleted(callback, syncDB, profile) for db, _ in pairs(self.members) do db:DeleteProfile(profile, true); end end function DBGroup:OnProfileCopied(callback, syncDB, profile) for db, _ in pairs(self.members) do db:CopyProfile(profile, true); end end function DBGroup:OnProfileReset(callback, syncDB) for db, _ in pairs(self.members) do db:ResetProfile(false, false); end end local altProfile = nil; local dualSpecEnabled = nil; local activeSpecGroup = nil; function DBGroup:OnSyncShutdown(callback, syncDB) if self.usesDualSpec and not altProfile then altProfile = syncDB:GetDualSpecProfile(); dualSpecEnabled = syncDB:IsDualSpecEnabled(); activeSpecGroup = GetActiveSpecGroup(); end end local timestamp = nil; function DBGroup:OnMemberShutdown(callback, db) if not timestamp then -- ensure uniform timestamps to minimize timestamp = time(); -- calls to SetProfile in NewGroup end self.members[db].char.logoutTimestamp = timestamp; if self.usesDualSpec then if not altProfile then altProfile = self.syncDB:GetDualSpecProfile(); dualSpecEnabled = self.syncDB:IsDualSpecEnabled(); activeSpecGroup = GetActiveSpecGroup(); end self.members[db].char.altProfile = altProfile; self.members[db].char.dualSpecEnabled = dualSpecEnabled; self.members[db].char.activeSpecGroup = activeSpecGroup; end end -- update existing groups for groupName, group in pairs(LibModuleDBShare.groups) do for funcName, func in pairs(DBGroup) do group[funcName] = func; end end
