annotate DependencyLoader/Tree.lua @ 14:78b28ebdc169

added embeds.xml to load.xml added a couple of other internal notes
author mckenziemc
date Fri, 10 Dec 2010 05:29:22 -0800
parents b230b94d4487
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