2 QuestHelper_Loadtime
= {}
3 QuestHelper_File
["error.lua"] = "Development Version"
4 QuestHelper_Loadtime
["error.lua"] = GetTime()
7 Much of this code is ganked wholesale from Swatter, and is Copyright (C) 2006 Norganna.
10 QuestHelper_local_version
= QuestHelper_File
["error.lua"]
11 QuestHelper_toc_version
= GetAddOnMetadata("QuestHelper", "Version")
13 local origHandler
= geterrorhandler()
15 local QuestHelper_ErrorCatcher
= { }
17 local startup_errors
= {}
18 local completely_started
= false
19 local yelled_at_user
= false
21 local first_error
= nil
23 QuestHelper_Errors
= {}
24 QuestHelper_Errors
.crashes
= {}
26 function QuestHelper_ErrorCatcher
.TextError(text
)
27 DEFAULT_CHAT_FRAME
:AddMessage(string.format("|cffff8080QuestHelper Error Handler: |r%s", text
))
31 -- ganked verbatim from Swatter
32 function QuestHelper_ErrorCatcher
.GetAddOns()
34 for i
= 1, GetNumAddOns() do
35 local name
, title
, notes
, enabled
, loadable
, reason
, security
= GetAddOnInfo(i
)
37 local loaded
= IsAddOnLoaded(i
)
39 if not name
then name
= "Anonymous" end
40 name
= name
:gsub("[^a-zA-Z0-9]+", "")
41 local version
= GetAddOnMetadata(i
, "Version")
42 local class
= getglobal(name
)
43 if not class
or type(class
)~='table' then class
= getglobal(name
:lower()) end
44 if not class
or type(class
)~='table' then class
= getglobal(name
:sub(1,1):upper()..name
:sub(2):lower()) end
45 if not class
or type(class
)~='table' then class
= getglobal(name
:upper()) end
46 if class
and type(class
)=='table' then
47 if (class
.version
) then
48 version
= class
.version
49 elseif (class
.Version
) then
50 version
= class
.Version
51 elseif (class
.VERSION
) then
52 version
= class
.VERSION
55 local const
= getglobal(name
:upper().."_VERSION")
56 if (const
) then version
= const
end
58 if type(version
)=='table' then
60 nLog
.AddMessage("!swatter", "Swatter.lua", N_INFO
, "version is a table", name
, table.concat(version
,":"))
62 version
= table.concat(version
,":")
66 addlist
= addlist
.." "..name
..", v"..version
.."\n"
68 addlist
= addlist
.." "..name
.."\n"
77 function QuestHelper_ErrorCatcher
.CondenseErrors()
78 while next(startup_errors
) do
79 _
, err
= next(startup_errors
)
80 table.remove(startup_errors
)
84 for _
, item
in ipairs(QuestHelper_Errors
.crashes
) do
85 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
87 item
.count
= item
.count
+ 1
92 table.insert(QuestHelper_Errors
.crashes
, err
)
97 function QuestHelper_ErrorPackage(depth
)
99 timestamp
= date("%Y-%m-%d %H:%M:%S"),
101 local_version
= QuestHelper_local_version
,
102 toc_version
= QuestHelper_toc_version
,
103 game_version
= GetBuildInfo(),
104 locale
= GetLocale(),
105 mutation_passes_exceeded
= QuestHelper
and QuestHelper
.mutation_passes_exceeded
,
106 stack
= debugstack(depth
or 4, 20, 20),
110 function QuestHelper_ErrorCatcher_ExplicitError(o_msg
, o_frame
, o_stack
, ...)
113 -- We toss it into StartupErrors, and then if we're running properly, we'll merge it into the main DB.
114 local terror
= QuestHelper_ErrorPackage()
118 terror
.addons
= QuestHelper_ErrorCatcher
.GetAddOns()
119 terror
.stack
= o_stack
or terror
.stack
121 table.insert(startup_errors
, terror
)
123 if not first_error
then first_error
= terror
end
125 if completely_started
then QuestHelper_ErrorCatcher
.CondenseErrors() end
127 if not yelled_at_user
then
128 message("QuestHelper has broken. You may have to restart WoW. Type \"/qh error\" for a detailed error message.")
129 yelled_at_user
= true
133 function QuestHelper_ErrorCatcher
.OnError(o_msg
, o_frame
, o_stack
, o_etype
, ...)
134 if (string.find(o_msg
, "QuestHelper") or string.find(debugstack(2, 20, 20), "QuestHelper")) and not string.find(o_msg
, "Cartographer_POI") then
135 QuestHelper_ErrorCatcher_ExplicitError(o_msg
, o_frame
, o_stack
)
138 return origHandler(o_msg
, o_frame
, o_stack
, o_etype
, unpack(arg
or {})) -- pass it on
141 seterrorhandler(QuestHelper_ErrorCatcher
.OnError
) -- at this point we can catch errors
143 function QuestHelper_ErrorCatcher
.CompletelyStarted()
144 completely_started
= true
145 QuestHelper_ErrorCatcher
.CondenseErrors()
148 function QuestHelper_ErrorCatcher_CompletelyStarted()
149 QuestHelper_ErrorCatcher
.CompletelyStarted()
154 -- and here is the GUI
158 function QHE_Gui
.ErrorUpdate()
159 QHE_Gui
.ErrorTextinate()
160 QHE_Gui
.Error
.Box
:SetText(QHE_Gui
.Error
.curError
)
161 QHE_Gui
.Error
.Scroll
:UpdateScrollChildRect()
162 QHE_Gui
.Error
.Box
:ClearFocus()
165 function QHE_Gui
.ErrorTextinate()
167 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
)
169 QHE_Gui
.Error
.curError
= "None"
173 function QHE_Gui
.ErrorClicked()
174 if (QHE_Gui
.Error
.selected
) then return end
175 QHE_Gui
.Error
.Box
:HighlightText()
176 QHE_Gui
.Error
.selected
= true
179 function QHE_Gui
.ErrorDone()
184 -- Create our error message frame. Most of this is also ganked from Swatter.
185 QHE_Gui
.Error
= CreateFrame("Frame", "QHE_GUIErrorFrame", UIParent
)
187 QHE_Gui
.Error
:SetPoint("CENTER", "UIParent", "CENTER")
188 QHE_Gui
.Error
:SetFrameStrata("TOOLTIP")
189 QHE_Gui
.Error
:SetHeight(300)
190 QHE_Gui
.Error
:SetWidth(600)
191 QHE_Gui
.Error
:SetBackdrop({
192 bgFile
= "Interface/Tooltips/ChatBubble-Background",
193 edgeFile
= "Interface/Tooltips/ChatBubble-BackDrop",
194 tile
= true, tileSize
= 32, edgeSize
= 32,
195 insets
= { left
= 32, right
= 32, top
= 32, bottom
= 32 }
197 QHE_Gui
.Error
:SetBackdropColor(0.2,0,0, 1)
198 QHE_Gui
.Error
:SetScript("OnShow", QHE_Gui
.ErrorShow
)
199 QHE_Gui
.Error
:SetMovable(true)
201 QHE_Gui
.ProxyFrame
= CreateFrame("Frame", "QHE_GuiProxyFrame")
202 QHE_Gui
.ProxyFrame
:SetParent(QHE_Gui
.Error
)
203 QHE_Gui
.ProxyFrame
.IsShown
= function() return QHE_Gui
.Error
:IsShown() end
204 QHE_Gui
.ProxyFrame
.escCount
= 0
205 QHE_Gui
.ProxyFrame
.timer
= 0
206 QHE_Gui
.ProxyFrame
.Hide
= (
208 local numEscapes
= QHE_Gui
.numEscapes
or 1
209 self
.escCount
= self
.escCount
+ 1
210 if ( self
.escCount
>= numEscapes
) then
211 self
:GetParent():Hide()
214 if ( self
.escCount
== 1 ) then
219 QHE_Gui
.ProxyFrame
:SetScript("OnUpdate",
220 function( self
, elapsed
)
221 local timer
= self
.timer
+ elapsed
222 if ( timer
>= 1 ) then
228 table.insert(UISpecialFrames
, "QHE_GuiProxyFrame")
230 QHE_Gui
.Drag
= CreateFrame("Button", nil, QHE_Gui
.Error
)
231 QHE_Gui
.Drag
:SetPoint("TOPLEFT", QHE_Gui
.Error
, "TOPLEFT", 10,-5)
232 QHE_Gui
.Drag
:SetPoint("TOPRIGHT", QHE_Gui
.Error
, "TOPRIGHT", -10,-5)
233 QHE_Gui
.Drag
:SetHeight(8)
234 QHE_Gui
.Drag
:SetHighlightTexture("Interface\\FriendsFrame\\UI-FriendsFrame-HighlightBar")
236 QHE_Gui
.Drag
:SetScript("OnMouseDown", function() QHE_Gui
.Error
:StartMoving() end)
237 QHE_Gui
.Drag
:SetScript("OnMouseUp", function() QHE_Gui
.Error
:StopMovingOrSizing() end)
239 QHE_Gui
.Error
.Done
= CreateFrame("Button", "", QHE_Gui
.Error
, "OptionsButtonTemplate")
240 QHE_Gui
.Error
.Done
:SetText("Close")
241 QHE_Gui
.Error
.Done
:SetPoint("BOTTOMRIGHT", QHE_Gui
.Error
, "BOTTOMRIGHT", -10, 10)
242 QHE_Gui
.Error
.Done
:SetScript("OnClick", QHE_Gui
.ErrorDone
)
244 QHE_Gui
.Error
.Mesg
= QHE_Gui
.Error
:CreateFontString("", "OVERLAY", "GameFontNormalSmall")
245 QHE_Gui
.Error
.Mesg
:SetJustifyH("LEFT")
246 QHE_Gui
.Error
.Mesg
:SetPoint("TOPRIGHT", QHE_Gui
.Error
.Prev
, "TOPLEFT", -10, 0)
247 QHE_Gui
.Error
.Mesg
:SetPoint("LEFT", QHE_Gui
.Error
, "LEFT", 15, 0)
248 QHE_Gui
.Error
.Mesg
:SetHeight(20)
249 QHE_Gui
.Error
.Mesg
:SetText("Select All and Copy the above error message to report this bug.")
251 QHE_Gui
.Error
.Scroll
= CreateFrame("ScrollFrame", "QHE_GUIErrorInputScroll", QHE_Gui
.Error
, "UIPanelScrollFrameTemplate")
252 QHE_Gui
.Error
.Scroll
:SetPoint("TOPLEFT", QHE_Gui
.Error
, "TOPLEFT", 20, -20)
253 QHE_Gui
.Error
.Scroll
:SetPoint("RIGHT", QHE_Gui
.Error
, "RIGHT", -30, 0)
254 QHE_Gui
.Error
.Scroll
:SetPoint("BOTTOM", QHE_Gui
.Error
.Done
, "TOP", 0, 10)
256 QHE_Gui
.Error
.Box
= CreateFrame("EditBox", "QHE_GUIErrorEditBox", QHE_Gui
.Error
.Scroll
)
257 QHE_Gui
.Error
.Box
:SetWidth(500)
258 QHE_Gui
.Error
.Box
:SetHeight(85)
259 QHE_Gui
.Error
.Box
:SetMultiLine(true)
260 QHE_Gui
.Error
.Box
:SetAutoFocus(false)
261 QHE_Gui
.Error
.Box
:SetFontObject(GameFontHighlight
)
262 QHE_Gui
.Error
.Box
:SetScript("OnEscapePressed", QHE_Gui
.ErrorDone
)
263 QHE_Gui
.Error
.Box
:SetScript("OnTextChanged", QHE_Gui
.ErrorUpdate
)
264 QHE_Gui
.Error
.Box
:SetScript("OnEditFocusGained", QHE_Gui
.ErrorClicked
)
266 QHE_Gui
.Error
.Scroll
:SetScrollChild(QHE_Gui
.Error
.Box
)
268 function QuestHelper_ErrorCatcher_ReportError()
269 QHE_Gui
.Error
.selected
= false
270 QHE_Gui
.ErrorUpdate()