fix upgrade.lua freakout
[QuestHelper.git] / error.lua
blob8ee68a2e013a48cbc3443fbc48bab3576cf1762d
1 QuestHelper_File = {}
2 QuestHelper_Loadtime = {}
3 QuestHelper_File["error.lua"] = "Development Version"
4 QuestHelper_Loadtime["error.lua"] = GetTime()
6 --[[
7 Much of this code is ganked wholesale from Swatter, and is Copyright (C) 2006 Norganna.
8 ]]
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))
28 end
31 -- ganked verbatim from Swatter
32 function QuestHelper_ErrorCatcher.GetAddOns()
33 local addlist = ""
34 for i = 1, GetNumAddOns() do
35 local name, title, notes, enabled, loadable, reason, security = GetAddOnInfo(i)
37 local loaded = IsAddOnLoaded(i)
38 if (loaded) then
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
53 end
54 end
55 local const = getglobal(name:upper().."_VERSION")
56 if (const) then version = const end
58 if type(version)=='table' then
59 if (nLog) then
60 nLog.AddMessage("!swatter", "Swatter.lua", N_INFO, "version is a table", name, table.concat(version,":"))
61 end
62 version = table.concat(version,":")
63 end
65 if (version) then
66 addlist = addlist.." "..name..", v"..version.."\n"
67 else
68 addlist = addlist.." "..name.."\n"
69 end
70 end
71 end
72 return addlist
73 end
76 -- here's the logic
77 function QuestHelper_ErrorCatcher.CondenseErrors()
78 while next(startup_errors) do
79 _, err = next(startup_errors)
80 table.remove(startup_errors)
82 local found = false
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
86 found = true
87 item.count = item.count + 1
88 end
89 end
91 if not found then
92 table.insert(QuestHelper_Errors.crashes, err)
93 end
94 end
95 end
97 function QuestHelper_ErrorPackage(depth)
98 return {
99 timestamp = date("%Y-%m-%d %H:%M:%S"),
100 stack = stack,
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, ...)
111 msg = o_msg or ""
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()
116 terror.message = msg
117 terror.count = 0
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
156 local QHE_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()
166 if first_error then
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)
168 else
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()
180 QHE_Gui.Error:Hide()
184 -- Create our error message frame. Most of this is also ganked from Swatter.
185 QHE_Gui.Error = CreateFrame("Frame", "QHE_GUIErrorFrame", UIParent)
186 QHE_Gui.Error:Hide()
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 = (
207 function( self )
208 local numEscapes = QHE_Gui.numEscapes or 1
209 self.escCount = self.escCount + 1
210 if ( self.escCount >= numEscapes ) then
211 self:GetParent():Hide()
212 self.escCount = 0
214 if ( self.escCount == 1 ) then
215 self.timer = 0
219 QHE_Gui.ProxyFrame:SetScript("OnUpdate",
220 function( self, elapsed )
221 local timer = self.timer + elapsed
222 if ( timer >= 1 ) then
223 self.escCount = 0
225 self.timer = timer
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()
271 QHE_Gui.Error:Show()