annotate LibModuleDBShare-1.0/LibModuleDBShare-1.0.lua @ 33:3f329c676eac v1.0 release

Updated luadoc comments. Set minor version to 2, so any alpha versions are overwritten.
author Andrew Knoll <andrewtknoll@gmail.com>
date Tue, 19 Mar 2013 00:10:03 -0400
parents ff0e10fd2a5f
children 328df380892c
rev   line source
andrewtknoll@33 1 --- **LibModuleDBShare-1.0** provides a shared profile manager for addons without a central core.
andrewtknoll@33 2 -- A basic options panel for the group is added to the Blizzard options panel, as well as a
andrewtknoll@33 3 -- standard profile manager as a subpanel. Changes through the profiles panel are propagated
andrewtknoll@33 4 -- to member databases. The root panel can be used as a parent for your module config panels,
andrewtknoll@33 5 -- to keep all your addon's config in one place. The root panel's name is the same as the group's
andrewtknoll@33 6 -- name.\\
andrewtknoll@33 7 -- \\
andrewtknoll@33 8 -- A group can be created using the ':NewGroup' library method. The returned object inherits
andrewtknoll@33 9 -- the ':AddDB' method of the DBGroup object described below.\\
andrewtknoll@33 10 -- \\
andrewtknoll@33 11 -- **LibDualSpec Support**\\
andrewtknoll@33 12 -- LibModuleDBShare can use LibDualSpec to manage automatic profile switching with talent spec
andrewtknoll@33 13 -- changes. This integration is handled by the library; there is no need to use LibDualSpec
andrewtknoll@33 14 -- on member databases directly.
>@5 15 --
>@5 16 -- @usage
andrewtknoll@33 17 -- local database;
andrewtknoll@33 18 -- -- this function is called after the ADDON_LOADED event fires
andrewtknoll@33 19 -- function initializeDB()
andrewtknoll@33 20 -- database = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true);
andrewtknoll@33 21 -- local group = LibStub("LibModuleDBShare-1.0"):GetGroup("Group Name");
andrewtknoll@33 22 -- if not group then
andrewtknoll@33 23 -- group = LibStub("LibModuleDBShare-1.0"):NewGroup("Group Name", "A description for this group.", database);
andrewtknoll@33 24 -- else
andrewtknoll@33 25 -- group:AddDB(database);
andrewtknoll@33 26 -- end
andrewtknoll@33 27 -- end
>@5 28 -- @class file
andrewtknoll@33 29 -- @name LibModuleDBShare-1.0
andrewtknoll@33 30 local MAJOR, MINOR = "LibModuleDBShare-1.0", 2
>@3 31 local LibModuleDBShare, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
>@3 32
>@4 33 if not LibModuleDBShare then return end -- No upgrade needed
>@4 34
andrewtknoll@29 35 -- Lua functions
andrewtknoll@26 36 local error, type, pairs, time = error, type, pairs, time;
andrewtknoll@15 37
andrewtknoll@17 38 -- Required Libraries
@12 39 local AceDB = LibStub("AceDB-3.0");
andrewtknoll@17 40 local AceDBOptions = LibStub("AceDBOptions-3.0");
andrewtknoll@17 41 local AceConfigRegistry = LibStub("AceConfigRegistry-3.0");
andrewtknoll@17 42 local AceConfigDialog = LibStub("AceConfigDialog-3.0");
@12 43
andrewtknoll@28 44 -- Optional Libraries
andrewtknoll@28 45 local LibDualSpec = LibStub("LibDualSpec-1.0", true);
andrewtknoll@28 46
>@4 47 LibModuleDBShare.groups = LibModuleDBShare.groups or {};
>@4 48
>@5 49 local DBGroup = {};
>@5 50
>@5 51 --- Creates a new DB group.
andrewtknoll@33 52 -- @param groupName The name of the new DB group, as shown in the options panel.
andrewtknoll@21 53 -- @param groupDescription A description of the group to be shown in the root options panel.
andrewtknoll@21 54 -- @param initialDB The first DB to add to the group.
andrewtknoll@28 55 -- @param usesDualSpec True if this group should use LibDualSpec, false otherwise.
>@5 56 -- @usage
andrewtknoll@33 57 -- local myDB = LibStub("AceDB-3.0"):New("MySavedVar");
andrewtknoll@33 58 -- local myAddonDBGroup = LibStub("LibModuleDBShare-1.0"):NewGroup("MyAddonGroupName", "MyDescription", myDB, true)
>@5 59 -- @return the new DB group object
andrewtknoll@33 60 -- @name LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB[, usesDualSpec]);
andrewtknoll@21 61 function LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec)
andrewtknoll@21 62 -- verify parameters
andrewtknoll@26 63 if type(groupName) ~= "string" then
andrewtknoll@26 64 error("Usage: LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): 'groupName' must be a string.", 2);
andrewtknoll@26 65 elseif type(groupDescription) ~= "string" then
andrewtknoll@26 66 error("Usage: LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): 'groupDescription' must be a string.", 2);
andrewtknoll@26 67 elseif type(LibModuleDBShare.groups[groupName]) ~= "nil" then
andrewtknoll@31 68 error("Usage: LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): group '"..groupName.."' already exists.", 2);
andrewtknoll@27 69 elseif type(initialDB) ~= "table" or not AceDB.db_registry[initialDB] then
andrewtknoll@31 70 error("Usage: LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): 'initialDB' must be an AceDB-3.0 database.", 2);
andrewtknoll@31 71 elseif initialDB.parent then
andrewtknoll@31 72 error("Usage: LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): 'initialDB' must not be a namespace.", 2)
andrewtknoll@28 73 elseif type(usesDualSpec) ~= "boolean" and type(usesDualSpec) ~= "nil" then
andrewtknoll@31 74 error("Usage: LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): 'usesDualSpec' must be a boolean or nil.", 2);
andrewtknoll@28 75 elseif usesDualSpec and not LibDualSpec then
andrewtknoll@31 76 error("Usage: LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): 'usesDualSpec' cannot be true without LibDualSpec-1.0 installed.", 2);
andrewtknoll@26 77 end
andrewtknoll@21 78 -- create group
@12 79 local group = {}
@12 80 group.name = groupName;
andrewtknoll@21 81 group.members = {};
andrewtknoll@21 82 -- create root option panel for group
andrewtknoll@17 83 group.rootOptionsTable = {
andrewtknoll@17 84 type = "group",
andrewtknoll@17 85 name = groupName,
andrewtknoll@17 86 args = {
andrewtknoll@17 87 text = {
andrewtknoll@17 88 type = "description",
andrewtknoll@21 89 name = groupDescription,
andrewtknoll@17 90 },
andrewtknoll@17 91 },
andrewtknoll@17 92 };
andrewtknoll@17 93 AceConfigRegistry:RegisterOptionsTable(groupName, group.rootOptionsTable);
andrewtknoll@17 94 AceConfigDialog:AddToBlizOptions(groupName);
andrewtknoll@21 95 -- create sync DB and profile options page
@12 96 group.syncDBTable = {};
andrewtknoll@21 97 group.syncDB = AceDB:New(group.syncDBTable, nil, initialDB:GetCurrentProfile());
andrewtknoll@17 98 group.profileOptionsTable = AceDBOptions:GetOptionsTable(group.syncDB, false);
andrewtknoll@28 99 if usesDualSpec then
andrewtknoll@29 100 group.usesDualSpec = true;
andrewtknoll@28 101 LibDualSpec:EnhanceDatabase(group.syncDB, groupName);
andrewtknoll@28 102 LibDualSpec:EnhanceOptions(group.profileOptionsTable, group.syncDB);
andrewtknoll@29 103 else
andrewtknoll@29 104 group.usesDualSpec = false;
andrewtknoll@28 105 end
andrewtknoll@17 106 AceConfigRegistry:RegisterOptionsTable(groupName.."Profiles", group.profileOptionsTable);
andrewtknoll@18 107 AceConfigDialog:AddToBlizOptions(groupName.."Profiles", group.profileOptionsTable.name, groupName);
andrewtknoll@21 108 -- add all profiles from initialDB to syncDB
andrewtknoll@21 109 for i, profile in pairs(initialDB:GetProfiles()) do
andrewtknoll@21 110 group.syncDB:SetProfile(profile);
andrewtknoll@21 111 end
andrewtknoll@28 112 -- load profile info from initialDB
andrewtknoll@21 113 group.syncDB:SetProfile(initialDB:GetCurrentProfile());
andrewtknoll@27 114 group.members[initialDB] = initialDB:GetNamespace(MAJOR, true) or initialDB:RegisterNamespace(MAJOR);
andrewtknoll@29 115 local storedData = group.members[initialDB].char;
andrewtknoll@29 116 if type(storedData.logoutTimestamp) == "number" then
andrewtknoll@29 117 group.profileTimestamp = storedData.logoutTimestamp;
andrewtknoll@22 118 else
andrewtknoll@22 119 group.profileTimestamp = 0;
andrewtknoll@22 120 end
andrewtknoll@29 121 if usesDualSpec and storedData.altProfile then
andrewtknoll@30 122 namespace = group.syncDB:GetNamespace("LibDualSpec-1.0");
andrewtknoll@30 123 namespace.char.enabled = storedData.dualSpecEnabled;
andrewtknoll@30 124 namespace.char.profile = storedData.altProfile;
andrewtknoll@30 125 namespace.char.specGroup = storedData.activeSpecGroup;
andrewtknoll@30 126 group.syncDB:CheckDualSpecState();
andrewtknoll@28 127 end
andrewtknoll@21 128 -- add methods and callbacks
@12 129 for k, v in pairs(DBGroup) do
@12 130 group[k] = v;
@12 131 end
andrewtknoll@19 132 group.syncDB.RegisterCallback(group, "OnProfileChanged", "OnProfileChanged");
andrewtknoll@19 133 group.syncDB.RegisterCallback(group, "OnProfileDeleted", "OnProfileDeleted");
andrewtknoll@19 134 group.syncDB.RegisterCallback(group, "OnProfileCopied", "OnProfileCopied");
andrewtknoll@19 135 group.syncDB.RegisterCallback(group, "OnProfileReset", "OnProfileReset");
andrewtknoll@28 136 group.syncDB.RegisterCallback(group, "OnDatabaseShutdown", "OnSyncShutdown");
andrewtknoll@28 137 initialDB.RegisterCallback(group, "OnDatabaseShutdown", "OnMemberShutdown");
andrewtknoll@20 138 group.squelchCallbacks = false;
andrewtknoll@19 139 LibModuleDBShare.groups[groupName] = group;
@12 140 return group;
>@4 141 end
>@4 142
>@5 143 --- Retrieves an existing DB group.
>@5 144 -- @param groupName The name of the DB group to retrieve.
>@5 145 -- @usage
>@5 146 -- local myAddonDBGroup = LibStub("LibModuleDBShare-1.0"):GetGroup("MyAddonGroupName")
>@5 147 -- @return the DB group object, or nil if not found
>@5 148 function LibModuleDBShare:GetGroup(groupName)
andrewtknoll@27 149 if type(groupName) ~= "string" then
andrewtknoll@27 150 error("Usage: LibModuleDBShare:GetGroup(groupName): 'groupName' must be a string.", 2);
andrewtknoll@27 151 end
@12 152 return LibModuleDBShare.groups[groupName];
>@4 153 end
>@5 154
>@5 155 --- Adds a database to the group.
andrewtknoll@22 156 -- @param newDB The database to add.
>@5 157 -- @usage
>@5 158 -- myAddonDBGroup:AddDB(MyAddon.db)
andrewtknoll@22 159 function DBGroup:AddDB(newDB)
andrewtknoll@22 160 -- verify parameters
andrewtknoll@26 161 if type(newDB) ~= "table" or not AceDB.db_registry[newDB] then
andrewtknoll@31 162 error("Usage: DBGroup:AddDB(newDB): 'newDB' must be an AceDB-3.0 database.", 2);
andrewtknoll@31 163 elseif newDB.parent then
andrewtknoll@31 164 error("Usage: DBGroup:AddDB(newDB): 'newDB' must not be a namespace.", 2)
andrewtknoll@26 165 elseif type(self.members[newDB]) ~= "nil" then
andrewtknoll@31 166 error("Usage: DBGroup:AddDB(newDB): 'newDB' is already a member of DBGroup.", 2);
andrewtknoll@31 167 end
andrewtknoll@31 168 for groupName, group in pairs(LibModuleDBShare.groups) do
andrewtknoll@31 169 if group.members[newDB] ~= nil then
andrewtknoll@31 170 error("Usage: DBGroup:AddDB(newDB): 'newDB' is already a member of group '"..groupName.."'.", 2);
andrewtknoll@31 171 end
andrewtknoll@26 172 end
andrewtknoll@22 173 -- record current profile
andrewtknoll@20 174 local syncProfile = self.syncDB:GetCurrentProfile();
andrewtknoll@22 175 -- add new profiles to syncDB
andrewtknoll@20 176 self.squelchCallbacks = true;
andrewtknoll@22 177 for i, profile in pairs(newDB:GetProfiles()) do
andrewtknoll@20 178 self.syncDB:SetProfile(profile);
andrewtknoll@20 179 end
andrewtknoll@22 180 -- set current profile based on timestamps
andrewtknoll@27 181 local namespace = newDB:GetNamespace(MAJOR, true) or newDB:RegisterNamespace(MAJOR);
andrewtknoll@29 182 local storedData = namespace.char;
andrewtknoll@29 183 if type(storedData.logoutTimestamp) == "number" and storedData.logoutTimestamp > self.profileTimestamp then
andrewtknoll@22 184 self.squelchCallbacks = false;
andrewtknoll@22 185 self.syncDB:SetProfile(newDB:GetCurrentProfile());
andrewtknoll@29 186 self.profileTimestamp = storedData.logoutTimestamp;
andrewtknoll@30 187 if usesDualSpec and storedData.altProfile then
andrewtknoll@30 188 namespace = group.syncDB:GetNamespace("LibDualSpec-1.0");
andrewtknoll@30 189 namespace.char.enabled = storedData.dualSpecEnabled;
andrewtknoll@30 190 namespace.char.profile = storedData.altProfile;
andrewtknoll@30 191 namespace.char.specGroup = storedData.activeSpecGroup;
andrewtknoll@30 192 group.syncDB:CheckDualSpecState();
andrewtknoll@28 193 end
andrewtknoll@20 194 else
andrewtknoll@20 195 self.syncDB:SetProfile(syncProfile);
andrewtknoll@22 196 newDB:SetProfile(syncProfile);
andrewtknoll@22 197 self.squelchCallbacks = false;
andrewtknoll@20 198 end
andrewtknoll@22 199 -- add to members list
andrewtknoll@27 200 self.members[newDB] = namespace;
andrewtknoll@28 201 newDB.RegisterCallback(self, "OnDatabaseShutdown", "OnMemberShutdown");
>@5 202 end
andrewtknoll@18 203
andrewtknoll@19 204 -- callback handlers (new profiles are handled by OnProfileChanged)
andrewtknoll@19 205
andrewtknoll@24 206 function DBGroup:OnProfileChanged(callback, syncDB, profile)
andrewtknoll@24 207 if not self.squelchCallbacks then
andrewtknoll@24 208 for db, _ in pairs(self.members) do
andrewtknoll@25 209 db:SetProfile(profile);
andrewtknoll@24 210 end
andrewtknoll@24 211 end
andrewtknoll@18 212 end
andrewtknoll@18 213
andrewtknoll@24 214 function DBGroup:OnProfileDeleted(callback, syncDB, profile)
andrewtknoll@24 215 for db, _ in pairs(self.members) do
andrewtknoll@24 216 db:DeleteProfile(profile, true);
andrewtknoll@24 217 end
andrewtknoll@18 218 end
andrewtknoll@18 219
andrewtknoll@24 220 function DBGroup:OnProfileCopied(callback, syncDB, profile)
andrewtknoll@24 221 for db, _ in pairs(self.members) do
andrewtknoll@24 222 db:CopyProfile(profile, true);
andrewtknoll@24 223 end
andrewtknoll@18 224 end
andrewtknoll@18 225
andrewtknoll@24 226 function DBGroup:OnProfileReset(callback, syncDB)
andrewtknoll@24 227 for db, _ in pairs(self.members) do
andrewtknoll@24 228 db:ResetProfile(false, false);
andrewtknoll@24 229 end
andrewtknoll@18 230 end
andrewtknoll@23 231
andrewtknoll@29 232 local altProfile = nil;
andrewtknoll@29 233 local dualSpecEnabled = nil;
andrewtknoll@29 234 local activeSpecGroup = nil;
andrewtknoll@28 235
andrewtknoll@28 236 function DBGroup:OnSyncShutdown(callback, syncDB)
andrewtknoll@29 237 if self.usesDualSpec and not altProfile then
andrewtknoll@29 238 altProfile = syncDB:GetDualSpecProfile();
andrewtknoll@29 239 dualSpecEnabled = syncDB:IsDualSpecEnabled();
andrewtknoll@29 240 activeSpecGroup = GetActiveSpecGroup();
andrewtknoll@28 241 end
andrewtknoll@28 242 end
andrewtknoll@28 243
andrewtknoll@24 244 local timestamp = nil;
andrewtknoll@24 245
andrewtknoll@28 246 function DBGroup:OnMemberShutdown(callback, db)
andrewtknoll@27 247 if not timestamp then -- ensure uniform timestamps to minimize
andrewtknoll@27 248 timestamp = time(); -- calls to SetProfile in NewGroup
andrewtknoll@24 249 end
andrewtknoll@29 250 if self.usesDualSpec then
andrewtknoll@29 251 if not altProfile then
andrewtknoll@29 252 altProfile = self.syncDB:GetDualSpecProfile();
andrewtknoll@29 253 dualSpecEnabled = self.syncDB:IsDualSpecEnabled();
andrewtknoll@29 254 activeSpecGroup = GetActiveSpecGroup();
andrewtknoll@29 255 end
andrewtknoll@29 256 self.members[db].char.logoutTimestamp = timestamp;
andrewtknoll@29 257 self.members[db].char.altProfile = altProfile;
andrewtknoll@29 258 self.members[db].char.dualSpecEnabled = dualSpecEnabled;
andrewtknoll@29 259 self.members[db].char.activeSpecGroup = activeSpecGroup;
andrewtknoll@28 260 end
andrewtknoll@23 261 end
andrewtknoll@33 262
andrewtknoll@33 263 -- update existing groups
andrewtknoll@33 264 for groupName, group in pairs(LibModuleDBShare.groups) do
andrewtknoll@33 265 for funcName, func in pairs(DBGroup) do
andrewtknoll@33 266 group[funcName] = func;
andrewtknoll@33 267 end
andrewtknoll@33 268 end