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