1 QuestHelper_File
["error.lua"] = "Development Version"
2 QuestHelper_Loadtime
["error.lua"] = GetTime()
5 Much of this code is ganked wholesale from Swatter, and is Copyright (C) 2006 Norganna.
8 QuestHelper_local_version
= QuestHelper_File
["error.lua"]
9 QuestHelper_toc_version
= GetAddOnMetadata("QuestHelper", "Version")
11 local origHandler
= geterrorhandler()
13 local QuestHelper_ErrorCatcher
= { }
15 local startup_errors
= {}
16 local completely_started
= false
17 local yelled_at_user
= false
19 local first_error
= nil
21 QuestHelper_Errors
= {}
23 function QuestHelper_ErrorCatcher
.TextError(text
)
24 DEFAULT_CHAT_FRAME
:AddMessage(string.format("|cffff8080QuestHelper Error Handler: |r%s", text
))
28 -- ganked verbatim from Swatter
29 function QuestHelper_ErrorCatcher
.GetAddOns()
31 for i
= 1, GetNumAddOns() do
32 local name
, title
, notes
, enabled
, loadable
, reason
, security
= GetAddOnInfo(i
)
34 local loaded
= IsAddOnLoaded(i
)
36 if not name
then name
= "Anonymous" end
37 name
= name
:gsub("[^a-zA-Z0-9]+", "")
38 local version
= GetAddOnMetadata(i
, "Version")
39 local class
= getglobal(name
)
40 if not class
or type(class
)~='table' then class
= getglobal(name
:lower()) end
41 if not class
or type(class
)~='table' then class
= getglobal(name
:sub(1,1):upper()..name
:sub(2):lower()) end
42 if not class
or type(class
)~='table' then class
= getglobal(name
:upper()) end
43 if class
and type(class
)=='table' then
44 if (class
.version
) then
45 version
= class
.version
46 elseif (class
.Version
) then
47 version
= class
.Version
48 elseif (class
.VERSION
) then
49 version
= class
.VERSION
52 local const
= getglobal(name
:upper().."_VERSION")
53 if (const
) then version
= const
end
55 if type(version
)=='table' then
56 version
= table.concat(version
,":")
60 addlist
= addlist
.." "..name
..", v"..version
.."\n"
62 addlist
= addlist
.." "..name
.."\n"
69 local error_uniqueness_whitelist
= {
75 function QuestHelper_ErrorCatcher
.CondenseErrors()
76 if completely_started
then
77 while next(startup_errors
) do
78 _
, err
= next(startup_errors
)
79 table.remove(startup_errors
)
81 if not QuestHelper_Errors
[err
.type] then QuestHelper_Errors
[err
.type] = {} end
85 for _
, item
in ipairs(QuestHelper_Errors
[err
.type]) do
87 for k
, v
in pairs(err
.dat
) do
88 if not error_uniqueness_whitelist
[k
] and item
[k
] ~= v
then match
= false break end
90 if match
then for k
, v
in pairs(item
) do
91 if not error_uniqueness_whitelist
[k
] and err
.dat
[k
] ~= v
then match
= false break end
95 item
.count
= (item
.count
or 1) + 1
101 table.insert(QuestHelper_Errors
[err
.type], err
.dat
)
107 function QuestHelper_ErrorCatcher_RegisterError(typ
, dat
)
108 table.insert(startup_errors
, {type = typ
, dat
= dat
})
109 QuestHelper_ErrorCatcher
.CondenseErrors()
112 function QuestHelper_ErrorPackage(depth
)
114 timestamp
= date("%Y-%m-%d %H:%M:%S"),
115 local_version
= QuestHelper_local_version
,
116 toc_version
= QuestHelper_toc_version
,
117 game_version
= GetBuildInfo(),
118 locale
= GetLocale(),
119 mutation_passes_exceeded
= QuestHelper
and QuestHelper
.mutation_passes_exceeded
,
120 stack
= debugstack(depth
or 4, 20, 20),
124 function QuestHelper_ErrorCatcher_ExplicitError(o_msg
, o_frame
, o_stack
, ...)
127 -- We toss it into StartupErrors, and then if we're running properly, we'll merge it into the main DB.
128 local terror
= QuestHelper_ErrorPackage()
131 terror
.addons
= QuestHelper_ErrorCatcher
.GetAddOns()
132 terror
.stack
= o_stack
or terror
.stack
134 QuestHelper_ErrorCatcher_RegisterError("crash", terror
)
136 if not first_error
then first_error
= terror
end
138 QuestHelper_ErrorCatcher
.CondenseErrors()
140 if not yelled_at_user
then
141 message("QuestHelper has broken. You may have to restart WoW. Type \"/qh error\" for a detailed error message.")
142 yelled_at_user
= true
146 function QuestHelper_ErrorCatcher
.OnError(o_msg
, o_frame
, o_stack
, o_etype
, ...)
150 string.find(o_msg
, "QuestHelper") -- Obviously we care about our bugs
153 string.find(debugstack(2, 20, 20), "QuestHelper") -- We're being a little overzealous and catching any bug with "QuestHelper" in the stack. This possibly should be removed, I'm not sure it's ever caught anything interesting.
154 and not string.find(o_msg
, "Cartographer_POI") -- Cartographer started throwing ridiculous numbers of errors on startup with QH in the stack, and since we caught stuff with QH in the stack, we decided these errors were ours. Urgh. Disabled.
157 and not string.match(o_msg
, "WTF\\Account\\.*") -- Sometimes the WTF file gets corrupted. This isn't our fault, since we weren't involved in writing it, and there's also nothing we can do about it - in fact we can't even retrieve the remnants of the old file. We may as well just ignore it. I suppose we could pop up a little dialog saying "clear some space on your hard drive, dufus" but, meh.
159 QuestHelper_ErrorCatcher_ExplicitError(o_msg
, o_frame
, o_stack
)
162 return origHandler(o_msg
, o_frame
, o_stack
, o_etype
, unpack(arg
or {})) -- pass it on
165 seterrorhandler(QuestHelper_ErrorCatcher
.OnError
) -- at this point we can catch errors
167 function QuestHelper_ErrorCatcher
.CompletelyStarted()
168 completely_started
= true
170 -- Our old code generated a horrifying number of redundant items. My bad. I considered going and trying to collate them into one chunk, but I think I'm just going to wipe them - it's easier, faster, and should fix some performance issues.
171 if not QuestHelper_Errors
.version
or QuestHelper_Errors
.version
~= 1 then
172 QuestHelper_Errors
= {version
= 1}
175 QuestHelper_ErrorCatcher
.CondenseErrors()
178 function QuestHelper_ErrorCatcher_CompletelyStarted()
179 QuestHelper_ErrorCatcher
.CompletelyStarted()
184 -- and here is the GUI
188 function QHE_Gui
.ErrorUpdate()
189 QHE_Gui
.ErrorTextinate()
190 QHE_Gui
.Error
.Box
:SetText(QHE_Gui
.Error
.curError
)
191 QHE_Gui
.Error
.Scroll
:UpdateScrollChildRect()
192 QHE_Gui
.Error
.Box
:ClearFocus()
195 function QHE_Gui
.ErrorTextinate()
197 QHE_Gui
.Error
.curError
= string.format("msg: %s\ntoc: %s\nv: %s\ngame: %s\nlocale: %s\ntimestamp: %s\nmutation: %s\n\n%s\naddons:\n%s", first_error
.message
, first_error
.toc_version
, first_error
.local_version
, first_error
.game_version
, first_error
.locale
, first_error
.timestamp
, tostring(first_error
.mutation_passes_exceeded
), first_error
.stack
, first_error
.addons
)
199 QHE_Gui
.Error
.curError
= "None"
203 function QHE_Gui
.ErrorClicked()
204 if (QHE_Gui
.Error
.selected
) then return end
205 QHE_Gui
.Error
.Box
:HighlightText()
206 QHE_Gui
.Error
.selected
= true
209 function QHE_Gui
.ErrorDone()
214 -- Create our error message frame. Most of this is also ganked from Swatter.
215 QHE_Gui
.Error
= CreateFrame("Frame", "QHE_GUIErrorFrame", UIParent
)
217 QHE_Gui
.Error
:SetPoint("CENTER", "UIParent", "CENTER")
218 QHE_Gui
.Error
:SetFrameStrata("TOOLTIP")
219 QHE_Gui
.Error
:SetHeight(300)
220 QHE_Gui
.Error
:SetWidth(600)
221 QHE_Gui
.Error
:SetBackdrop({
222 bgFile
= "Interface/Tooltips/ChatBubble-Background",
223 edgeFile
= "Interface/Tooltips/ChatBubble-BackDrop",
224 tile
= true, tileSize
= 32, edgeSize
= 32,
225 insets
= { left
= 32, right
= 32, top
= 32, bottom
= 32 }
227 QHE_Gui
.Error
:SetBackdropColor(0.2,0,0, 1)
228 QHE_Gui
.Error
:SetScript("OnShow", QHE_Gui
.ErrorShow
)
229 QHE_Gui
.Error
:SetMovable(true)
231 QHE_Gui
.ProxyFrame
= CreateFrame("Frame", "QHE_GuiProxyFrame")
232 QHE_Gui
.ProxyFrame
:SetParent(QHE_Gui
.Error
)
233 QHE_Gui
.ProxyFrame
.IsShown
= function() return QHE_Gui
.Error
:IsShown() end
234 QHE_Gui
.ProxyFrame
.escCount
= 0
235 QHE_Gui
.ProxyFrame
.timer
= 0
236 QHE_Gui
.ProxyFrame
.Hide
= (
238 local numEscapes
= QHE_Gui
.numEscapes
or 1
239 self
.escCount
= self
.escCount
+ 1
240 if ( self
.escCount
>= numEscapes
) then
241 self
:GetParent():Hide()
244 if ( self
.escCount
== 1 ) then
249 QHE_Gui
.ProxyFrame
:SetScript("OnUpdate",
250 function( self
, elapsed
)
251 local timer
= self
.timer
+ elapsed
252 if ( timer
>= 1 ) then
258 table.insert(UISpecialFrames
, "QHE_GuiProxyFrame")
260 QHE_Gui
.Drag
= CreateFrame("Button", nil, QHE_Gui
.Error
)
261 QHE_Gui
.Drag
:SetPoint("TOPLEFT", QHE_Gui
.Error
, "TOPLEFT", 10,-5)
262 QHE_Gui
.Drag
:SetPoint("TOPRIGHT", QHE_Gui
.Error
, "TOPRIGHT", -10,-5)
263 QHE_Gui
.Drag
:SetHeight(8)
264 QHE_Gui
.Drag
:SetHighlightTexture("Interface\\FriendsFrame\\UI-FriendsFrame-HighlightBar")
266 QHE_Gui
.Drag
:SetScript("OnMouseDown", function() QHE_Gui
.Error
:StartMoving() end)
267 QHE_Gui
.Drag
:SetScript("OnMouseUp", function() QHE_Gui
.Error
:StopMovingOrSizing() end)
269 QHE_Gui
.Error
.Done
= CreateFrame("Button", "", QHE_Gui
.Error
, "OptionsButtonTemplate")
270 QHE_Gui
.Error
.Done
:SetText("Close")
271 QHE_Gui
.Error
.Done
:SetPoint("BOTTOMRIGHT", QHE_Gui
.Error
, "BOTTOMRIGHT", -10, 10)
272 QHE_Gui
.Error
.Done
:SetScript("OnClick", QHE_Gui
.ErrorDone
)
274 QHE_Gui
.Error
.Mesg
= QHE_Gui
.Error
:CreateFontString("", "OVERLAY", "GameFontNormalSmall")
275 QHE_Gui
.Error
.Mesg
:SetJustifyH("LEFT")
276 QHE_Gui
.Error
.Mesg
:SetPoint("TOPRIGHT", QHE_Gui
.Error
.Prev
, "TOPLEFT", -10, 0)
277 QHE_Gui
.Error
.Mesg
:SetPoint("LEFT", QHE_Gui
.Error
, "LEFT", 15, 0)
278 QHE_Gui
.Error
.Mesg
:SetHeight(20)
279 QHE_Gui
.Error
.Mesg
:SetText("Select All and Copy the above error message to report this bug.")
281 QHE_Gui
.Error
.Scroll
= CreateFrame("ScrollFrame", "QHE_GUIErrorInputScroll", QHE_Gui
.Error
, "UIPanelScrollFrameTemplate")
282 QHE_Gui
.Error
.Scroll
:SetPoint("TOPLEFT", QHE_Gui
.Error
, "TOPLEFT", 20, -20)
283 QHE_Gui
.Error
.Scroll
:SetPoint("RIGHT", QHE_Gui
.Error
, "RIGHT", -30, 0)
284 QHE_Gui
.Error
.Scroll
:SetPoint("BOTTOM", QHE_Gui
.Error
.Done
, "TOP", 0, 10)
286 QHE_Gui
.Error
.Box
= CreateFrame("EditBox", "QHE_GUIErrorEditBox", QHE_Gui
.Error
.Scroll
)
287 QHE_Gui
.Error
.Box
:SetWidth(500)
288 QHE_Gui
.Error
.Box
:SetHeight(85)
289 QHE_Gui
.Error
.Box
:SetMultiLine(true)
290 QHE_Gui
.Error
.Box
:SetAutoFocus(false)
291 QHE_Gui
.Error
.Box
:SetFontObject(GameFontHighlight
)
292 QHE_Gui
.Error
.Box
:SetScript("OnEscapePressed", QHE_Gui
.ErrorDone
)
293 QHE_Gui
.Error
.Box
:SetScript("OnTextChanged", QHE_Gui
.ErrorUpdate
)
294 QHE_Gui
.Error
.Box
:SetScript("OnEditFocusGained", QHE_Gui
.ErrorClicked
)
296 QHE_Gui
.Error
.Scroll
:SetScrollChild(QHE_Gui
.Error
.Box
)
298 function QuestHelper_ErrorCatcher_ReportError()
299 QHE_Gui
.Error
.selected
= false
300 QHE_Gui
.ErrorUpdate()