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@15
|
15 local classes = addonTable.classes
|
mckenziemc@15
|
16
|
mckenziemc@15
|
17
|
mckenziemc@8
|
18 Tree.trees = {}
|
mckenziemc@8
|
19
|
mckenziemc@10
|
20
|
mckenziemc@15
|
21 --- (private) Creates a new tree object.
|
mckenziemc@15
|
22 -- Assumptions: root addon exists and is not a Blizzard addon.
|
mckenziemc@8
|
23 -- @param root Name, index, or Addon object of the root addon.
|
mckenziemc@8
|
24 function Tree:New(root)
|
mckenziemc@8
|
25 if type(root) ~= "table" then
|
mckenziemc@15
|
26 root = classes.Addon:Get(root)
|
mckenziemc@8
|
27 end
|
mckenziemc@8
|
28
|
mckenziemc@8
|
29 local instance = {}
|
mckenziemc@8
|
30 setmetatable(instance, self.instanceMetatable)
|
mckenziemc@8
|
31
|
mckenziemc@8
|
32 instance.root = root
|
mckenziemc@8
|
33
|
mckenziemc@8
|
34 return instance
|
mckenziemc@8
|
35 end
|
mckenziemc@8
|
36
|
mckenziemc@8
|
37
|
mckenziemc@8
|
38 --- Retrieves the tree rooted at the specified addon
|
mckenziemc@15
|
39 -- Assumptions: root addon exists and is not a Blizzard addon
|
mckenziemc@8
|
40 -- @param root Name, index, or Addon object of the root.
|
mckenziemc@8
|
41 function Tree:Get(root)
|
mckenziemc@8
|
42 if type(root) ~= "table" then
|
mckenziemc@15
|
43 root = classes.Addon:Get(root)
|
mckenziemc@8
|
44 end
|
mckenziemc@8
|
45
|
mckenziemc@8
|
46 local tree = self.trees[root]
|
mckenziemc@8
|
47
|
mckenziemc@8
|
48 if tree then
|
mckenziemc@8
|
49 return tree
|
mckenziemc@8
|
50 else
|
mckenziemc@8
|
51 tree = self:New(root)
|
mckenziemc@8
|
52 self.trees[root] = tree
|
mckenziemc@8
|
53 return tree
|
mckenziemc@8
|
54 end
|
mckenziemc@8
|
55 end
|
mckenziemc@8
|
56
|
mckenziemc@8
|
57
|
mckenziemc@15
|
58 -- NOTE: All tree:Can functions should check the root too.
|
mckenziemc@15
|
59 -- That way, the hooks don't have to do "if addon:Can_ and tree:Can_",
|
mckenziemc@15
|
60 -- plus the tree can cache info that includes the capabilities of the
|
mckenziemc@15
|
61 -- root addon.
|
mckenziemc@15
|
62
|
mckenziemc@15
|
63
|
mckenziemc@15
|
64 --- Checks if the tree rooted at the specified addon
|
mckenziemc@12
|
65 -- can be loaded if all dependencies are enabled
|
mckenziemc@12
|
66 -- and the UI is reloaded.
|
mckenziemc@12
|
67 -- Basically makes sure all dependencies are installed.
|
mckenziemc@12
|
68 function tree:CanLoad()
|
mckenziemc@15
|
69 local root = self.root
|
mckenziemc@15
|
70
|
mckenziemc@15
|
71 if root:IsLoaded() then
|
mckenziemc@15
|
72 return true
|
mckenziemc@15
|
73 end
|
mckenziemc@15
|
74
|
mckenziemc@15
|
75 if not root:CanLoad() then
|
mckenziemc@12
|
76 return false
|
mckenziemc@12
|
77 end
|
mckenziemc@12
|
78
|
mckenziemc@12
|
79 -- check all the dependencies
|
mckenziemc@15
|
80 local dependencies = {root:GetDependencies()}
|
mckenziemc@15
|
81
|
mckenziemc@8
|
82 for i, depName in pairs(dependencies) do
|
mckenziemc@15
|
83 if not classes.Addon:Exists(depName) then
|
mckenziemc@12
|
84 return false
|
mckenziemc@12
|
85 end
|
mckenziemc@12
|
86
|
mckenziemc@15
|
87 local dep = classes.Addon:Get(depName)
|
mckenziemc@15
|
88 local depTree = Tree:Get(dep)
|
mckenziemc@8
|
89
|
mckenziemc@12
|
90 if not depTree:CanLoad() then
|
mckenziemc@15
|
91 return false
|
mckenziemc@10
|
92 end
|
mckenziemc@10
|
93 end
|
mckenziemc@10
|
94
|
mckenziemc@12
|
95 return true
|
mckenziemc@8
|
96 end
|
mckenziemc@8
|
97
|
mckenziemc@8
|
98
|
mckenziemc@12
|
99 --- Checks if the tree can be loaded on demand.
|
mckenziemc@15
|
100 -- Does not allow for force-loading; dependencies must
|
mckenziemc@15
|
101 -- already be loaded, or enabled and LoD.
|
mckenziemc@10
|
102 function tree:CanLoD()
|
mckenziemc@15
|
103 local root = self.root
|
mckenziemc@15
|
104
|
mckenziemc@15
|
105 if root:IsLoaded() then
|
mckenziemc@8
|
106 return true
|
mckenziemc@8
|
107 end
|
mckenziemc@8
|
108
|
mckenziemc@15
|
109 if not root:CanLoD() then
|
mckenziemc@8
|
110 return false
|
mckenziemc@8
|
111 end
|
mckenziemc@8
|
112
|
mckenziemc@8
|
113 -- now check dependencies recursively
|
mckenziemc@15
|
114 local dependencies = {root:GetDependencies()}
|
mckenziemc@15
|
115
|
mckenziemc@8
|
116 for i, depName in pairs(dependencies) do
|
mckenziemc@15
|
117 if not classes.Addon:Exists(depName) then
|
mckenziemc@15
|
118 return false
|
mckenziemc@15
|
119 end
|
mckenziemc@15
|
120
|
mckenziemc@15
|
121 local dep = classes.Addon:Get(depName)
|
mckenziemc@15
|
122 local depTree = Tree:Get(dep)
|
mckenziemc@8
|
123
|
mckenziemc@10
|
124 if not depTree:CanLoD() then
|
mckenziemc@10
|
125 return false
|
mckenziemc@8
|
126 end
|
mckenziemc@8
|
127 end
|
mckenziemc@8
|
128
|
mckenziemc@8
|
129 return true
|
mckenziemc@8
|
130 end
|
mckenziemc@8
|
131
|
mckenziemc@8
|
132
|
mckenziemc@15
|
133 --- Checks if this tree can be force-loaded.
|
mckenziemc@15
|
134 -- Does not check user settings nor if force-loading is actually available.
|
mckenziemc@15
|
135 -- @return canForceLoad True if this tree can be force loaded, false otherwise
|
mckenziemc@15
|
136 function tree:CanForceLoad()
|
mckenziemc@15
|
137 local root = self.root
|
mckenziemc@15
|
138 -- TODO: remove redundencies (for now they're here for design flexibility)
|
mckenziemc@15
|
139
|
mckenziemc@15
|
140 -- this addon must be loaded, able to load-on-demand, or able to force-load
|
mckenziemc@15
|
141 if root:IsLoaded() then
|
mckenziemc@15
|
142 return true
|
mckenziemc@15
|
143 end
|
mckenziemc@15
|
144
|
mckenziemc@15
|
145 if not root:CanForceLoad() then
|
mckenziemc@12
|
146 return false
|
mckenziemc@8
|
147 end
|
mckenziemc@8
|
148
|
mckenziemc@8
|
149 -- now check dependencies recursively
|
mckenziemc@15
|
150 local dependencies = {root:GetDependencies()}
|
mckenziemc@15
|
151
|
mckenziemc@8
|
152 for i, depName in pairs(dependencies) do
|
mckenziemc@15
|
153 if not classes.Addon:Exists(depName) then
|
mckenziemc@12
|
154 return false
|
mckenziemc@8
|
155 end
|
mckenziemc@12
|
156
|
mckenziemc@15
|
157 local dep = classes.Addon:Get(depName)
|
mckenziemc@15
|
158 local depTree = Tree:Get(dep)
|
mckenziemc@15
|
159
|
mckenziemc@15
|
160 if not depTree:CanForceLoad() then
|
mckenziemc@15
|
161 return false
|
mckenziemc@12
|
162 end
|
mckenziemc@8
|
163 end
|
mckenziemc@8
|
164
|
mckenziemc@8
|
165 return true
|
mckenziemc@8
|
166 end
|
mckenziemc@8
|
167
|
mckenziemc@12
|
168
|
mckenziemc@15
|
169 --- Prepares this tree to be loaded, whether through
|
mckenziemc@15
|
170 -- a ui reload or by loading on demand.
|
mckenziemc@15
|
171 -- Assumptions: CanLoad is true for this tree
|
mckenziemc@15
|
172 function tree:PrepareForLoad()
|
mckenziemc@15
|
173 local root = self.root
|
mckenziemc@15
|
174
|
mckenziemc@15
|
175 -- The Addon class will take care of delaying enables
|
mckenziemc@15
|
176 -- till after PLAYER_LOGIN if necessary.
|
mckenziemc@15
|
177
|
mckenziemc@15
|
178 root:Enable()
|
mckenziemc@15
|
179
|
mckenziemc@15
|
180 -- enable dependencies
|
mckenziemc@15
|
181 local dependencies = {root:GetDependencies()}
|
mckenziemc@15
|
182
|
mckenziemc@15
|
183 for i, depName in pairs(dependencies) do
|
mckenziemc@15
|
184 Tree:Get(depName):PrepareForLoad()
|
mckenziemc@15
|
185 end
|
mckenziemc@12
|
186
|
mckenziemc@15
|
187 -- prepare embeds, if they are available separately
|
mckenziemc@15
|
188 local embeds = {root:GetEmbeds(addon)}
|
mckenziemc@12
|
189
|
mckenziemc@15
|
190 for i, embedName in pairs(embeds) do
|
mckenziemc@15
|
191 if classes.Addon:Exists(embedName) then
|
mckenziemc@15
|
192 Tree:Get(embedName):PrepareForLoad()
|
mckenziemc@12
|
193 end
|
mckenziemc@12
|
194 end
|
mckenziemc@12
|
195 end
|
mckenziemc@12
|
196
|
mckenziemc@12
|
197
|
mckenziemc@12
|
198 -- I think the problem this solves is a major issue with
|
mckenziemc@12
|
199 -- migrating to separate libs. think about it more and document
|
mckenziemc@12
|
200 -- here and in project description
|
mckenziemc@15
|
201
|
mckenziemc@15
|
202 --- Force-loads this addon tree. If a subtree can be loaded on
|
mckenziemc@15
|
203 -- demand, this function will enable but not load the subtree.
|
mckenziemc@15
|
204 -- Assumptions: the root addon should be force-loaded, not just enabled.
|
mckenziemc@15
|
205 --function tree:ForceLoad()
|
mckenziemc@15
|
206
|
mckenziemc@15
|
207 -- Assumptions: the root is loadable-on demand, and force-load is available.
|
mckenziemc@15
|
208 -- and tree can be force-loaded
|
mckenziemc@12
|
209 function tree:PrepareForLoD()
|
mckenziemc@15
|
210 local root = self.root
|
mckenziemc@12
|
211
|
mckenziemc@15
|
212 -- prepare dependencies first (for consistency)
|
mckenziemc@15
|
213 local dependencies = {root:GetDependencies()}
|
mckenziemc@15
|
214
|
mckenziemc@12
|
215 for i, depName in pairs(dependencies) do
|
mckenziemc@15
|
216 local dep = classes.Addon:Get(depName)
|
mckenziemc@12
|
217
|
mckenziemc@15
|
218 if not dep:IsLoaded() then
|
mckenziemc@15
|
219 if dep:CanLoD() then
|
mckenziemc@15
|
220 -- don't load it now but make sure its dependencies are prepared
|
mckenziemc@15
|
221 Tree:Get(dep):PrepareForLoD()
|
mckenziemc@15
|
222 else
|
mckenziemc@15
|
223 -- Based on our assumption about the tree, this addon
|
mckenziemc@15
|
224 -- should be able to force-load.
|
mckenziemc@15
|
225 -- force-load it now so we can load the parent on demand
|
mckenziemc@15
|
226 Tree:Get(dep):ForceLoad()
|
mckenziemc@15
|
227 end
|
mckenziemc@12
|
228 end
|
mckenziemc@12
|
229 end
|
mckenziemc@12
|
230
|
mckenziemc@12
|
231 -- prepare embeds, if they are available separately
|
mckenziemc@15
|
232 local embeds = {root:GetEmbeds()}
|
mckenziemc@15
|
233
|
mckenziemc@12
|
234 for i, embedName in pairs(embeds) do
|
mckenziemc@15
|
235 if classes.Addon:Exists(embedName) then
|
mckenziemc@15
|
236 local embed = classes.Addon:Get(embedName)
|
mckenziemc@15
|
237
|
mckenziemc@15
|
238 if not embed:IsLoaded() then
|
mckenziemc@15
|
239 if embed:CanLoD() then
|
mckenziemc@15
|
240 Tree:Get(embed):PrepareForLoD()
|
mckenziemc@15
|
241 else
|
mckenziemc@15
|
242 Tree:Get(embed):ForceLoad()
|
mckenziemc@15
|
243 end
|
mckenziemc@12
|
244 end
|
mckenziemc@12
|
245 end
|
mckenziemc@12
|
246 end
|
mckenziemc@15
|
247
|
mckenziemc@15
|
248 root:Enable()
|
mckenziemc@12
|
249 end
|
mckenziemc@12
|
250
|
mckenziemc@12
|
251
|
mckenziemc@15
|
252 --- Force-loads this tree.
|
mckenziemc@15
|
253 -- This will also load any LoD addons in the tree
|
mckenziemc@10
|
254 function tree:ForceLoad()
|
mckenziemc@15
|
255 local root = self.root
|
mckenziemc@15
|
256
|
mckenziemc@15
|
257 -- FIXME: if already loaded
|
mckenziemc@15
|
258
|
mckenziemc@8
|
259 -- load dependencies
|
mckenziemc@15
|
260 local dependencies = {root:GetDependencies()}
|
mckenziemc@15
|
261
|
mckenziemc@8
|
262 for i, depName in pairs(dependencies) do
|
mckenziemc@15
|
263 Tree:Get(depName):ForceLoad()
|
mckenziemc@8
|
264 end
|
mckenziemc@8
|
265
|
mckenziemc@8
|
266 -- load embeds, if they are available separately
|
mckenziemc@15
|
267 local embeds = {root:GetEmbeds()}
|
mckenziemc@15
|
268
|
mckenziemc@8
|
269 for i, embedName in pairs(embeds) do
|
mckenziemc@15
|
270 if classes.Addon:Exists(embedName) then
|
mckenziemc@15
|
271 Tree:Get(embedName):ForceLoad()
|
mckenziemc@15
|
272 end
|
mckenziemc@8
|
273 end
|
mckenziemc@8
|
274
|
mckenziemc@8
|
275 root:ForceLoad()
|
mckenziemc@8
|
276 end
|