comparison DependencyLoader/Tree.lua @ 15:a46bf694050c

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