annotate LibModuleDBShare-1.0/LibModuleDBShare-1.0.lua @ 29:d8dd617017de

Rewrote LibDualSpec support to use public APIs instead of directly accessing data.
author Andrew Knoll <andrewtknoll@gmail.com>
date Sun, 17 Mar 2013 03:05:25 -0400
parents 085d93d62782
children 5c7143d32287
rev   line source
>@5 1 --- **LibModuleDBShare-1.0**\\
>@5 2 -- A description will eventually be here.
>@5 3 --
>@5 4 -- @usage
>@5 5 -- Also coming soon.
>@5 6 -- @class file
>@5 7 -- @name LibModuleDBShare-1.0.lua
>@3 8 local MAJOR, MINOR = "LibModuleDBShare-1.0", 1
>@3 9 local LibModuleDBShare, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
>@3 10
>@4 11 if not LibModuleDBShare then return end -- No upgrade needed
>@4 12
andrewtknoll@29 13 -- Lua functions
andrewtknoll@26 14 local error, type, pairs, time = error, type, pairs, time;
andrewtknoll@15 15
andrewtknoll@29 16 -- Blizzard functions
andrewtknoll@29 17 local GetActiveSpecGroup = GetActiveSpecGroup;
andrewtknoll@29 18
andrewtknoll@17 19 -- Required Libraries
@12 20 local AceDB = LibStub("AceDB-3.0");
andrewtknoll@17 21 local AceDBOptions = LibStub("AceDBOptions-3.0");
andrewtknoll@17 22 local AceConfigRegistry = LibStub("AceConfigRegistry-3.0");
andrewtknoll@17 23 local AceConfigDialog = LibStub("AceConfigDialog-3.0");
@12 24
andrewtknoll@28 25 -- Optional Libraries
andrewtknoll@28 26 local LibDualSpec = LibStub("LibDualSpec-1.0", true);
andrewtknoll@28 27
>@4 28 LibModuleDBShare.groups = LibModuleDBShare.groups or {};
>@4 29
>@5 30 local DBGroup = {};
>@5 31
>@5 32 --- Creates a new DB group.
>@5 33 -- @param groupName The name of the new DB group.
andrewtknoll@21 34 -- @param groupDescription A description of the group to be shown in the root options panel.
andrewtknoll@21 35 -- @param initialDB The first DB to add to the group.
andrewtknoll@28 36 -- @param usesDualSpec True if this group should use LibDualSpec, false otherwise.
>@5 37 -- @usage
>@5 38 -- local myAddonDBGroup = LibStub("LibModuleDBShare-1.0"):NewGroup("MyAddonGroupName", true)
>@5 39 -- @return the new DB group object
andrewtknoll@21 40 function LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec)
andrewtknoll@21 41 -- verify parameters
andrewtknoll@26 42 if type(groupName) ~= "string" then
andrewtknoll@26 43 error("Usage: LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): 'groupName' must be a string.", 2);
andrewtknoll@26 44 elseif type(groupDescription) ~= "string" then
andrewtknoll@26 45 error("Usage: LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): 'groupDescription' must be a string.", 2);
andrewtknoll@26 46 elseif type(LibModuleDBShare.groups[groupName]) ~= "nil" then
andrewtknoll@26 47 error("LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): group '"..groupName.."' already exists.", 2);
andrewtknoll@27 48 elseif type(initialDB) ~= "table" or not AceDB.db_registry[initialDB] then
andrewtknoll@27 49 error("LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): 'initalDB' must be an AceDB-3.0 database.", 2);
andrewtknoll@28 50 elseif type(usesDualSpec) ~= "boolean" and type(usesDualSpec) ~= "nil" then
andrewtknoll@28 51 error("LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): 'usesDualSpec' must be a boolean or nil.", 2);
andrewtknoll@28 52 elseif usesDualSpec and not LibDualSpec then
andrewtknoll@28 53 error("LibModuleDBShare:NewGroup(groupName, groupDescription, initialDB, usesDualSpec): 'usesDualSpec' cannot be true without LibDualSpec-1.0 installed.", 2);
andrewtknoll@26 54 end
andrewtknoll@21 55 -- create group
@12 56 local group = {}
@12 57 group.name = groupName;
andrewtknoll@21 58 group.members = {};
andrewtknoll@21 59 -- create root option panel for group
andrewtknoll@17 60 group.rootOptionsTable = {
andrewtknoll@17 61 type = "group",
andrewtknoll@17 62 name = groupName,
andrewtknoll@17 63 args = {
andrewtknoll@17 64 text = {
andrewtknoll@17 65 type = "description",
andrewtknoll@21 66 name = groupDescription,
andrewtknoll@17 67 },
andrewtknoll@17 68 },
andrewtknoll@17 69 };
andrewtknoll@17 70 AceConfigRegistry:RegisterOptionsTable(groupName, group.rootOptionsTable);
andrewtknoll@17 71 AceConfigDialog:AddToBlizOptions(groupName);
andrewtknoll@21 72 -- create sync DB and profile options page
@12 73 group.syncDBTable = {};
andrewtknoll@21 74 group.syncDB = AceDB:New(group.syncDBTable, nil, initialDB:GetCurrentProfile());
andrewtknoll@17 75 group.profileOptionsTable = AceDBOptions:GetOptionsTable(group.syncDB, false);
andrewtknoll@28 76 if usesDualSpec then
andrewtknoll@29 77 group.usesDualSpec = true;
andrewtknoll@28 78 LibDualSpec:EnhanceDatabase(group.syncDB, groupName);
andrewtknoll@28 79 LibDualSpec:EnhanceOptions(group.profileOptionsTable, group.syncDB);
andrewtknoll@29 80 else
andrewtknoll@29 81 group.usesDualSpec = false;
andrewtknoll@28 82 end
andrewtknoll@17 83 AceConfigRegistry:RegisterOptionsTable(groupName.."Profiles", group.profileOptionsTable);
andrewtknoll@18 84 AceConfigDialog:AddToBlizOptions(groupName.."Profiles", group.profileOptionsTable.name, groupName);
andrewtknoll@21 85 -- add all profiles from initialDB to syncDB
andrewtknoll@21 86 for i, profile in pairs(initialDB:GetProfiles()) do
andrewtknoll@21 87 group.syncDB:SetProfile(profile);
andrewtknoll@21 88 end
andrewtknoll@28 89 -- load profile info from initialDB
andrewtknoll@21 90 group.syncDB:SetProfile(initialDB:GetCurrentProfile());
andrewtknoll@27 91 group.members[initialDB] = initialDB:GetNamespace(MAJOR, true) or initialDB:RegisterNamespace(MAJOR);
andrewtknoll@29 92 local storedData = group.members[initialDB].char;
andrewtknoll@29 93 if type(storedData.logoutTimestamp) == "number" then
andrewtknoll@29 94 group.profileTimestamp = storedData.logoutTimestamp;
andrewtknoll@22 95 else
andrewtknoll@22 96 group.profileTimestamp = 0;
andrewtknoll@22 97 end
andrewtknoll@29 98 if usesDualSpec and storedData.altProfile then
andrewtknoll@29 99 group.syncDB:SetDualSpecProfile(storedData.altProfile);
andrewtknoll@29 100 group.syncDB:SetDualSpecEnabled(storedData.dualSpecEnabled);
andrewtknoll@29 101 if storedData.dualSpecEnabled and storedData.activeSpecGroup ~= GetActiveSpecGroup() then
andrewtknoll@29 102 group.syncDB:SetDualSpecProfile(group.syncDB:GetCurrentProfile());
andrewtknoll@29 103 group.syncDB:SetProfile(storedData.altProfile);
andrewtknoll@29 104 initialDB:SetProfile(storedData.altProfile);
andrewtknoll@29 105 end
andrewtknoll@28 106 end
andrewtknoll@21 107 -- add methods and callbacks
@12 108 for k, v in pairs(DBGroup) do
@12 109 group[k] = v;
@12 110 end
andrewtknoll@19 111 group.syncDB.RegisterCallback(group, "OnProfileChanged", "OnProfileChanged");
andrewtknoll@19 112 group.syncDB.RegisterCallback(group, "OnProfileDeleted", "OnProfileDeleted");
andrewtknoll@19 113 group.syncDB.RegisterCallback(group, "OnProfileCopied", "OnProfileCopied");
andrewtknoll@19 114 group.syncDB.RegisterCallback(group, "OnProfileReset", "OnProfileReset");
andrewtknoll@28 115 group.syncDB.RegisterCallback(group, "OnDatabaseShutdown", "OnSyncShutdown");
andrewtknoll@28 116 initialDB.RegisterCallback(group, "OnDatabaseShutdown", "OnMemberShutdown");
andrewtknoll@20 117 group.squelchCallbacks = false;
andrewtknoll@19 118 LibModuleDBShare.groups[groupName] = group;
@12 119 return group;
>@4 120 end
>@4 121
>@5 122 --- Retrieves an existing DB group.
>@5 123 -- @param groupName The name of the DB group to retrieve.
>@5 124 -- @usage
>@5 125 -- local myAddonDBGroup = LibStub("LibModuleDBShare-1.0"):GetGroup("MyAddonGroupName")
>@5 126 -- @return the DB group object, or nil if not found
>@5 127 function LibModuleDBShare:GetGroup(groupName)
andrewtknoll@27 128 if type(groupName) ~= "string" then
andrewtknoll@27 129 error("Usage: LibModuleDBShare:GetGroup(groupName): 'groupName' must be a string.", 2);
andrewtknoll@27 130 end
@12 131 return LibModuleDBShare.groups[groupName];
>@4 132 end
>@5 133
>@5 134 --- Adds a database to the group.
andrewtknoll@22 135 -- @param newDB The database to add.
>@5 136 -- @usage
>@5 137 -- myAddonDBGroup:AddDB(MyAddon.db)
andrewtknoll@22 138 function DBGroup:AddDB(newDB)
andrewtknoll@22 139 -- verify parameters
andrewtknoll@26 140 if type(newDB) ~= "table" or not AceDB.db_registry[newDB] then
andrewtknoll@26 141 error("Usage: DBGroup:AddDB(newDB): 'newDB' must be a table.", 2);
andrewtknoll@26 142 elseif type(self.members[newDB]) ~= "nil" then
andrewtknoll@26 143 error("DBGroup:AddDB(newDB): 'newDB' is already a member of DBGroup.", 2);
andrewtknoll@26 144 end
andrewtknoll@22 145 -- record current profile
andrewtknoll@20 146 local syncProfile = self.syncDB:GetCurrentProfile();
andrewtknoll@22 147 -- add new profiles to syncDB
andrewtknoll@20 148 self.squelchCallbacks = true;
andrewtknoll@22 149 for i, profile in pairs(newDB:GetProfiles()) do
andrewtknoll@20 150 self.syncDB:SetProfile(profile);
andrewtknoll@20 151 end
andrewtknoll@22 152 -- set current profile based on timestamps
andrewtknoll@27 153 local namespace = newDB:GetNamespace(MAJOR, true) or newDB:RegisterNamespace(MAJOR);
andrewtknoll@29 154 local storedData = namespace.char;
andrewtknoll@29 155 if type(storedData.logoutTimestamp) == "number" and storedData.logoutTimestamp > self.profileTimestamp then
andrewtknoll@22 156 self.squelchCallbacks = false;
andrewtknoll@22 157 self.syncDB:SetProfile(newDB:GetCurrentProfile());
andrewtknoll@29 158 self.profileTimestamp = storedData.logoutTimestamp;
andrewtknoll@29 159 if self.usesDualSpec and storedData.altProfile then
andrewtknoll@29 160 self.syncDB:SetDualSpecProfile(storedData.altProfile);
andrewtknoll@29 161 self.syncDB:SetDualSpecEnabled(storedData.dualSpecEnabled);
andrewtknoll@29 162 if storedData.dualSpecEnabled and storedData.activeSpecGroup ~= GetActiveSpecGroup() then
andrewtknoll@29 163 self.syncDB:SetDualSpecProfile(self.syncDB:GetCurrentProfile());
andrewtknoll@29 164 self.syncDB:SetProfile(storedData.altProfile);
andrewtknoll@29 165 newDB:SetProfile(storedData.altProfile);
andrewtknoll@29 166 end
andrewtknoll@28 167 end
andrewtknoll@20 168 else
andrewtknoll@20 169 self.syncDB:SetProfile(syncProfile);
andrewtknoll@22 170 newDB:SetProfile(syncProfile);
andrewtknoll@22 171 self.squelchCallbacks = false;
andrewtknoll@20 172 end
andrewtknoll@22 173 -- add to members list
andrewtknoll@27 174 self.members[newDB] = namespace;
andrewtknoll@28 175 newDB.RegisterCallback(self, "OnDatabaseShutdown", "OnMemberShutdown");
>@5 176 end
andrewtknoll@18 177
andrewtknoll@19 178 -- callback handlers (new profiles are handled by OnProfileChanged)
andrewtknoll@19 179
andrewtknoll@24 180 function DBGroup:OnProfileChanged(callback, syncDB, profile)
andrewtknoll@24 181 if not self.squelchCallbacks then
andrewtknoll@24 182 for db, _ in pairs(self.members) do
andrewtknoll@25 183 db:SetProfile(profile);
andrewtknoll@24 184 end
andrewtknoll@24 185 end
andrewtknoll@18 186 end
andrewtknoll@18 187
andrewtknoll@24 188 function DBGroup:OnProfileDeleted(callback, syncDB, profile)
andrewtknoll@24 189 for db, _ in pairs(self.members) do
andrewtknoll@24 190 db:DeleteProfile(profile, true);
andrewtknoll@24 191 end
andrewtknoll@18 192 end
andrewtknoll@18 193
andrewtknoll@24 194 function DBGroup:OnProfileCopied(callback, syncDB, profile)
andrewtknoll@24 195 for db, _ in pairs(self.members) do
andrewtknoll@24 196 db:CopyProfile(profile, true);
andrewtknoll@24 197 end
andrewtknoll@18 198 end
andrewtknoll@18 199
andrewtknoll@24 200 function DBGroup:OnProfileReset(callback, syncDB)
andrewtknoll@24 201 for db, _ in pairs(self.members) do
andrewtknoll@24 202 db:ResetProfile(false, false);
andrewtknoll@24 203 end
andrewtknoll@18 204 end
andrewtknoll@23 205
andrewtknoll@29 206 local altProfile = nil;
andrewtknoll@29 207 local dualSpecEnabled = nil;
andrewtknoll@29 208 local activeSpecGroup = nil;
andrewtknoll@28 209
andrewtknoll@28 210 function DBGroup:OnSyncShutdown(callback, syncDB)
andrewtknoll@29 211 if self.usesDualSpec and not altProfile then
andrewtknoll@29 212 altProfile = syncDB:GetDualSpecProfile();
andrewtknoll@29 213 dualSpecEnabled = syncDB:IsDualSpecEnabled();
andrewtknoll@29 214 activeSpecGroup = GetActiveSpecGroup();
andrewtknoll@28 215 end
andrewtknoll@28 216 end
andrewtknoll@28 217
andrewtknoll@24 218 local timestamp = nil;
andrewtknoll@24 219
andrewtknoll@28 220 function DBGroup:OnMemberShutdown(callback, db)
andrewtknoll@27 221 if not timestamp then -- ensure uniform timestamps to minimize
andrewtknoll@27 222 timestamp = time(); -- calls to SetProfile in NewGroup
andrewtknoll@24 223 end
andrewtknoll@29 224 if self.usesDualSpec then
andrewtknoll@29 225 if not altProfile then
andrewtknoll@29 226 altProfile = self.syncDB:GetDualSpecProfile();
andrewtknoll@29 227 dualSpecEnabled = self.syncDB:IsDualSpecEnabled();
andrewtknoll@29 228 activeSpecGroup = GetActiveSpecGroup();
andrewtknoll@29 229 end
andrewtknoll@29 230 self.members[db].char.logoutTimestamp = timestamp;
andrewtknoll@29 231 self.members[db].char.altProfile = altProfile;
andrewtknoll@29 232 self.members[db].char.dualSpecEnabled = dualSpecEnabled;
andrewtknoll@29 233 self.members[db].char.activeSpecGroup = activeSpecGroup;
andrewtknoll@28 234 end
andrewtknoll@23 235 end