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
= {}
22 QuestHelper_Errors
.crashes
= {}
24 function QuestHelper_ErrorCatcher
.TextError(text
)
25 DEFAULT_CHAT_FRAME
:AddMessage(string.format("|cffff8080QuestHelper Error Handler: |r%s", text
))
29 -- ganked verbatim from Swatter
30 function QuestHelper_ErrorCatcher
.GetAddOns()
32 for i
= 1, GetNumAddOns() do
33 local name
, title
, notes
, enabled
, loadable
, reason
, security
= GetAddOnInfo(i
)
35 local loaded
= IsAddOnLoaded(i
)
37 if not name
then name
= "Anonymous" end
38 name
= name
:gsub("[^a-zA-Z0-9]+", "")
39 local version
= GetAddOnMetadata(i
, "Version")
40 local class
= getglobal(name
)
41 if not class
or type(class
)~='table' then class
= getglobal(name
:lower()) end
42 if not class
or type(class
)~='table' then class
= getglobal(name
:sub(1,1):upper()..name
:sub(2):lower()) end
43 if not class
or type(class
)~='table' then class
= getglobal(name
:upper()) end
44 if class
and type(class
)=='table' then
45 if (class
.version
) then
46 version
= class
.version
47 elseif (class
.Version
) then
48 version
= class
.Version
49 elseif (class
.VERSION
) then
50 version
= class
.VERSION
53 local const
= getglobal(name
:upper().."_VERSION")
54 if (const
) then version
= const
end
56 if type(version
)=='table' then
58 nLog
.AddMessage("!swatter", "Swatter.lua", N_INFO
, "version is a table", name
, table.concat(version
,":"))
60 version
= table.concat(version
,":")
64 addlist
= addlist
.." "..name
..", v"..version
.."\n"
66 addlist
= addlist
.." "..name
.."\n"
75 function QuestHelper_ErrorCatcher
.CondenseErrors()
76 while next(startup_errors
) do
77 _
, err
= next(startup_errors
)
78 table.remove(startup_errors
)
82 for _
, item
in ipairs(QuestHelper_Errors
.crashes
) do
83 if item
.message
== err
.message
and item
.stack
== err
.stack
and item
.local_version
== err
.local_version
and item
.toc_version
== err
.toc_version
and item
.addons
== err
.addons
and item
.game_version
== err
.game_version
and item
.locale
== err
.locale
then
85 item
.count
= item
.count
+ 1
90 table.insert(QuestHelper_Errors
.crashes
, err
)
95 function QuestHelper_ErrorPackage(depth
)
97 timestamp
= date("%Y-%m-%d %H:%M:%S"),
99 local_version
= QuestHelper_local_version
,
100 toc_version
= QuestHelper_toc_version
,
101 game_version
= GetBuildInfo(),
102 locale
= GetLocale(),
103 mutation_passes_exceeded
= QuestHelper
and QuestHelper
.mutation_passes_exceeded
,
104 stack
= debugstack(depth
or 4, 20, 20),
108 function QuestHelper_ErrorCatcher_ExplicitError(o_msg
, o_frame
, o_stack
, ...)
111 -- We toss it into StartupErrors, and then if we're running properly, we'll merge it into the main DB.
112 local terror
= QuestHelper_ErrorPackage()
116 terror
.addons
= QuestHelper_ErrorCatcher
.GetAddOns()
117 terror
.stack
= o_stack
or terror
.stack
119 table.insert(startup_errors
, terror
)
121 if not first_error
then first_error
= terror
end
123 if completely_started
then QuestHelper_ErrorCatcher
.CondenseErrors() end
125 if not yelled_at_user
then
126 message("QuestHelper has broken. You may have to restart WoW. Type \"/qh error\" for a detailed error message.")
127 yelled_at_user
= true
131 function QuestHelper_ErrorCatcher
.OnError(o_msg
, o_frame
, o_stack
, o_etype
, ...)
133 string.find(o_msg
, "QuestHelper") -- Obviously we care about our bugs
134 or 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.
136 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.
137 and not string.find(o_msg
, "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.
139 QuestHelper_ErrorCatcher_ExplicitError(o_msg
, o_frame
, o_stack
)
142 return origHandler(o_msg
, o_frame
, o_stack
, o_etype
, unpack(arg
or {})) -- pass it on
145 seterrorhandler(QuestHelper_ErrorCatcher
.OnError
) -- at this point we can catch errors
147 function QuestHelper_ErrorCatcher
.CompletelyStarted()
148 completely_started
= true
149 QuestHelper_ErrorCatcher
.CondenseErrors()
152 function QuestHelper_ErrorCatcher_CompletelyStarted()
153 QuestHelper_ErrorCatcher
.CompletelyStarted()
158 -- and here is the GUI
162 function QHE_Gui
.ErrorUpdate()
163 QHE_Gui
.ErrorTextinate()
164 QHE_Gui
.Error
.Box
:SetText(QHE_Gui
.Error
.curError
)
165 QHE_Gui
.Error
.Scroll
:UpdateScrollChildRect()
166 QHE_Gui
.Error
.Box
:ClearFocus()
169 function QHE_Gui
.ErrorTextinate()
171 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
)
173 QHE_Gui
.Error
.curError
= "None"
177 function QHE_Gui
.ErrorClicked()
178 if (QHE_Gui
.Error
.selected
) then return end
179 QHE_Gui
.Error
.Box
:HighlightText()
180 QHE_Gui
.Error
.selected
= true
183 function QHE_Gui
.ErrorDone()
188 -- Create our error message frame. Most of this is also ganked from Swatter.
189 QHE_Gui
.Error
= CreateFrame("Frame", "QHE_GUIErrorFrame", UIParent
)
191 QHE_Gui
.Error
:SetPoint("CENTER", "UIParent", "CENTER")
192 QHE_Gui
.Error
:SetFrameStrata("TOOLTIP")
193 QHE_Gui
.Error
:SetHeight(300)
194 QHE_Gui
.Error
:SetWidth(600)
195 QHE_Gui
.Error
:SetBackdrop({
196 bgFile
= "Interface/Tooltips/ChatBubble-Background",
197 edgeFile
= "Interface/Tooltips/ChatBubble-BackDrop",
198 tile
= true, tileSize
= 32, edgeSize
= 32,
199 insets
= { left
= 32, right
= 32, top
= 32, bottom
= 32 }
201 QHE_Gui
.Error
:SetBackdropColor(0.2,0,0, 1)
202 QHE_Gui
.Error
:SetScript("OnShow", QHE_Gui
.ErrorShow
)
203 QHE_Gui
.Error
:SetMovable(true)
205 QHE_Gui
.ProxyFrame
= CreateFrame("Frame", "QHE_GuiProxyFrame")
206 QHE_Gui
.ProxyFrame
:SetParent(QHE_Gui
.Error
)
207 QHE_Gui
.ProxyFrame
.IsShown
= function() return QHE_Gui
.Error
:IsShown() end
208 QHE_Gui
.ProxyFrame
.escCount
= 0
209 QHE_Gui
.ProxyFrame
.timer
= 0
210 QHE_Gui
.ProxyFrame
.Hide
= (
212 local numEscapes
= QHE_Gui
.numEscapes
or 1
213 self
.escCount
= self
.escCount
+ 1
214 if ( self
.escCount
>= numEscapes
) then
215 self
:GetParent():Hide()
218 if ( self
.escCount
== 1 ) then
223 QHE_Gui
.ProxyFrame
:SetScript("OnUpdate",
224 function( self
, elapsed
)
225 local timer
= self
.timer
+ elapsed
226 if ( timer
>= 1 ) then
232 table.insert(UISpecialFrames
, "QHE_GuiProxyFrame")
234 QHE_Gui
.Drag
= CreateFrame("Button", nil, QHE_Gui
.Error
)
235 QHE_Gui
.Drag
:SetPoint("TOPLEFT", QHE_Gui
.Error
, "TOPLEFT", 10,-5)
236 QHE_Gui
.Drag
:SetPoint("TOPRIGHT", QHE_Gui
.Error
, "TOPRIGHT", -10,-5)
237 QHE_Gui
.Drag
:SetHeight(8)
238 QHE_Gui
.Drag
:SetHighlightTexture("Interface\\FriendsFrame\\UI-FriendsFrame-HighlightBar")
240 QHE_Gui
.Drag
:SetScript("OnMouseDown", function() QHE_Gui
.Error
:StartMoving() end)
241 QHE_Gui
.Drag
:SetScript("OnMouseUp", function() QHE_Gui
.Error
:StopMovingOrSizing() end)
243 QHE_Gui
.Error
.Done
= CreateFrame("Button", "", QHE_Gui
.Error
, "OptionsButtonTemplate")
244 QHE_Gui
.Error
.Done
:SetText("Close")
245 QHE_Gui
.Error
.Done
:SetPoint("BOTTOMRIGHT", QHE_Gui
.Error
, "BOTTOMRIGHT", -10, 10)
246 QHE_Gui
.Error
.Done
:SetScript("OnClick", QHE_Gui
.ErrorDone
)
248 QHE_Gui
.Error
.Mesg
= QHE_Gui
.Error
:CreateFontString("", "OVERLAY", "GameFontNormalSmall")
249 QHE_Gui
.Error
.Mesg
:SetJustifyH("LEFT")
250 QHE_Gui
.Error
.Mesg
:SetPoint("TOPRIGHT", QHE_Gui
.Error
.Prev
, "TOPLEFT", -10, 0)
251 QHE_Gui
.Error
.Mesg
:SetPoint("LEFT", QHE_Gui
.Error
, "LEFT", 15, 0)
252 QHE_Gui
.Error
.Mesg
:SetHeight(20)
253 QHE_Gui
.Error
.Mesg
:SetText("Select All and Copy the above error message to report this bug.")
255 QHE_Gui
.Error
.Scroll
= CreateFrame("ScrollFrame", "QHE_GUIErrorInputScroll", QHE_Gui
.Error
, "UIPanelScrollFrameTemplate")
256 QHE_Gui
.Error
.Scroll
:SetPoint("TOPLEFT", QHE_Gui
.Error
, "TOPLEFT", 20, -20)
257 QHE_Gui
.Error
.Scroll
:SetPoint("RIGHT", QHE_Gui
.Error
, "RIGHT", -30, 0)
258 QHE_Gui
.Error
.Scroll
:SetPoint("BOTTOM", QHE_Gui
.Error
.Done
, "TOP", 0, 10)
260 QHE_Gui
.Error
.Box
= CreateFrame("EditBox", "QHE_GUIErrorEditBox", QHE_Gui
.Error
.Scroll
)
261 QHE_Gui
.Error
.Box
:SetWidth(500)
262 QHE_Gui
.Error
.Box
:SetHeight(85)
263 QHE_Gui
.Error
.Box
:SetMultiLine(true)
264 QHE_Gui
.Error
.Box
:SetAutoFocus(false)
265 QHE_Gui
.Error
.Box
:SetFontObject(GameFontHighlight
)
266 QHE_Gui
.Error
.Box
:SetScript("OnEscapePressed", QHE_Gui
.ErrorDone
)
267 QHE_Gui
.Error
.Box
:SetScript("OnTextChanged", QHE_Gui
.ErrorUpdate
)
268 QHE_Gui
.Error
.Box
:SetScript("OnEditFocusGained", QHE_Gui
.ErrorClicked
)
270 QHE_Gui
.Error
.Scroll
:SetScrollChild(QHE_Gui
.Error
.Box
)
272 function QuestHelper_ErrorCatcher_ReportError()
273 QHE_Gui
.Error
.selected
= false
274 QHE_Gui
.ErrorUpdate()