annotate LibModuleDBShare-1.0/LibModuleDBShare-1.0.lua @ 28:085d93d62782

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