annotate DependencyLoader/Tree.lua @ 12:b230b94d4487

fixed Addon.lua to use the unhooked EnableAddOn (still needs to be changed to grab from the interface) improved the error message when creating an Addon object on a Blizzard addon (will add direct support later) implemented the hooks on EnableAddOn and LoadAddOn rearranged functions inside Tree.lua, with some edits copied OptDeps from main module to the bootstrap module, to delegate loading to the client when possible
author mckenziemc
date Fri, 10 Dec 2010 00:21:17 -0800
parents e0a4a8b5b389
children a46bf694050c
rev   line source
mckenziemc@8 1 -- Tree
mckenziemc@8 2 -- Represents a recursive "tree" of addon
mckenziemc@8 3 -- dependencies rooted at a specific addon.
mckenziemc@8 4
mckenziemc@8 5
mckenziemc@8 6 local addonName, addonTable = ...
mckenziemc@8 7
mckenziemc@8 8
mckenziemc@10 9 -- FIXME: prevent infinite loops in the recursive functions
mckenziemc@8 10
mckenziemc@8 11
mckenziemc@8 12 local Tree, tree = addonTable:NewClass("Tree")
mckenziemc@8 13
mckenziemc@8 14
mckenziemc@8 15 Tree.trees = {}
mckenziemc@8 16
mckenziemc@10 17
mckenziemc@8 18 -- internal
mckenziemc@8 19 -- Creates a new tree object
mckenziemc@8 20 -- @param root Name, index, or Addon object of the root addon.
mckenziemc@8 21 function Tree:New(root)
mckenziemc@8 22 if type(root) ~= "table" then
mckenziemc@8 23 root = addonTable.classes.Addon:Get(root)
mckenziemc@8 24 end
mckenziemc@8 25
mckenziemc@8 26 local instance = {}
mckenziemc@8 27 setmetatable(instance, self.instanceMetatable)
mckenziemc@8 28
mckenziemc@8 29 instance.root = root
mckenziemc@8 30
mckenziemc@8 31 return instance
mckenziemc@8 32 end
mckenziemc@8 33
mckenziemc@8 34
mckenziemc@8 35 --- Retrieves the tree rooted at the specified addon
mckenziemc@8 36 -- @param root Name, index, or Addon object of the root.
mckenziemc@8 37 function Tree:Get(root)
mckenziemc@8 38 if type(root) ~= "table" then
mckenziemc@8 39 root = addonTable.classes.Addon:Get(root)
mckenziemc@8 40 end
mckenziemc@8 41
mckenziemc@8 42 local tree = self.trees[root]
mckenziemc@8 43
mckenziemc@8 44 if tree then
mckenziemc@8 45 return tree
mckenziemc@8 46 else
mckenziemc@8 47 tree = self:New(root)
mckenziemc@8 48 self.trees[root] = tree
mckenziemc@8 49 return tree
mckenziemc@8 50 end
mckenziemc@8 51 end
mckenziemc@8 52
mckenziemc@8 53
mckenziemc@12 54 -- Checks if the tree rooted at the specified addon
mckenziemc@12 55 -- can be loaded if all dependencies are enabled
mckenziemc@12 56 -- and the UI is reloaded.
mckenziemc@12 57 -- Basically makes sure all dependencies are installed.
mckenziemc@12 58 function tree:CanLoad()
mckenziemc@12 59 if not self.root:CanLoad() then
mckenziemc@12 60 return false
mckenziemc@12 61 end
mckenziemc@12 62
mckenziemc@12 63 -- check all the dependencies
mckenziemc@8 64 local dependencies = {self.root:GetDependencies()}
mckenziemc@8 65 for i, depName in pairs(dependencies) do
mckenziemc@12 66 local dep = addonTable.classes.Addon:Get(depName)
mckenziemc@12 67
mckenziemc@12 68 if not dep:CanLoad() then
mckenziemc@12 69 return false
mckenziemc@12 70 end
mckenziemc@12 71
mckenziemc@8 72 local depTree = Tree:Get(depName)
mckenziemc@8 73
mckenziemc@12 74 if not depTree:CanLoad() then
mckenziemc@12 75 return false -- missing dependency
mckenziemc@10 76 end
mckenziemc@10 77 end
mckenziemc@10 78
mckenziemc@12 79 return true
mckenziemc@8 80 end
mckenziemc@8 81
mckenziemc@8 82
mckenziemc@12 83 --- Checks if the tree can be loaded on demand.
mckenziemc@12 84 -- Does not consider force-loading; dependencies must
mckenziemc@12 85 -- be enabled and LoD, or loaded
mckenziemc@10 86 function tree:CanLoD()
mckenziemc@8 87 -- since this will be used recursively, return true if
mckenziemc@8 88 -- this is already loaded.
mckenziemc@10 89 if self.root:IsLoaded() then
mckenziemc@8 90 return true
mckenziemc@8 91 end
mckenziemc@8 92
mckenziemc@8 93 -- true if all dependencies are loaded or LoD
mckenziemc@8 94
mckenziemc@10 95 if not self.root:CanLoD() then
mckenziemc@8 96 return false
mckenziemc@8 97 end
mckenziemc@8 98
mckenziemc@8 99 -- now check dependencies recursively
mckenziemc@12 100 local dependencies = {self.root:GetDependencies()}
mckenziemc@8 101 for i, depName in pairs(dependencies) do
mckenziemc@10 102 local depTree = Tree:Get(depName)
mckenziemc@8 103
mckenziemc@10 104 if not depTree:CanLoD() then
mckenziemc@10 105 return false
mckenziemc@8 106 end
mckenziemc@8 107 end
mckenziemc@8 108
mckenziemc@8 109 return true
mckenziemc@8 110 end
mckenziemc@8 111
mckenziemc@8 112
mckenziemc@12 113 --- Checks if this tree can be loaded on demand as long as
mckenziemc@12 114 -- force-loading is allowed for preparing dependencies.
mckenziemc@12 115 function tree:CanLoDWithForce()
mckenziemc@12 116 if not self.root:CanLoD() then
mckenziemc@12 117 return false
mckenziemc@8 118 end
mckenziemc@8 119
mckenziemc@8 120 -- now check dependencies recursively
mckenziemc@10 121 local dependencies = {self.root:GetDependencies()}
mckenziemc@8 122 for i, depName in pairs(dependencies) do
mckenziemc@12 123 local dep = addonTable.classes.Addon:Get(depName)
mckenziemc@10 124 local depTree = Tree:Get(depName)
mckenziemc@8 125
mckenziemc@12 126 if not dep:CanLoad() then
mckenziemc@12 127 return false
mckenziemc@8 128 end
mckenziemc@12 129
mckenziemc@12 130 if dep:CanLoD() then
mckenziemc@12 131 if not depTree:CanLoDWithForce() then
mckenziemc@12 132 return false
mckenziemc@12 133 end
mckenziemc@12 134 elseif dep:CanForceLoad() then
mckenziemc@12 135 if not depTree:CanForceLoad() then
mckenziemc@12 136 return
mckenziemc@12 137 end
mckenziemc@12 138 end
mckenziemc@8 139 end
mckenziemc@8 140
mckenziemc@8 141 return true
mckenziemc@8 142 end
mckenziemc@8 143
mckenziemc@12 144
mckenziemc@12 145
mckenziemc@12 146 --- Checks if this tree can be force-loaded.
mckenziemc@12 147 -- Does not check user settings nor if force-loading is actually available.
mckenziemc@12 148 -- @return canForceLoad True if this tree can be force loaded, false otherwise
mckenziemc@12 149 function tree:CanForceLoad()
mckenziemc@12 150 -- TODO: remove redundencies (for now they're here for design flexibility)
mckenziemc@12 151
mckenziemc@12 152 -- this addon must be loaded, able to load-on-demand, or able to force-load
mckenziemc@12 153 if self.root:IsLoaded() then
mckenziemc@12 154 return true
mckenziemc@12 155 end
mckenziemc@12 156
mckenziemc@12 157 if not self.root:CanLoad() then
mckenziemc@12 158 return false
mckenziemc@12 159 end
mckenziemc@12 160
mckenziemc@12 161 if not self.root:CanForceLoad() then
mckenziemc@12 162 return false
mckenziemc@12 163 end
mckenziemc@12 164
mckenziemc@12 165 -- now check dependencies recursively
mckenziemc@12 166 local dependencies = {self.root:GetDependencies()}
mckenziemc@12 167 for i, depName in pairs(dependencies) do
mckenziemc@12 168 local dep = addonTable.classes.Addon:Get(depName)
mckenziemc@12 169 local depTree = Tree:Get(depName)
mckenziemc@12 170
mckenziemc@12 171 if not dep:CanLoad() then
mckenziemc@12 172 return false
mckenziemc@12 173 end
mckenziemc@12 174
mckenziemc@12 175 if not dep:CanLoD() and not dep:CanForceLoad() then
mckenziemc@12 176 return false
mckenziemc@12 177 end
mckenziemc@12 178
mckenziemc@12 179 if not depTree:CanForceLoad() then
mckenziemc@12 180 return false
mckenziemc@12 181 end
mckenziemc@12 182 end
mckenziemc@12 183
mckenziemc@12 184 return
mckenziemc@12 185 end
mckenziemc@12 186
mckenziemc@12 187
mckenziemc@12 188
mckenziemc@10 189 --[[
mckenziemc@8 190 -- Loads the tree rooted at the specified addon.
mckenziemc@8 191 -- FIXME: load the root too or not?
mckenziemc@8 192 -- Supports both LoD addons and those that require force-loading.
mckenziemc@10 193 function tree:Load(addon)
mckenziemc@8 194 -- don't check if the tree can actually be loaded.
mckenziemc@8 195 -- external code should do that itself to check if it
mckenziemc@8 196 -- should even call this at all.
mckenziemc@8 197
mckenziemc@8 198 if self:ForceLoadAvailable() then
mckenziemc@8 199 -- LoD trees can also be force-loaded
mckenziemc@8 200 self:ForceLoadTree(addon)
mckenziemc@8 201 else
mckenziemc@8 202 self:LoadLoDTree(addon)
mckenziemc@8 203 end
mckenziemc@8 204 end
mckenziemc@10 205 ]]
mckenziemc@8 206
mckenziemc@8 207
mckenziemc@12 208 function tree:PrepareForReload()
mckenziemc@12 209 -- if force-loading is enabled then we have to queue this if the addon isn't lod
mckenziemc@12 210 local function callback()
mckenziemc@12 211 self.root:Enable()
mckenziemc@12 212
mckenziemc@12 213 -- check dependencies
mckenziemc@12 214 local dependencies = {self.root:GetDependencies()}
mckenziemc@12 215 for i, depName in pairs(dependencies) do
mckenziemc@12 216 Tree:Get(depName):PrepareForReload()
mckenziemc@12 217 end
mckenziemc@12 218
mckenziemc@12 219 -- prepare embeds, if they are available separately
mckenziemc@12 220 local embeds = {self.root:GetEmbeds(addon)}
mckenziemc@12 221 for i, embedName in pairs(embeds) do
mckenziemc@12 222 Tree:Get(embedName):PrepareForReload()
mckenziemc@12 223 end
mckenziemc@12 224 end
mckenziemc@12 225
mckenziemc@12 226 if IsLoggedIn() then
mckenziemc@12 227 callback()
mckenziemc@12 228 else
mckenziemc@12 229 -- TODO: replace with cleaner alternative?
mckenziemc@12 230 local frame = CreateFrame("Frame")
mckenziemc@12 231 frame:SetScript("OnEvent", callback)
mckenziemc@12 232 frame:RegisterEvent("PLAYER_LOGIN")
mckenziemc@12 233 end
mckenziemc@12 234 end
mckenziemc@12 235
mckenziemc@12 236
mckenziemc@12 237 -- I think the problem this solves is a major issue with
mckenziemc@12 238 -- migrating to separate libs. think about it more and document
mckenziemc@12 239 -- here and in project description
mckenziemc@12 240 function tree:PrepareForLoD()
mckenziemc@12 241 -- assume root is LoD
mckenziemc@12 242
mckenziemc@12 243 -- check dependencies
mckenziemc@12 244 local dependencies = {self.root:GetDependencies(addon)}
mckenziemc@12 245 for i, depName in pairs(dependencies) do
mckenziemc@12 246 local depTree = Tree:Get(depName)
mckenziemc@12 247 depTree:PrepareForLoD()
mckenziemc@12 248
mckenziemc@12 249 --[[
mckenziemc@12 250 if dep:CanLoD() then
mckenziemc@12 251 -- don't load it now but make sure its dependencies are prepared
mckenziemc@12 252 self:PrepareLoDTree(depName)
mckenziemc@12 253 else
mckenziemc@12 254 -- FIXME: if it's already loaded
mckenziemc@12 255 -- force-load it now so we can load the parent on demand
mckenziemc@12 256 self:ForceLoadTree(depName)
mckenziemc@12 257 end
mckenziemc@12 258 ]]
mckenziemc@12 259 end
mckenziemc@12 260
mckenziemc@12 261 -- prepare embeds, if they are available separately
mckenziemc@12 262 local embeds = {self.root:GetEmbeds(addon)} -- FIXME: addon?
mckenziemc@12 263 for i, embedName in pairs(embeds) do
mckenziemc@12 264 local embedTree = Tree:Get(embedName)
mckenziemc@12 265 embedTree:PrepareForLoD()
mckenziemc@12 266
mckenziemc@12 267 --[[
mckenziemc@12 268 if embed then
mckenziemc@12 269 if embed:CanLoD() then
mckenziemc@12 270 -- don't load it now but make sure its dependencies are prepared
mckenziemc@12 271 self:PrepareLoDTree(embedName)
mckenziemc@12 272 else
mckenziemc@12 273 -- FIXME: if it's already loaded
mckenziemc@12 274 -- force-load it now so we can load the parent on demand
mckenziemc@12 275 self:ForceLoadTree(depName)
mckenziemc@12 276 end
mckenziemc@12 277 end
mckenziemc@12 278 ]]
mckenziemc@12 279 end
mckenziemc@12 280 end
mckenziemc@12 281
mckenziemc@12 282
mckenziemc@8 283 -- load the root too, since it may actually be a leaf
mckenziemc@10 284 function tree:ForceLoad()
mckenziemc@8 285 -- load dependencies
mckenziemc@10 286 local dependencies = {self.root:GetDependencies()}
mckenziemc@8 287 for i, depName in pairs(dependencies) do
mckenziemc@10 288 local depTree = Tree:Get(depName)
mckenziemc@10 289 depTree:ForceLoad()
mckenziemc@8 290 end
mckenziemc@8 291
mckenziemc@8 292 -- load embeds, if they are available separately
mckenziemc@10 293 local embeds = {self.root:GetEmbeds()}
mckenziemc@8 294 for i, embedName in pairs(embeds) do
mckenziemc@10 295 local embedTree = Tree:Get(embedName)
mckenziemc@10 296 embedTree:ForceLoad()
mckenziemc@8 297 end
mckenziemc@8 298
mckenziemc@8 299 root:ForceLoad()
mckenziemc@8 300 end
mckenziemc@8 301
mckenziemc@8 302
mckenziemc@10 303 --[[ don't think i need this
mckenziemc@8 304 function core:LoadLoDTree(root)
mckenziemc@8 305 root = self:GetAddon(root)
mckenziemc@8 306 assert(root)
mckenziemc@8 307
mckenziemc@8 308 -- load dependencies
mckenziemc@8 309 local dependencies = {root:GetDependencies(addon)}
mckenziemc@8 310 for i, depName in pairs(dependencies) do
mckenziemc@8 311 self:LoadLoDTree(depName)
mckenziemc@8 312 end
mckenziemc@8 313
mckenziemc@8 314 -- load embeds, if they are available separately
mckenziemc@8 315 local embeds = {root:GetEmbeds(addon)}
mckenziemc@8 316 for i, embedName in pairs(embeds) do
mckenziemc@8 317 if Addon:Exists(embedName) then
mckenziemc@8 318 self:LoadLoDTree(embedName)
mckenziemc@8 319 end
mckenziemc@8 320 end
mckenziemc@8 321
mckenziemc@8 322 root:LoD()
mckenziemc@8 323 end
mckenziemc@10 324 ]]
mckenziemc@8 325