463 lines
14 KiB
Lua
463 lines
14 KiB
Lua
--[[
|
|
Name: AceModuleCore-2.0
|
|
Revision: $Rev: 17998 $
|
|
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
|
|
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
|
|
Website: http://www.wowace.com/
|
|
Documentation: http://www.wowace.com/index.php/AceModuleCore-2.0
|
|
SVN: http://svn.wowace.com/root/trunk/Ace2/AceModuleCore-2.0
|
|
Description: Mixin to provide a module system so that modules or plugins can
|
|
use an addon as its core.
|
|
Dependencies: AceLibrary, AceOO-2.0, AceAddon-2.0, AceEvent-2.0 (optional), Compost-2.0 (optional)
|
|
]]
|
|
|
|
local MAJOR_VERSION = "AceModuleCore-2.0"
|
|
local MINOR_VERSION = "$Revision: 17998 $"
|
|
|
|
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
|
|
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
|
|
|
|
if loadstring("return function(...) return ... end") and AceLibrary:HasInstance(MAJOR_VERSION) then return end -- lua51 check
|
|
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
|
|
|
|
local function safecall(func,a,b,c,d,e,f,g)
|
|
local success, err = pcall(func,a,b,c,d,e,f,g)
|
|
if not success then geterrorhandler()(err) end
|
|
end
|
|
|
|
local table_setn
|
|
do
|
|
local version = GetBuildInfo()
|
|
if string.find(version, "^2%.") then
|
|
-- 2.0.0
|
|
table_setn = function() end
|
|
else
|
|
table_setn = table.setn
|
|
end
|
|
end
|
|
|
|
local new, del
|
|
do
|
|
local list = setmetatable({}, {__mode = 'k'})
|
|
function new()
|
|
local t = next(list)
|
|
if t then
|
|
list[t] = nil
|
|
return t
|
|
else
|
|
return {}
|
|
end
|
|
end
|
|
function del(t)
|
|
for k in pairs(t) do
|
|
t[k] = nil
|
|
end
|
|
table_setn(t, 0)
|
|
list[t] = true
|
|
return nil
|
|
end
|
|
end
|
|
|
|
local AceOO = AceLibrary:GetInstance("AceOO-2.0")
|
|
local AceModuleCore = AceOO.Mixin {
|
|
"NewModule",
|
|
"HasModule",
|
|
"GetModule",
|
|
"IsModule",
|
|
"IterateModules",
|
|
"SetModuleMixins",
|
|
"SetModuleClass",
|
|
"IsModuleActive",
|
|
"ToggleModuleActive"
|
|
}
|
|
local AceEvent
|
|
|
|
local Compost = AceLibrary:HasInstance("Compost-2.0") and AceLibrary("Compost-2.0")
|
|
|
|
local function getlibrary(lib)
|
|
if type(lib) == "string" then
|
|
return AceLibrary(lib)
|
|
else
|
|
return lib
|
|
end
|
|
end
|
|
|
|
local tmp
|
|
function AceModuleCore:NewModule(name, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
|
if not self.modules then
|
|
AceModuleCore:error("CreatePrototype() must be called before attempting to create a new module.", 2)
|
|
end
|
|
AceModuleCore:argCheck(name, 2, "string")
|
|
if string.len(name) == 0 then
|
|
AceModuleCore:error("Bad argument #2 to `NewModule`, string must not be empty")
|
|
end
|
|
if self.modules[name] then
|
|
AceModuleCore:error("The module %q has already been registered", name)
|
|
end
|
|
|
|
if not tmp then
|
|
tmp = {}
|
|
end
|
|
if a1 then table.insert(tmp, a1)
|
|
if a2 then table.insert(tmp, a2)
|
|
if a3 then table.insert(tmp, a3)
|
|
if a4 then table.insert(tmp, a4)
|
|
if a5 then table.insert(tmp, a5)
|
|
if a6 then table.insert(tmp, a6)
|
|
if a7 then table.insert(tmp, a7)
|
|
if a8 then table.insert(tmp, a8)
|
|
if a9 then table.insert(tmp, a9)
|
|
if a10 then table.insert(tmp, a10)
|
|
if a11 then table.insert(tmp, a11)
|
|
if a12 then table.insert(tmp, a12)
|
|
if a13 then table.insert(tmp, a13)
|
|
if a14 then table.insert(tmp, a14)
|
|
if a15 then table.insert(tmp, a15)
|
|
if a16 then table.insert(tmp, a16)
|
|
if a17 then table.insert(tmp, a17)
|
|
if a18 then table.insert(tmp, a18)
|
|
if a19 then table.insert(tmp, a19)
|
|
if a20 then table.insert(tmp, a20)
|
|
end end end end end end end end end end end end end end end end end end end end
|
|
for k,v in ipairs(tmp) do
|
|
tmp[k] = getlibrary(v)
|
|
end
|
|
|
|
if self.moduleMixins then
|
|
for _,mixin in ipairs(self.moduleMixins) do
|
|
local exists = false
|
|
for _,v in ipairs(tmp) do
|
|
if mixin == v then
|
|
exists = true
|
|
break
|
|
end
|
|
end
|
|
if not exists then
|
|
table.insert(tmp, mixin)
|
|
end
|
|
end
|
|
end
|
|
|
|
local module = AceOO.Classpool(self.moduleClass, unpack(tmp)):new(name)
|
|
self.modules[name] = module
|
|
module.name = name
|
|
module.title = name
|
|
|
|
AceModuleCore.totalModules[module] = self
|
|
|
|
if AceEvent then
|
|
AceEvent:TriggerEvent("Ace2_ModuleCreated", module)
|
|
end
|
|
|
|
for k in pairs(tmp) do
|
|
tmp[k] = nil
|
|
end
|
|
table_setn(tmp, 0)
|
|
return module
|
|
end
|
|
|
|
function AceModuleCore:HasModule(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
|
if a1 then if not self.modules[a1] then return false end
|
|
if a2 then if not self.modules[a2] then return false end
|
|
if a3 then if not self.modules[a3] then return false end
|
|
if a4 then if not self.modules[a4] then return false end
|
|
if a5 then if not self.modules[a5] then return false end
|
|
if a6 then if not self.modules[a6] then return false end
|
|
if a7 then if not self.modules[a7] then return false end
|
|
if a8 then if not self.modules[a8] then return false end
|
|
if a9 then if not self.modules[a9] then return false end
|
|
if a10 then if not self.modules[a10] then return false end
|
|
if a11 then if not self.modules[a11] then return false end
|
|
if a12 then if not self.modules[a12] then return false end
|
|
if a13 then if not self.modules[a13] then return false end
|
|
if a14 then if not self.modules[a14] then return false end
|
|
if a15 then if not self.modules[a15] then return false end
|
|
if a16 then if not self.modules[a16] then return false end
|
|
if a17 then if not self.modules[a17] then return false end
|
|
if a18 then if not self.modules[a18] then return false end
|
|
if a19 then if not self.modules[a19] then return false end
|
|
if a20 then if not self.modules[a20] then return false end
|
|
end end end end end end end end end end end end end end end end end end end end
|
|
|
|
return true
|
|
end
|
|
|
|
function AceModuleCore:GetModule(name)
|
|
if not self.modules then
|
|
AceModuleCore:error("Error initializing class. Please report error.")
|
|
end
|
|
if not self.modules[name] then
|
|
AceModuleCore:error("Cannot find module %q.", name)
|
|
end
|
|
return self.modules[name]
|
|
end
|
|
|
|
function AceModuleCore:IsModule(module)
|
|
if self == AceModuleCore then
|
|
return AceModuleCore.totalModules[module]
|
|
else
|
|
for k,v in pairs(self.modules) do
|
|
if v == module then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
end
|
|
|
|
function AceModuleCore:IterateModules()
|
|
local t = new()
|
|
for k in pairs(self.modules) do
|
|
table.insert(t, k)
|
|
end
|
|
table.sort(t)
|
|
local i = 0
|
|
return function()
|
|
i = i + 1
|
|
local x = t[i]
|
|
if x then
|
|
return x, self.modules[x]
|
|
else
|
|
t = del(t)
|
|
return nil
|
|
end
|
|
end, nil, nil
|
|
end
|
|
|
|
function AceModuleCore:SetModuleMixins(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
|
if self.moduleMixins then
|
|
AceModuleCore:error('Cannot call "SetModuleMixins" twice')
|
|
elseif not self.modules then
|
|
AceModuleCore:error("Error initializing class. Please report error.")
|
|
elseif next(self.modules) then
|
|
AceModuleCore:error('Cannot call "SetModuleMixins" after "NewModule" has been called.')
|
|
end
|
|
|
|
self.moduleMixins = Compost and Compost:Acquire(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) or {a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20}
|
|
for k,v in ipairs(self.moduleMixins) do
|
|
self.moduleMixins[k] = getlibrary(v)
|
|
end
|
|
end
|
|
|
|
function AceModuleCore:SetModuleClass(class)
|
|
class = getlibrary(class)
|
|
AceModuleCore:assert(AceOO.inherits(class, AceOO.Class), "Bad argument #2 to `SetModuleClass' (Class expected)")
|
|
if not self.modules then
|
|
AceModuleCore:error("Error initializing class. Please report error.")
|
|
end
|
|
if self.customModuleClass then
|
|
AceModuleCore:error("Cannot call `SetModuleClass' twice.")
|
|
end
|
|
self.customModuleClass = true
|
|
self.moduleClass = class
|
|
self.modulePrototype = class.prototype
|
|
end
|
|
|
|
function AceModuleCore:ToggleModuleActive(module, state)
|
|
AceModuleCore:argCheck(module, 2, "table", "string")
|
|
AceModuleCore:argCheck(state, 3, "nil", "boolean")
|
|
|
|
if type(module) == "string" then
|
|
if not self:HasModule(module) then
|
|
AceModuleCore:error("Cannot find module %q", module)
|
|
end
|
|
module = self:GetModule(module)
|
|
else
|
|
if not self:IsModule(module) then
|
|
AceModuleCore:error("%q is not a module", module)
|
|
end
|
|
end
|
|
|
|
local disable
|
|
if state == nil then
|
|
disable = self:IsModuleActive(module)
|
|
else
|
|
disable = not state
|
|
if disable ~= self:IsModuleActive(module) then
|
|
return
|
|
end
|
|
end
|
|
|
|
if type(module.ToggleActive) == "function" then
|
|
return module:ToggleActive(not disable)
|
|
elseif AceOO.inherits(self, "AceDB-2.0") then
|
|
if not self.db or not self.db.raw then
|
|
AceModuleCore:error("Cannot toggle a module until `RegisterDB' has been called and `ADDON_LOADED' has been fireed.")
|
|
end
|
|
if type(self.db.raw.disabledModules) ~= "table" then
|
|
self.db.raw.disabledModules = Compost and Compost:Acquire() or {}
|
|
end
|
|
local _,profile = self:GetProfile()
|
|
if type(self.db.raw.disabledModules[profile]) ~= "table" then
|
|
self.db.raw.disabledModules[profile] = Compost and Compost:Acquire() or {}
|
|
end
|
|
if type(self.db.raw.disabledModules[profile][module.name]) ~= "table" then
|
|
self.db.raw.disabledModules[profile][module.name] = disable or nil
|
|
end
|
|
if not disable then
|
|
if not next(self.db.raw.disabledModules[profile]) then
|
|
if Compost then
|
|
Compost:Reclaim(self.db.raw.disabledModules[profile])
|
|
end
|
|
self.db.raw.disabledModules[profile] = nil
|
|
end
|
|
if not next(self.db.raw.disabledModules) then
|
|
if Compost then
|
|
Compost:Reclaim(self.db.raw.disabledModules)
|
|
end
|
|
self.db.raw.disabledModules = nil
|
|
end
|
|
end
|
|
else
|
|
if type(self.disabledModules) ~= "table" then
|
|
self.disabledModules = Compost and Compost:Acquire() or {}
|
|
end
|
|
self.disabledModules[module.name] = disable or nil
|
|
end
|
|
if AceOO.inherits(module, "AceAddon-2.0") then
|
|
local AceAddon = AceLibrary("AceAddon-2.0")
|
|
if not AceAddon.addonsStarted[module] then
|
|
return
|
|
end
|
|
end
|
|
if not disable then
|
|
local current = module.class
|
|
while true do
|
|
if current == AceOO.Class then
|
|
break
|
|
end
|
|
if current.mixins then
|
|
for mixin in pairs(current.mixins) do
|
|
if type(mixin.OnEmbedEnable) == "function" then
|
|
safecall(mixin.OnEmbedEnable, mixin, module)
|
|
end
|
|
end
|
|
end
|
|
current = current.super
|
|
end
|
|
if type(module.OnEnable) == "function" then
|
|
safecall(module.OnEnable, module)
|
|
end
|
|
if AceEvent then
|
|
AceEvent:TriggerEvent("Ace2_AddonEnabled", module)
|
|
end
|
|
else
|
|
local current = module.class
|
|
while true do
|
|
if current == AceOO.Class then
|
|
break
|
|
end
|
|
if current.mixins then
|
|
for mixin in pairs(current.mixins) do
|
|
if type(mixin.OnEmbedDisable) == "function" then
|
|
safecall(mixin.OnEmbedDisable, mixin, module)
|
|
end
|
|
end
|
|
end
|
|
current = current.super
|
|
end
|
|
if type(module.OnDisable) == "function" then
|
|
safecall(module.OnDisable, module)
|
|
end
|
|
if AceEvent then
|
|
AceEvent:TriggerEvent("Ace2_AddonDisabled", module)
|
|
end
|
|
end
|
|
return not disable
|
|
end
|
|
|
|
function AceModuleCore:IsModuleActive(module)
|
|
AceModuleCore:argCheck(module, 2, "table", "string")
|
|
|
|
if AceModuleCore == self then
|
|
self:argCheck(module, 2, "table")
|
|
|
|
local core = AceModuleCore.totalModules[module]
|
|
if not core then
|
|
self:error("Bad argument #2 to `IsModuleActive'. Not a module")
|
|
end
|
|
return core:IsModuleActive(module)
|
|
end
|
|
|
|
if type(module) == "string" then
|
|
if not self:HasModule(module) then
|
|
AceModuleCore:error("Cannot find module %q", module)
|
|
end
|
|
module = self:GetModule(module)
|
|
else
|
|
if not self:IsModule(module) then
|
|
AceModuleCore:error("%q is not a module", module)
|
|
end
|
|
end
|
|
|
|
if type(module.IsActive) == "function" then
|
|
return module:IsActive()
|
|
elseif AceOO.inherits(self, "AceDB-2.0") then
|
|
local _,profile = self:GetProfile()
|
|
return not self.db or not self.db.raw or not self.db.raw.disabledModules or not self.db.raw.disabledModules[profile] or not self.db.raw.disabledModules[profile][module.name]
|
|
else
|
|
return not self.disabledModules or not self.disabledModules[module.name]
|
|
end
|
|
end
|
|
|
|
function AceModuleCore:OnInstanceInit(target)
|
|
if target.modules then
|
|
AceModuleCore:error("OnInstanceInit cannot be called twice")
|
|
end
|
|
target.modules = Compost and Compost:Acquire() or {}
|
|
|
|
target.moduleClass = AceOO.Class("AceAddon-2.0")
|
|
target.modulePrototype = target.moduleClass.prototype
|
|
end
|
|
|
|
AceModuleCore.OnManualEmbed = AceModuleCore.OnInstanceInit
|
|
|
|
function AceModuleCore.OnEmbedProfileDisable(AceModuleCore, self, newProfile)
|
|
if not AceOO.inherits(self, "AceDB-2.0") then
|
|
return
|
|
end
|
|
local _,currentProfile = self:GetProfile()
|
|
for k, module in pairs(self.modules) do
|
|
if type(module.IsActive) == "function" or type(module.ToggleActive) == "function" then
|
|
-- continue
|
|
else
|
|
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]
|
|
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]
|
|
if currentActive ~= newActive then
|
|
self:ToggleModuleActive(module)
|
|
if not self.db.raw.disabledModules then
|
|
self.db.raw.disabledModules = {}
|
|
end
|
|
if not self.db.raw.disabledModules[currentProfile] then
|
|
self.db.raw.disabledModules[currentProfile] = {}
|
|
end
|
|
self.db.raw.disabledModules[currentProfile][module.name] = not currentActive or nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function activate(self, oldLib, oldDeactivate)
|
|
AceModuleCore = self
|
|
|
|
if oldLib then
|
|
self.totalModules = oldLib.totalModules
|
|
end
|
|
if not self.totalModules then
|
|
self.totalModules = {}
|
|
end
|
|
|
|
self.super.activate(self, oldLib, oldDeactivate)
|
|
end
|
|
|
|
local function external(self, major, instance)
|
|
if major == "Compost-2.0" then
|
|
Compost = instance
|
|
elseif major == "AceEvent-2.0" then
|
|
AceEvent = instance
|
|
end
|
|
end
|
|
|
|
AceLibrary:Register(AceModuleCore, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
|
|
AceModuleCore = AceLibrary(MAJOR_VERSION)
|