| flickerstreak@23 | 1 --[[ | 
| flickerstreak@23 | 2 Name: AceModuleCore-2.0 | 
| flickerstreak@23 | 3 Revision: $Rev: 43318 $ | 
| flickerstreak@23 | 4 Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) | 
| flickerstreak@23 | 5 Inspired By: Ace 1.x by Turan (turan@gryphon.com) | 
| flickerstreak@23 | 6 Website: http://www.wowace.com/ | 
| flickerstreak@23 | 7 Documentation: http://www.wowace.com/index.php/AceModuleCore-2.0 | 
| flickerstreak@23 | 8 SVN: http://svn.wowace.com/root/trunk/Ace2/AceModuleCore-2.0 | 
| flickerstreak@23 | 9 Description: Mixin to provide a module system so that modules or plugins can | 
| flickerstreak@23 | 10              use an addon as its core. | 
| flickerstreak@23 | 11 Dependencies: AceLibrary, AceOO-2.0, AceAddon-2.0, AceEvent-2.0 (optional) | 
| flickerstreak@23 | 12 License: LGPL v2.1 | 
| flickerstreak@23 | 13 ]] | 
| flickerstreak@23 | 14 | 
| flickerstreak@23 | 15 local MAJOR_VERSION = "AceModuleCore-2.0" | 
| flickerstreak@23 | 16 local MINOR_VERSION = "$Revision: 43318 $" | 
| flickerstreak@23 | 17 | 
| flickerstreak@23 | 18 if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end | 
| flickerstreak@23 | 19 if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end | 
| flickerstreak@23 | 20 | 
| flickerstreak@23 | 21 if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end | 
| flickerstreak@23 | 22 | 
| flickerstreak@23 | 23 local function safecall(func, ...) | 
| flickerstreak@23 | 24 	local success, err = pcall(func, ...) | 
| flickerstreak@23 | 25 	if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end | 
| flickerstreak@23 | 26 end | 
| flickerstreak@23 | 27 | 
| flickerstreak@23 | 28 local AceEvent | 
| flickerstreak@23 | 29 local AceOO = AceLibrary:GetInstance("AceOO-2.0") | 
| flickerstreak@23 | 30 local AceModuleCore = AceOO.Mixin { | 
| flickerstreak@23 | 31 									"NewModule", | 
| flickerstreak@23 | 32 									"HasModule", | 
| flickerstreak@23 | 33 									"GetModule", | 
| flickerstreak@23 | 34 									"IsModule", | 
| flickerstreak@23 | 35 									"IterateModules", | 
| flickerstreak@23 | 36 									"IterateModulesWithMethod", | 
| flickerstreak@23 | 37 									"CallMethodOnAllModules", | 
| flickerstreak@23 | 38 									"SetModuleMixins", | 
| flickerstreak@23 | 39 									"SetModuleClass", | 
| flickerstreak@23 | 40 									"IsModuleActive", | 
| flickerstreak@23 | 41 									"ToggleModuleActive", | 
| flickerstreak@23 | 42 									"SetModuleDefaultState", | 
| flickerstreak@23 | 43 								  } | 
| flickerstreak@23 | 44 local AceAddon | 
| flickerstreak@23 | 45 | 
| flickerstreak@23 | 46 local function getlibrary(lib) | 
| flickerstreak@23 | 47 	if type(lib) == "string" then | 
| flickerstreak@23 | 48 		return AceLibrary(lib) | 
| flickerstreak@23 | 49 	else | 
| flickerstreak@23 | 50 		return lib | 
| flickerstreak@23 | 51 	end | 
| flickerstreak@23 | 52 end | 
| flickerstreak@23 | 53 | 
| flickerstreak@23 | 54 local new, del | 
| flickerstreak@23 | 55 do | 
| flickerstreak@23 | 56 	local list = setmetatable({}, {__mode='k'}) | 
| flickerstreak@23 | 57 	function new() | 
| flickerstreak@23 | 58 		local t = next(list) | 
| flickerstreak@23 | 59 		if t then | 
| flickerstreak@23 | 60 			list[t] = nil | 
| flickerstreak@23 | 61 			return t | 
| flickerstreak@23 | 62 		else | 
| flickerstreak@23 | 63 			return {} | 
| flickerstreak@23 | 64 		end | 
| flickerstreak@23 | 65 	end | 
| flickerstreak@23 | 66 	function del(t) | 
| flickerstreak@23 | 67 		for k in pairs(t) do | 
| flickerstreak@23 | 68 			t[k] = nil | 
| flickerstreak@23 | 69 		end | 
| flickerstreak@23 | 70 		list[t] = true | 
| flickerstreak@23 | 71 		return nil | 
| flickerstreak@23 | 72 	end | 
| flickerstreak@23 | 73 end | 
| flickerstreak@23 | 74 | 
| flickerstreak@23 | 75 local iterList = setmetatable({}, {__mode='v'}) | 
| flickerstreak@23 | 76 local modulesWithMethod = setmetatable({}, {__mode='kv'}) | 
| flickerstreak@23 | 77 do | 
| flickerstreak@23 | 78 	local function func(t) | 
| flickerstreak@23 | 79 		local i = t.i + 1 | 
| flickerstreak@23 | 80 		local l = t.l | 
| flickerstreak@23 | 81 		local k = l[i] | 
| flickerstreak@23 | 82 		if k then | 
| flickerstreak@23 | 83 			t.i = i | 
| flickerstreak@23 | 84 			return k, l.m[k] | 
| flickerstreak@23 | 85 		else | 
| flickerstreak@23 | 86 			t = del(t) | 
| flickerstreak@23 | 87 		end | 
| flickerstreak@23 | 88 	end | 
| flickerstreak@23 | 89 	function AceModuleCore:IterateModules() | 
| flickerstreak@23 | 90 		local list = iterList[self] | 
| flickerstreak@23 | 91 		if not list then | 
| flickerstreak@23 | 92 			list = new() | 
| flickerstreak@23 | 93 			for k in pairs(self.modules) do | 
| flickerstreak@23 | 94 				list[#list+1] = k | 
| flickerstreak@23 | 95 			end | 
| flickerstreak@23 | 96 			table.sort(list) | 
| flickerstreak@23 | 97 			list.m = self.modules | 
| flickerstreak@23 | 98 			iterList[self] = list | 
| flickerstreak@23 | 99 		end | 
| flickerstreak@23 | 100 		local t = new() | 
| flickerstreak@23 | 101 		t.i = 0 | 
| flickerstreak@23 | 102 		t.l = list | 
| flickerstreak@23 | 103 		return func, t, nil | 
| flickerstreak@23 | 104 	end | 
| flickerstreak@23 | 105 | 
| flickerstreak@23 | 106 	function AceModuleCore:IterateModulesWithMethod(method) | 
| flickerstreak@23 | 107 		local masterList = modulesWithMethod[self] | 
| flickerstreak@23 | 108 		if not masterList then | 
| flickerstreak@23 | 109 			masterList = new() | 
| flickerstreak@23 | 110 			modulesWithMethod[self] = masterList | 
| flickerstreak@23 | 111 		end | 
| flickerstreak@23 | 112 		local list = masterList[method] | 
| flickerstreak@23 | 113 		if not list then | 
| flickerstreak@23 | 114 			list = new() | 
| flickerstreak@23 | 115 			for k, v in pairs(self.modules) do | 
| flickerstreak@23 | 116 				if self:IsModuleActive(k) and type(v[method]) == "function" then | 
| flickerstreak@23 | 117 					list[#list+1] = k | 
| flickerstreak@23 | 118 				end | 
| flickerstreak@23 | 119 			end | 
| flickerstreak@23 | 120 			table.sort(list) | 
| flickerstreak@23 | 121 			list.m = self.modules | 
| flickerstreak@23 | 122 			masterList[method] = list | 
| flickerstreak@23 | 123 		end | 
| flickerstreak@23 | 124 		local t = new() | 
| flickerstreak@23 | 125 		t.i = 0 | 
| flickerstreak@23 | 126 		t.l = list | 
| flickerstreak@23 | 127 		return func, t, nil | 
| flickerstreak@23 | 128 	end | 
| flickerstreak@23 | 129 | 
| flickerstreak@23 | 130 --[[---------------------------------------------------------------------------------- | 
| flickerstreak@23 | 131 Notes: | 
| flickerstreak@23 | 132 	Safely calls the given method on all active modules if it exists on said modules. This will automatically subvert any errors that occur in the modules. | 
| flickerstreak@23 | 133 Arguments: | 
| flickerstreak@23 | 134 	string - the name of the method. | 
| flickerstreak@23 | 135 	tuple - the list of arguments to call the method with. | 
| flickerstreak@23 | 136 Example: | 
| flickerstreak@23 | 137 	core:CallMethodOnAllModules("OnSomething") | 
| flickerstreak@23 | 138 	core:CallMethodOnAllModules("OnSomethingElse", 1, 2, 3, 4) | 
| flickerstreak@23 | 139 ------------------------------------------------------------------------------------]] | 
| flickerstreak@23 | 140 	function AceModuleCore:CallMethodOnAllModules(method, ...) | 
| flickerstreak@23 | 141 		for name, module in self:IterateModulesWithMethod(method) do | 
| flickerstreak@23 | 142 			local success, ret = pcall(module[method], module, ...) | 
| flickerstreak@23 | 143 			if not success then | 
| flickerstreak@23 | 144 				geterrorhandler()(ret) | 
| flickerstreak@23 | 145 			end | 
| flickerstreak@23 | 146 		end | 
| flickerstreak@23 | 147 	end | 
| flickerstreak@23 | 148 end | 
| flickerstreak@23 | 149 | 
| flickerstreak@23 | 150 --[[---------------------------------------------------------------------------- | 
| flickerstreak@23 | 151 Notes: | 
| flickerstreak@23 | 152 	Create a new module, parented to self. | 
| flickerstreak@23 | 153 	The module created does, in fact, inherit from AceAddon-2.0. | 
| flickerstreak@23 | 154 Arguments: | 
| flickerstreak@23 | 155 	string - name/title of the Module. | 
| flickerstreak@23 | 156 	list of mixins the module is to inherit from. | 
| flickerstreak@23 | 157 Example: | 
| flickerstreak@23 | 158 	MyModule = core:NewModule('MyModule', "AceEvent-2.0", "AceHook-2.1") | 
| flickerstreak@23 | 159 ------------------------------------------------------------------------------]] | 
| flickerstreak@23 | 160 local tmp = {} | 
| flickerstreak@23 | 161 function AceModuleCore:NewModule(name, ...) | 
| flickerstreak@23 | 162 	if not self.modules then | 
| flickerstreak@23 | 163 		AceModuleCore:error("CreatePrototype() must be called before attempting to create a new module.", 2) | 
| flickerstreak@23 | 164 	end | 
| flickerstreak@23 | 165 	AceModuleCore:argCheck(name, 2, "string") | 
| flickerstreak@23 | 166 	if name:len() == 0 then | 
| flickerstreak@23 | 167 		AceModuleCore:error("Bad argument #2 to `NewModule`, string must not be empty") | 
| flickerstreak@23 | 168 	end | 
| flickerstreak@23 | 169 	if self.modules[name] then | 
| flickerstreak@23 | 170 		AceModuleCore:error("The module %q has already been registered", name) | 
| flickerstreak@23 | 171 	end | 
| flickerstreak@23 | 172 | 
| flickerstreak@23 | 173 	if iterList[self] then | 
| flickerstreak@23 | 174 		iterList[self] = del(iterList[self]) | 
| flickerstreak@23 | 175 	end | 
| flickerstreak@23 | 176 | 
| flickerstreak@23 | 177 	for i = 1, select('#', ...) do | 
| flickerstreak@23 | 178 		tmp[i] = getlibrary((select(i, ...))) | 
| flickerstreak@23 | 179 	end | 
| flickerstreak@23 | 180 | 
| flickerstreak@23 | 181 	if self.moduleMixins then | 
| flickerstreak@23 | 182 		for _,mixin in ipairs(self.moduleMixins) do | 
| flickerstreak@23 | 183 			local exists = false | 
| flickerstreak@23 | 184 			for _,v in ipairs(tmp) do | 
| flickerstreak@23 | 185 				if mixin == v then | 
| flickerstreak@23 | 186 					exists = true | 
| flickerstreak@23 | 187 					break | 
| flickerstreak@23 | 188 				end | 
| flickerstreak@23 | 189 			end | 
| flickerstreak@23 | 190 			if not exists then | 
| flickerstreak@23 | 191 				tmp[#tmp+1] = mixin | 
| flickerstreak@23 | 192 			end | 
| flickerstreak@23 | 193 		end | 
| flickerstreak@23 | 194 	end | 
| flickerstreak@23 | 195 | 
| flickerstreak@23 | 196 	local module = AceOO.Classpool(self.moduleClass, unpack(tmp)):new(name) | 
| flickerstreak@23 | 197 	self.modules[name] = module | 
| flickerstreak@23 | 198 	module.name = name | 
| flickerstreak@23 | 199 	module.title = name | 
| flickerstreak@23 | 200 | 
| flickerstreak@23 | 201 	AceModuleCore.totalModules[module] = self | 
| flickerstreak@23 | 202 | 
| flickerstreak@23 | 203 	if modulesWithMethod[self] then | 
| flickerstreak@23 | 204 		for k,v in pairs(modulesWithMethod[self]) do | 
| flickerstreak@23 | 205 			modulesWithMethod[self] = del(v) | 
| flickerstreak@23 | 206 		end | 
| flickerstreak@23 | 207 	end | 
| flickerstreak@23 | 208 | 
| flickerstreak@23 | 209 	if type(self.OnModuleCreated) == "function" then | 
| flickerstreak@23 | 210 		safecall(self.OnModuleCreated, self, name, module) | 
| flickerstreak@23 | 211 	end | 
| flickerstreak@23 | 212 	if AceEvent then | 
| flickerstreak@23 | 213 		AceEvent:TriggerEvent("Ace2_ModuleCreated", module) | 
| flickerstreak@23 | 214 	end | 
| flickerstreak@23 | 215 | 
| flickerstreak@23 | 216 	local num = #tmp | 
| flickerstreak@23 | 217 	for i = 1, num do | 
| flickerstreak@23 | 218 		tmp[i] = nil | 
| flickerstreak@23 | 219 	end | 
| flickerstreak@23 | 220 	return module | 
| flickerstreak@23 | 221 end | 
| flickerstreak@23 | 222 --[[---------------------------------------------------------------------------------- | 
| flickerstreak@23 | 223 Notes: | 
| flickerstreak@23 | 224 	Return whether the module names given are all available in the core. | 
| flickerstreak@23 | 225 Arguments: | 
| flickerstreak@23 | 226 	list of strings that are the names of the modules. (typically you'd only check for one) | 
| flickerstreak@23 | 227 Returns: | 
| flickerstreak@23 | 228 	* boolean - Whether all the modules are available in the core. | 
| flickerstreak@23 | 229 Example: | 
| flickerstreak@23 | 230 	if core:HasModule('Bank') then | 
| flickerstreak@23 | 231 		-- do banking | 
| flickerstreak@23 | 232 	end | 
| flickerstreak@23 | 233 ------------------------------------------------------------------------------------]] | 
| flickerstreak@23 | 234 function AceModuleCore:HasModule(...) | 
| flickerstreak@23 | 235 	for i = 1, select('#', ...) do | 
| flickerstreak@23 | 236 		if not self.modules[select(i, ...)] then | 
| flickerstreak@23 | 237 			return false | 
| flickerstreak@23 | 238 		end | 
| flickerstreak@23 | 239 	end | 
| flickerstreak@23 | 240 | 
| flickerstreak@23 | 241 	return true | 
| flickerstreak@23 | 242 end | 
| flickerstreak@23 | 243 | 
| flickerstreak@23 | 244 --[[------------------------------------------------------------------------------------ | 
| flickerstreak@23 | 245 Notes: | 
| flickerstreak@23 | 246 	Return the module "name" if it exists. | 
| flickerstreak@23 | 247 	If the module doesnot exist, an error is thrown. | 
| flickerstreak@23 | 248 Arguments: | 
| flickerstreak@23 | 249 	string - the name of the module. | 
| flickerstreak@23 | 250 Returns: | 
| flickerstreak@23 | 251 	The module requested, if it exists. | 
| flickerstreak@23 | 252 Example: | 
| flickerstreak@23 | 253 	local bank = core:GetModule('Bank') | 
| flickerstreak@23 | 254 ------------------------------------------------------------------------------------]] | 
| flickerstreak@23 | 255 function AceModuleCore:GetModule(name) | 
| flickerstreak@23 | 256 	if not self.modules then | 
| flickerstreak@23 | 257 		AceModuleCore:error("Error initializing class.  Please report error.") | 
| flickerstreak@23 | 258 	end | 
| flickerstreak@23 | 259 	if not self.modules[name] then | 
| flickerstreak@23 | 260 		AceModuleCore:error("Cannot find module %q.", name) | 
| flickerstreak@23 | 261 	end | 
| flickerstreak@23 | 262 	return self.modules[name] | 
| flickerstreak@23 | 263 end | 
| flickerstreak@23 | 264 | 
| flickerstreak@23 | 265 --[[---------------------------------------------------------------------------------- | 
| flickerstreak@23 | 266 Notes: | 
| flickerstreak@23 | 267 	Return whether the given module is actually a module. | 
| flickerstreak@23 | 268 Arguments: | 
| flickerstreak@23 | 269 	reference to the module | 
| flickerstreak@23 | 270 Returns: | 
| flickerstreak@23 | 271 	* boolean - whether the given module is actually a module. | 
| flickerstreak@23 | 272 Example: | 
| flickerstreak@23 | 273 	if core:IsModule(module) then | 
| flickerstreak@23 | 274 		-- do something | 
| flickerstreak@23 | 275 	end | 
| flickerstreak@23 | 276 	-- alternatively | 
| flickerstreak@23 | 277 	if AceModuleCore:IsModule(module) then | 
| flickerstreak@23 | 278 		-- checks all modules, no matter the parent | 
| flickerstreak@23 | 279 	end | 
| flickerstreak@23 | 280 ------------------------------------------------------------------------------------]] | 
| flickerstreak@23 | 281 function AceModuleCore:IsModule(module) | 
| flickerstreak@23 | 282 	if self == AceModuleCore then | 
| flickerstreak@23 | 283 		return AceModuleCore.totalModules[module] | 
| flickerstreak@23 | 284 	elseif type(module) == "table" then | 
| flickerstreak@23 | 285 		if module.name and self.modules[module.name] and self.modules[module.name].name == module.name then | 
| flickerstreak@23 | 286 			return true | 
| flickerstreak@23 | 287 		end | 
| flickerstreak@23 | 288 		for k,v in pairs(self.modules) do | 
| flickerstreak@23 | 289 			if v == module then | 
| flickerstreak@23 | 290 				return true | 
| flickerstreak@23 | 291 			end | 
| flickerstreak@23 | 292 		end | 
| flickerstreak@23 | 293 		return false | 
| flickerstreak@23 | 294 	end | 
| flickerstreak@23 | 295 end | 
| flickerstreak@23 | 296 | 
| flickerstreak@23 | 297 --[[---------------------------------------------------------------------------------- | 
| flickerstreak@23 | 298 Notes: | 
| flickerstreak@23 | 299  * Sets the default mixins for a given module. | 
| flickerstreak@23 | 300  * This cannot be called after :NewModule() has been called. | 
| flickerstreak@23 | 301  * This should really only be called if you use the mixins in your prototype. | 
| flickerstreak@23 | 302 Arguments: | 
| flickerstreak@23 | 303 	list of mixins (up to 20) | 
| flickerstreak@23 | 304 Example: | 
| flickerstreak@23 | 305 	core:SetModuleMixins("AceEvent-2.0", "AceHook-2.0") | 
| flickerstreak@23 | 306 ------------------------------------------------------------------------------------]] | 
| flickerstreak@23 | 307 function AceModuleCore:SetModuleMixins(...) | 
| flickerstreak@23 | 308 	if self.moduleMixins then | 
| flickerstreak@23 | 309 		AceModuleCore:error('Cannot call "SetModuleMixins" twice') | 
| flickerstreak@23 | 310 	elseif not self.modules then | 
| flickerstreak@23 | 311 		AceModuleCore:error("Error initializing class.  Please report error.") | 
| flickerstreak@23 | 312 	elseif next(self.modules) then | 
| flickerstreak@23 | 313 		AceModuleCore:error('Cannot call "SetModuleMixins" after "NewModule" has been called.') | 
| flickerstreak@23 | 314 	end | 
| flickerstreak@23 | 315 | 
| flickerstreak@23 | 316 	self.moduleMixins =  { ... } | 
| flickerstreak@23 | 317 	for i,v in ipairs(self.moduleMixins) do | 
| flickerstreak@23 | 318 		self.moduleMixins[i] = getlibrary(v) | 
| flickerstreak@23 | 319 	end | 
| flickerstreak@23 | 320 end | 
| flickerstreak@23 | 321 | 
| flickerstreak@23 | 322 -- #NODOC | 
| flickerstreak@23 | 323 function AceModuleCore:SetModuleClass(class) | 
| flickerstreak@23 | 324 	class = getlibrary(class) | 
| flickerstreak@23 | 325 	if not AceOO.inherits(class, AceOO.Class) then | 
| flickerstreak@23 | 326 		AceModuleCore:error("Bad argument #2 to `SetModuleClass' (Class expected)") | 
| flickerstreak@23 | 327 	end | 
| flickerstreak@23 | 328 	if not self.modules then | 
| flickerstreak@23 | 329 		AceModuleCore:error("Error initializing class.  Please report error.") | 
| flickerstreak@23 | 330 	end | 
| flickerstreak@23 | 331 	if self.customModuleClass then | 
| flickerstreak@23 | 332 		AceModuleCore:error("Cannot call `SetModuleClass' twice.") | 
| flickerstreak@23 | 333 	end | 
| flickerstreak@23 | 334 	self.customModuleClass = true | 
| flickerstreak@23 | 335 	self.moduleClass = class | 
| flickerstreak@23 | 336 	self.modulePrototype = class.prototype | 
| flickerstreak@23 | 337 end | 
| flickerstreak@23 | 338 | 
| flickerstreak@23 | 339 local mt = {__index=function(self, key) | 
| flickerstreak@23 | 340 	self[key] = false | 
| flickerstreak@23 | 341 	return false | 
| flickerstreak@23 | 342 end} | 
| flickerstreak@23 | 343 local defaultState = setmetatable({}, {__index=function(self, key) | 
| flickerstreak@23 | 344 	local t = setmetatable({}, mt) | 
| flickerstreak@23 | 345 	self[key] = t | 
| flickerstreak@23 | 346 	return t | 
| flickerstreak@23 | 347 end}) | 
| flickerstreak@23 | 348 | 
| flickerstreak@23 | 349 local function isDisabled(core, module) | 
| flickerstreak@23 | 350 	local moduleName | 
| flickerstreak@23 | 351 	if type(module) == "table" then | 
| flickerstreak@23 | 352 		moduleName = module.name | 
| flickerstreak@23 | 353 	else | 
| flickerstreak@23 | 354 		moduleName = module | 
| flickerstreak@23 | 355 	end | 
| flickerstreak@23 | 356 	local disabled | 
| flickerstreak@23 | 357 	if type(module) == "table" and type(module.IsActive) == "function" then | 
| flickerstreak@23 | 358 		return not module:IsActive() | 
| flickerstreak@23 | 359 	elseif AceOO.inherits(core, "AceDB-2.0") then | 
| flickerstreak@23 | 360 		local _,profile = core:GetProfile() | 
| flickerstreak@23 | 361 		disabled = core.db and core.db.raw and core.db.raw.disabledModules and core.db.raw.disabledModules[profile] and core.db.raw.disabledModules[profile][moduleName] | 
| flickerstreak@23 | 362 	else | 
| flickerstreak@23 | 363 		disabled = core.disabledModules and core.disabledModules[moduleName] | 
| flickerstreak@23 | 364 	end | 
| flickerstreak@23 | 365 	if disabled == nil then | 
| flickerstreak@23 | 366 		return defaultState[core][moduleName] | 
| flickerstreak@23 | 367 	else | 
| flickerstreak@23 | 368 		return disabled | 
| flickerstreak@23 | 369 	end | 
| flickerstreak@23 | 370 end | 
| flickerstreak@23 | 371 | 
| flickerstreak@23 | 372 --[[---------------------------------------------------------------------------------- | 
| flickerstreak@23 | 373 Notes: | 
| flickerstreak@23 | 374 	Sets the default active state of a module. This should be called before the ADDON_LOADED of the module. | 
| flickerstreak@23 | 375 Arguments: | 
| flickerstreak@23 | 376 	string - name of the module. | 
| flickerstreak@23 | 377 	table - reference to the module. | 
| flickerstreak@23 | 378 	boolean - new state. false means disabled by default, true means enabled by default (true is the default). | 
| flickerstreak@23 | 379 Example: | 
| flickerstreak@23 | 380 	self:SetModuleDefaultState('bank', false) | 
| flickerstreak@23 | 381 ------------------------------------------------------------------------------------]] | 
| flickerstreak@23 | 382 function AceModuleCore:SetModuleDefaultState(module, state) | 
| flickerstreak@23 | 383 	AceModuleCore:argCheck(module, 2, "table", "string") | 
| flickerstreak@23 | 384 	AceModuleCore:argCheck(state, 3, "boolean") | 
| flickerstreak@23 | 385 | 
| flickerstreak@23 | 386 	if type(module) == "table" then | 
| flickerstreak@23 | 387 		if not self:IsModule(module) then | 
| flickerstreak@23 | 388 			AceModuleCore:error("%q is not a module", module) | 
| flickerstreak@23 | 389 		end | 
| flickerstreak@23 | 390 		module = module.name | 
| flickerstreak@23 | 391 	end | 
| flickerstreak@23 | 392 | 
| flickerstreak@23 | 393 	defaultState[self][module] = not state | 
| flickerstreak@23 | 394 end | 
| flickerstreak@23 | 395 | 
| flickerstreak@23 | 396 --[[---------------------------------------------------------------------------------- | 
| flickerstreak@23 | 397 Notes: | 
| flickerstreak@23 | 398 Toggles the active state of a module. | 
| flickerstreak@23 | 399 | 
| flickerstreak@23 | 400 This calls module:ToggleActive([state]) if available. | 
| flickerstreak@23 | 401 | 
| flickerstreak@23 | 402 If suspending, This will call :OnDisable() on the module if it is available. Also, it will iterate through the addon's mixins and call :OnEmbedDisable(module) if available. - this in turn will, through AceEvent and others, unregister events/hooks/etc. depending on the mixin. Also, it will call :OnModuleDisable(module) on the core if it is available. | 
| flickerstreak@23 | 403 | 
| flickerstreak@23 | 404 If resuming, This will call :OnEnable(first) on the module if it is available. Also, it will iterate through the addon's mixins and call :OnEmbedEnable(module) if available. - this in turn will, through AceEvent and others, unregister events/hooks/etc. depending on the mixin. Also, it will call :OnModuleEnable(module) on the core if it is available. | 
| flickerstreak@23 | 405 | 
| flickerstreak@23 | 406 If you call :ToggleModuleActive("name or module, true) and it is already active, it silently returns, same if you pass false and it is inactive. | 
| flickerstreak@23 | 407 | 
| flickerstreak@23 | 408 Arguments: | 
| flickerstreak@23 | 409 	string/table - name of the module or a reference to the module | 
| flickerstreak@23 | 410 	[optional] boolean - new state. (default not :IsModuleActive("name" or module)) | 
| flickerstreak@23 | 411 Returns: | 
| flickerstreak@23 | 412 	* boolean - Whether the module is now in an active (enabled) state. | 
| flickerstreak@23 | 413 Example: | 
| flickerstreak@23 | 414 	self:ToggleModuleActive('bank') | 
| flickerstreak@23 | 415 ------------------------------------------------------------------------------------]] | 
| flickerstreak@23 | 416 function AceModuleCore:ToggleModuleActive(module, state) | 
| flickerstreak@23 | 417 	AceModuleCore:argCheck(module, 2, "table", "string") | 
| flickerstreak@23 | 418 	AceModuleCore:argCheck(state, 3, "nil", "boolean") | 
| flickerstreak@23 | 419 | 
| flickerstreak@23 | 420 	if type(module) == "string" then | 
| flickerstreak@23 | 421 		if not self:HasModule(module) then | 
| flickerstreak@23 | 422 			AceModuleCore:error("Cannot find module %q", module) | 
| flickerstreak@23 | 423 		end | 
| flickerstreak@23 | 424 		module = self:GetModule(module) | 
| flickerstreak@23 | 425 	elseif not self:IsModule(module) then | 
| flickerstreak@23 | 426 		AceModuleCore:error("%q is not a module", module) | 
| flickerstreak@23 | 427 	end | 
| flickerstreak@23 | 428 | 
| flickerstreak@23 | 429 	local disable | 
| flickerstreak@23 | 430 	if state == nil then | 
| flickerstreak@23 | 431 		disable = self:IsModuleActive(module) | 
| flickerstreak@23 | 432 	else | 
| flickerstreak@23 | 433 		disable = not state | 
| flickerstreak@23 | 434 		if disable ~= self:IsModuleActive(module) then | 
| flickerstreak@23 | 435 			return | 
| flickerstreak@23 | 436 		end | 
| flickerstreak@23 | 437 	end | 
| flickerstreak@23 | 438 | 
| flickerstreak@23 | 439 	if type(module.ToggleActive) == "function" then | 
| flickerstreak@23 | 440 		return module:ToggleActive(not disable) | 
| flickerstreak@23 | 441 	elseif AceOO.inherits(self, "AceDB-2.0") then | 
| flickerstreak@23 | 442 		if not self.db or not self.db.raw then | 
| flickerstreak@23 | 443 			AceModuleCore:error("Cannot toggle a module until `RegisterDB' has been called and `ADDON_LOADED' has been fired.") | 
| flickerstreak@23 | 444 		end | 
| flickerstreak@23 | 445 		if type(self.db.raw.disabledModules) ~= "table" then | 
| flickerstreak@23 | 446 			self.db.raw.disabledModules = {} | 
| flickerstreak@23 | 447 		end | 
| flickerstreak@23 | 448 		local _,profile = self:GetProfile() | 
| flickerstreak@23 | 449 		if type(self.db.raw.disabledModules[profile]) ~= "table" then | 
| flickerstreak@23 | 450 			self.db.raw.disabledModules[profile] = {} | 
| flickerstreak@23 | 451 		end | 
| flickerstreak@23 | 452 		if type(self.db.raw.disabledModules[profile][module.name]) ~= "table" then | 
| flickerstreak@23 | 453 			local value = nil | 
| flickerstreak@23 | 454 			if disable ~= defaultState[self][module.name] then | 
| flickerstreak@23 | 455 				value = disable | 
| flickerstreak@23 | 456 			end | 
| flickerstreak@23 | 457 			self.db.raw.disabledModules[profile][module.name] = value | 
| flickerstreak@23 | 458 		end | 
| flickerstreak@23 | 459 		if not disable then | 
| flickerstreak@23 | 460 			if not next(self.db.raw.disabledModules[profile]) then | 
| flickerstreak@23 | 461 				self.db.raw.disabledModules[profile] = nil | 
| flickerstreak@23 | 462 			end | 
| flickerstreak@23 | 463 			if not next(self.db.raw.disabledModules) then | 
| flickerstreak@23 | 464 				self.db.raw.disabledModules = nil | 
| flickerstreak@23 | 465 			end | 
| flickerstreak@23 | 466 		end | 
| flickerstreak@23 | 467 	else | 
| flickerstreak@23 | 468 		if type(self.disabledModules) ~= "table" then | 
| flickerstreak@23 | 469 			self.disabledModules = {} | 
| flickerstreak@23 | 470 		end | 
| flickerstreak@23 | 471 		local value = nil | 
| flickerstreak@23 | 472 		if disable ~= defaultState[self][module.name] then | 
| flickerstreak@23 | 473 			value = disable | 
| flickerstreak@23 | 474 		end | 
| flickerstreak@23 | 475 		self.disabledModules[module.name] = value | 
| flickerstreak@23 | 476 	end | 
| flickerstreak@23 | 477 	if AceOO.inherits(module, "AceAddon-2.0") then | 
| flickerstreak@23 | 478 		if not AceAddon.addonsStarted[module] then | 
| flickerstreak@23 | 479 			return | 
| flickerstreak@23 | 480 		end | 
| flickerstreak@23 | 481 	end | 
| flickerstreak@23 | 482 	if not disable then | 
| flickerstreak@23 | 483 		local first = nil | 
| flickerstreak@23 | 484 		if AceOO.inherits(module, "AceAddon-2.0") then | 
| flickerstreak@23 | 485 			if AceAddon.addonsEnabled and not AceAddon.addonsEnabled[module] then | 
| flickerstreak@23 | 486 				AceAddon.addonsEnabled[module] = true | 
| flickerstreak@23 | 487 				first = true | 
| flickerstreak@23 | 488 			end | 
| flickerstreak@23 | 489 		end | 
| flickerstreak@23 | 490 		local current = module.class | 
| flickerstreak@23 | 491 		while true do | 
| flickerstreak@23 | 492 			if current == AceOO.Class then | 
| flickerstreak@23 | 493 				break | 
| flickerstreak@23 | 494 			end | 
| flickerstreak@23 | 495 			if current.mixins then | 
| flickerstreak@23 | 496 				for mixin in pairs(current.mixins) do | 
| flickerstreak@23 | 497 					if type(mixin.OnEmbedEnable) == "function" then | 
| flickerstreak@23 | 498 						safecall(mixin.OnEmbedEnable, mixin, module, first) | 
| flickerstreak@23 | 499 					end | 
| flickerstreak@23 | 500 				end | 
| flickerstreak@23 | 501 			end | 
| flickerstreak@23 | 502 			current = current.super | 
| flickerstreak@23 | 503 		end | 
| flickerstreak@23 | 504 		if type(module.OnEnable) == "function" then | 
| flickerstreak@23 | 505 			safecall(module.OnEnable, module, first) | 
| flickerstreak@23 | 506 		end | 
| flickerstreak@23 | 507 		if AceEvent then | 
| flickerstreak@23 | 508 			AceEvent:TriggerEvent("Ace2_AddonEnabled", module, first) | 
| flickerstreak@23 | 509 		end | 
| flickerstreak@23 | 510 	else | 
| flickerstreak@23 | 511 		local current = module.class | 
| flickerstreak@23 | 512 		while true do | 
| flickerstreak@23 | 513 			if current == AceOO.Class then | 
| flickerstreak@23 | 514 				break | 
| flickerstreak@23 | 515 			end | 
| flickerstreak@23 | 516 			if current.mixins then | 
| flickerstreak@23 | 517 				for mixin in pairs(current.mixins) do | 
| flickerstreak@23 | 518 					if type(mixin.OnEmbedDisable) == "function" then | 
| flickerstreak@23 | 519 						safecall(mixin.OnEmbedDisable, mixin, module) | 
| flickerstreak@23 | 520 					end | 
| flickerstreak@23 | 521 				end | 
| flickerstreak@23 | 522 			end | 
| flickerstreak@23 | 523 			current = current.super | 
| flickerstreak@23 | 524 		end | 
| flickerstreak@23 | 525 		if type(module.OnDisable) == "function" then | 
| flickerstreak@23 | 526 			safecall(module.OnDisable, module) | 
| flickerstreak@23 | 527 		end | 
| flickerstreak@23 | 528 		if AceEvent then | 
| flickerstreak@23 | 529 			AceEvent:TriggerEvent("Ace2_AddonDisabled", module) | 
| flickerstreak@23 | 530 		end | 
| flickerstreak@23 | 531 	end | 
| flickerstreak@23 | 532 	return not disable | 
| flickerstreak@23 | 533 end | 
| flickerstreak@23 | 534 | 
| flickerstreak@23 | 535 --[[----------------------------------------------------------------------- | 
| flickerstreak@23 | 536 Notes: | 
| flickerstreak@23 | 537 	Returns whether the module is in an active (enabled) state. This calls module:IsActive() if available. if notLoaded is set, then "name" must be a string. | 
| flickerstreak@23 | 538 Arguments: | 
| flickerstreak@23 | 539 	string/table - name of the module or a reference to the module | 
| flickerstreak@23 | 540 	[optional] - boolean - if set, this will check modules that are not loaded as well. (default: false) | 
| flickerstreak@23 | 541 Returns: | 
| flickerstreak@23 | 542 	* boolean - Whether the module is in an active (enabled) state. | 
| flickerstreak@23 | 543 Example: | 
| flickerstreak@23 | 544 	assert(self:IsModuleActive('bank')) | 
| flickerstreak@23 | 545 ------------------------------------------------------------------------]] | 
| flickerstreak@23 | 546 function AceModuleCore:IsModuleActive(module, notLoaded) | 
| flickerstreak@23 | 547 	AceModuleCore:argCheck(module, 2, "table", "string") | 
| flickerstreak@23 | 548 	AceModuleCore:argCheck(notLoaded, 3, "nil", "boolean") | 
| flickerstreak@23 | 549 	if notLoaded then | 
| flickerstreak@23 | 550 		AceModuleCore:argCheck(module, 2, "string") | 
| flickerstreak@23 | 551 	end | 
| flickerstreak@23 | 552 | 
| flickerstreak@23 | 553 	if AceModuleCore == self then | 
| flickerstreak@23 | 554 		self:argCheck(module, 2, "table") | 
| flickerstreak@23 | 555 | 
| flickerstreak@23 | 556 		local core = AceModuleCore.totalModules[module] | 
| flickerstreak@23 | 557 		if not core then | 
| flickerstreak@23 | 558 			self:error("Bad argument #2 to `IsModuleActive'. Not a module") | 
| flickerstreak@23 | 559 		end | 
| flickerstreak@23 | 560 		return core:IsModuleActive(module) | 
| flickerstreak@23 | 561 	end | 
| flickerstreak@23 | 562 | 
| flickerstreak@23 | 563 	if type(module) == "string" then | 
| flickerstreak@23 | 564 		if not notLoaded and not self:HasModule(module) then | 
| flickerstreak@23 | 565 			AceModuleCore:error("Cannot find module %q", module) | 
| flickerstreak@23 | 566 		end | 
| flickerstreak@23 | 567 		if not notLoaded then | 
| flickerstreak@23 | 568 			module = self:GetModule(module) | 
| flickerstreak@23 | 569 		else | 
| flickerstreak@23 | 570 			module = self:HasModule(module) and self:GetModule(module) or module | 
| flickerstreak@23 | 571 		end | 
| flickerstreak@23 | 572 	else | 
| flickerstreak@23 | 573 		if not self:IsModule(module) then | 
| flickerstreak@23 | 574 			AceModuleCore:error("%q is not a module", module) | 
| flickerstreak@23 | 575 		end | 
| flickerstreak@23 | 576 	end | 
| flickerstreak@23 | 577 | 
| flickerstreak@23 | 578 	return not isDisabled(self, module) | 
| flickerstreak@23 | 579 end | 
| flickerstreak@23 | 580 | 
| flickerstreak@23 | 581 -- #NODOC | 
| flickerstreak@23 | 582 function AceModuleCore:OnInstanceInit(target) | 
| flickerstreak@23 | 583 	if target.modules then | 
| flickerstreak@23 | 584 		do return end | 
| flickerstreak@23 | 585 		AceModuleCore:error("OnInstanceInit cannot be called twice") | 
| flickerstreak@23 | 586 	end | 
| flickerstreak@23 | 587 | 
| flickerstreak@23 | 588 	if not AceAddon then | 
| flickerstreak@23 | 589 		if AceLibrary:HasInstance("AceAddon-2.0") then | 
| flickerstreak@23 | 590 			AceAddon = AceLibrary("AceAddon-2.0") | 
| flickerstreak@23 | 591 		else | 
| flickerstreak@23 | 592 			self:error(MAJOR_VERSION .. " requires AceAddon-2.0") | 
| flickerstreak@23 | 593 		end | 
| flickerstreak@23 | 594 	end | 
| flickerstreak@23 | 595 	target.modules = {} | 
| flickerstreak@23 | 596 | 
| flickerstreak@23 | 597 	target.moduleClass = AceOO.Class("AceAddon-2.0") | 
| flickerstreak@23 | 598 	target.modulePrototype = target.moduleClass.prototype | 
| flickerstreak@23 | 599 end | 
| flickerstreak@23 | 600 | 
| flickerstreak@23 | 601 AceModuleCore.OnManualEmbed = AceModuleCore.OnInstanceInit | 
| flickerstreak@23 | 602 | 
| flickerstreak@23 | 603 function AceModuleCore.OnEmbedProfileDisable(AceModuleCore, self, newProfile) | 
| flickerstreak@23 | 604 	if not AceOO.inherits(self, "AceDB-2.0") then | 
| flickerstreak@23 | 605 		return | 
| flickerstreak@23 | 606 	end | 
| flickerstreak@23 | 607 	local _,currentProfile = self:GetProfile() | 
| flickerstreak@23 | 608 	for k, module in pairs(self.modules) do | 
| flickerstreak@23 | 609 		if type(module.IsActive) == "function" or type(module.ToggleActive) == "function" then | 
| flickerstreak@23 | 610 			-- continue | 
| flickerstreak@23 | 611 		else | 
| flickerstreak@23 | 612 			local currentActive =  not self.db or not self.db.raw or not self.db.raw.disabledModules or not self.db.raw.disabledModules[currentProfile] or not self.db.raw.disabledModules[currentProfile][module.name] | 
| flickerstreak@23 | 613 			local newActive =  not self.db or not self.db.raw or not self.db.raw.disabledModules or not self.db.raw.disabledModules[newProfile] or not self.db.raw.disabledModules[newProfile][module.name] | 
| flickerstreak@23 | 614 			if currentActive ~= newActive then | 
| flickerstreak@23 | 615 				self:ToggleModuleActive(module) | 
| flickerstreak@23 | 616 				if not self.db.raw.disabledModules then | 
| flickerstreak@23 | 617 					self.db.raw.disabledModules = {} | 
| flickerstreak@23 | 618 				end | 
| flickerstreak@23 | 619 				if not self.db.raw.disabledModules[currentProfile] then | 
| flickerstreak@23 | 620 					self.db.raw.disabledModules[currentProfile] = {} | 
| flickerstreak@23 | 621 				end | 
| flickerstreak@23 | 622 				self.db.raw.disabledModules[currentProfile][module.name] = not currentActive or nil | 
| flickerstreak@23 | 623 			end | 
| flickerstreak@23 | 624 		end | 
| flickerstreak@23 | 625 	end | 
| flickerstreak@23 | 626 end | 
| flickerstreak@23 | 627 | 
| flickerstreak@23 | 628 -- #NODOC | 
| flickerstreak@23 | 629 function AceModuleCore:Ace2_AddonEnabled(module, first) | 
| flickerstreak@23 | 630 	local addon = self.totalModules[module] | 
| flickerstreak@23 | 631 	if not addon then | 
| flickerstreak@23 | 632 		return | 
| flickerstreak@23 | 633 	end | 
| flickerstreak@23 | 634 | 
| flickerstreak@23 | 635 	if modulesWithMethod[addon] then | 
| flickerstreak@23 | 636 		for k,v in pairs(modulesWithMethod[addon]) do | 
| flickerstreak@23 | 637 			modulesWithMethod[addon] = del(v) | 
| flickerstreak@23 | 638 		end | 
| flickerstreak@23 | 639 	end | 
| flickerstreak@23 | 640 	if type(addon.OnModuleEnable) == "function" then | 
| flickerstreak@23 | 641 		safecall(addon.OnModuleEnable, addon, module, first) | 
| flickerstreak@23 | 642 	end | 
| flickerstreak@23 | 643 end | 
| flickerstreak@23 | 644 | 
| flickerstreak@23 | 645 -- #NODOC | 
| flickerstreak@23 | 646 function AceModuleCore:Ace2_AddonDisabled(module) | 
| flickerstreak@23 | 647 	local addon = self.totalModules[module] | 
| flickerstreak@23 | 648 	if not addon then | 
| flickerstreak@23 | 649 		return | 
| flickerstreak@23 | 650 	end | 
| flickerstreak@23 | 651 | 
| flickerstreak@23 | 652 	if modulesWithMethod[addon] then | 
| flickerstreak@23 | 653 		for k,v in pairs(modulesWithMethod[addon]) do | 
| flickerstreak@23 | 654 			modulesWithMethod[addon] = del(v) | 
| flickerstreak@23 | 655 		end | 
| flickerstreak@23 | 656 	end | 
| flickerstreak@23 | 657 	if type(addon.OnModuleDisable) == "function" then | 
| flickerstreak@23 | 658 		safecall(addon.OnModuleDisable, addon, module) | 
| flickerstreak@23 | 659 	end | 
| flickerstreak@23 | 660 end | 
| flickerstreak@23 | 661 | 
| flickerstreak@23 | 662 local function activate(self, oldLib, oldDeactivate) | 
| flickerstreak@23 | 663 	AceModuleCore = self | 
| flickerstreak@23 | 664 | 
| flickerstreak@23 | 665 	self.totalModules = oldLib and oldLib.totalModules or {} | 
| flickerstreak@23 | 666 | 
| flickerstreak@23 | 667 	self:activate(oldLib, oldDeactivate) | 
| flickerstreak@23 | 668 | 
| flickerstreak@23 | 669 	if oldDeactivate then | 
| flickerstreak@23 | 670 		oldDeactivate(oldLib) | 
| flickerstreak@23 | 671 	end | 
| flickerstreak@23 | 672 end | 
| flickerstreak@23 | 673 | 
| flickerstreak@23 | 674 local function external(self, major, instance) | 
| flickerstreak@23 | 675 	if major == "AceEvent-2.0" then | 
| flickerstreak@23 | 676 		AceEvent = instance | 
| flickerstreak@23 | 677 		AceEvent:embed(self) | 
| flickerstreak@23 | 678 | 
| flickerstreak@23 | 679 		self:UnregisterAllEvents() | 
| flickerstreak@23 | 680 		self:RegisterEvent("Ace2_AddonEnabled") | 
| flickerstreak@23 | 681 		self:RegisterEvent("Ace2_AddonDisabled") | 
| flickerstreak@23 | 682 	elseif major == "AceAddon-2.0" then | 
| flickerstreak@23 | 683 		AceAddon = instance | 
| flickerstreak@23 | 684 	end | 
| flickerstreak@23 | 685 end | 
| flickerstreak@23 | 686 | 
| flickerstreak@23 | 687 AceLibrary:Register(AceModuleCore, MAJOR_VERSION, MINOR_VERSION, activate, nil, external) | 
| flickerstreak@23 | 688 AceModuleCore = AceLibrary(MAJOR_VERSION) |