]> git.saurik.com Git - wxWidgets.git/blame_incremental - samples/debugrpt/debugrpt.cpp
Fix wrong in wxListCtrl::SetItemColumnImage() in r74716.
[wxWidgets.git] / samples / debugrpt / debugrpt.cpp
... / ...
CommitLineData
1///////////////////////////////////////////////////////////////////////////////
2// Name: debugrpt.cpp
3// Purpose: minimal sample showing wxDebugReport and related classes
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 2005-01-20
7// Copyright: (c) 2005 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8// Licence: wxWindows licence
9///////////////////////////////////////////////////////////////////////////////
10
11// ----------------------------------------------------------------------------
12// headers
13// ----------------------------------------------------------------------------
14
15#include "wx/app.h"
16#include "wx/log.h"
17#include "wx/frame.h"
18#include "wx/icon.h"
19#include "wx/menu.h"
20#include "wx/msgdlg.h"
21#include "wx/button.h"
22#include "wx/dcclient.h"
23
24#include "wx/datetime.h"
25#include "wx/ffile.h"
26#include "wx/filename.h"
27#include "wx/debugrpt.h"
28
29#if !wxUSE_DEBUGREPORT
30 #error "This sample can't be built without wxUSE_DEBUGREPORT"
31#endif // wxUSE_DEBUGREPORT
32
33#if !wxUSE_ON_FATAL_EXCEPTION
34 #error "This sample can't be built without wxUSE_ON_FATAL_EXCEPTION"
35#endif // wxUSE_ON_FATAL_EXCEPTION
36
37#ifndef wxHAS_IMAGES_IN_RESOURCES
38 #include "../sample.xpm"
39#endif
40
41// ----------------------------------------------------------------------------
42// custom debug reporting class
43// ----------------------------------------------------------------------------
44
45// this is your custom debug reporter: it will use curl program (which should
46// be available) to upload the crash report to the given URL (which should be
47// set up by you)
48class MyDebugReport : public wxDebugReportUpload
49{
50public:
51 MyDebugReport() : wxDebugReportUpload
52 (
53 wxT("http://your.url.here/"),
54 wxT("report:file"),
55 wxT("action")
56 )
57 {
58 }
59
60protected:
61 // this is called with the contents of the server response: you will
62 // probably want to parse the XML document in OnServerReply() instead of
63 // just dumping it as I do
64 virtual bool OnServerReply(const wxArrayString& reply)
65 {
66 if ( reply.IsEmpty() )
67 {
68 wxLogError(wxT("Didn't receive the expected server reply."));
69 return false;
70 }
71
72 wxString s(wxT("Server replied:\n"));
73
74 const size_t count = reply.GetCount();
75 for ( size_t n = 0; n < count; n++ )
76 {
77 s << wxT('\t') << reply[n] << wxT('\n');
78 }
79
80 wxLogMessage(wxT("%s"), s.c_str());
81
82 return true;
83 }
84};
85
86// another possibility would be to build email library from contrib and use
87// this class, after uncommenting it:
88#if 0
89
90#include "wx/net/email.h"
91
92class MyDebugReport : public wxDebugReportCompress
93{
94public:
95 virtual bool DoProcess()
96 {
97 if ( !wxDebugReportCompress::DoProcess() )
98 return false;
99 wxMailMessage msg(GetReportName() + wxT(" crash report"),
100 wxT("vadim@wxwindows.org"),
101 wxEmptyString, // mail body
102 wxEmptyString, // from address
103 GetCompressedFileName(),
104 wxT("crashreport.zip"));
105
106 return wxEmail::Send(msg);
107 }
108};
109
110#endif // 0
111
112// ----------------------------------------------------------------------------
113// helper functions
114// ----------------------------------------------------------------------------
115
116// just some functions to get a slightly deeper stack trace
117static void bar(const char *p)
118{
119 char *pc = 0;
120 *pc = *p;
121
122 printf("bar: %s\n", p);
123}
124
125void baz(const wxString& s)
126{
127 printf("baz: %s\n", (const char*)s.c_str());
128}
129
130void foo(int n)
131{
132 if ( n % 2 )
133 baz("odd");
134 else
135 bar("even");
136}
137
138// ----------------------------------------------------------------------------
139// main window
140// ----------------------------------------------------------------------------
141
142enum
143{
144 DebugRpt_Quit = wxID_EXIT,
145 DebugRpt_Crash = 100,
146 DebugRpt_Current,
147 DebugRpt_Paint,
148 DebugRpt_Upload,
149 DebugRpt_About = wxID_ABOUT
150};
151
152class MyFrame : public wxFrame
153{
154public:
155 MyFrame();
156
157private:
158 void OnQuit(wxCommandEvent& event);
159 void OnReportForCrash(wxCommandEvent& event);
160 void OnReportForCurrent(wxCommandEvent& event);
161 void OnReportPaint(wxCommandEvent& event);
162 void OnReportUpload(wxCommandEvent& event);
163 void OnAbout(wxCommandEvent& event);
164
165 void OnPaint(wxPaintEvent& event);
166
167
168 // number of lines drawn in OnPaint()
169 int m_numLines;
170
171 wxDECLARE_NO_COPY_CLASS(MyFrame);
172 DECLARE_EVENT_TABLE()
173};
174
175// ----------------------------------------------------------------------------
176// application class
177// ----------------------------------------------------------------------------
178
179// this is a usual application class modified to work with debug reporter
180//
181// basically just 2 things are necessary: call wxHandleFatalExceptions() as
182// early as possible and override OnFatalException() to create the report there
183class MyApp : public wxApp
184{
185public:
186 // call wxHandleFatalExceptions here
187 MyApp();
188
189 // create our main window here
190 virtual bool OnInit();
191
192 // called when a crash occurs in this application
193 virtual void OnFatalException();
194
195 // this is where we really generate the debug report
196 void GenerateReport(wxDebugReport::Context ctx);
197
198 // if this function is called, we'll use MyDebugReport which would try to
199 // upload the (next) generated debug report to its URL, otherwise we just
200 // generate the debug report and leave it in a local file
201 void UploadReport(bool doIt) { m_uploadReport = doIt; }
202
203private:
204 bool m_uploadReport;
205
206 wxDECLARE_NO_COPY_CLASS(MyApp);
207};
208
209IMPLEMENT_APP(MyApp)
210
211// ============================================================================
212// implementation
213// ============================================================================
214
215// ----------------------------------------------------------------------------
216// MyFrame
217// ----------------------------------------------------------------------------
218
219BEGIN_EVENT_TABLE(MyFrame, wxFrame)
220 EVT_MENU(DebugRpt_Quit, MyFrame::OnQuit)
221 EVT_MENU(DebugRpt_Crash, MyFrame::OnReportForCrash)
222 EVT_MENU(DebugRpt_Current, MyFrame::OnReportForCurrent)
223 EVT_MENU(DebugRpt_Paint, MyFrame::OnReportPaint)
224 EVT_MENU(DebugRpt_Upload, MyFrame::OnReportUpload)
225 EVT_MENU(DebugRpt_About, MyFrame::OnAbout)
226
227 EVT_PAINT(MyFrame::OnPaint)
228END_EVENT_TABLE()
229
230MyFrame::MyFrame()
231 : wxFrame(NULL, wxID_ANY, wxT("wxWidgets Debug Report Sample"),
232 wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE|wxDEFAULT_FRAME_STYLE)
233{
234 m_numLines = 10;
235
236 SetIcon(wxICON(sample));
237
238 wxMenu *menuFile = new wxMenu;
239 menuFile->Append(DebugRpt_Quit, wxT("E&xit\tAlt-X"));
240
241 wxMenu *menuReport = new wxMenu;
242 menuReport->Append(DebugRpt_Crash, wxT("Report for &crash\tCtrl-C"),
243 wxT("Provoke a crash inside the program and create report for it"));
244 menuReport->Append(DebugRpt_Current, wxT("Report for c&urrent context\tCtrl-U"),
245 wxT("Create report for the current program context"));
246 menuReport->Append(DebugRpt_Paint, wxT("Report for &paint handler\tCtrl-P"),
247 wxT("Provoke a repeatable crash in wxEVT_PAINT handler"));
248 menuReport->AppendSeparator();
249 menuReport->AppendCheckItem(DebugRpt_Upload, wxT("Up&load debug report"),
250 wxT("You need to configure a web server accepting debug report uploads to use this function"));
251
252 wxMenu *menuHelp = new wxMenu;
253 menuHelp->Append(DebugRpt_About, wxT("&About\tF1"));
254
255 wxMenuBar *mbar = new wxMenuBar();
256 mbar->Append(menuFile, wxT("&File"));
257 mbar->Append(menuReport, wxT("&Report"));
258 mbar->Append(menuHelp, wxT("&Help"));
259 SetMenuBar(mbar);
260
261 CreateStatusBar();
262
263 Show();
264}
265
266void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
267{
268 Close(true);
269}
270
271void MyFrame::OnReportForCrash(wxCommandEvent& WXUNUSED(event))
272{
273 // this call is going to crash
274 foo(32);
275 foo(17);
276}
277
278void MyFrame::OnReportForCurrent(wxCommandEvent& WXUNUSED(event))
279{
280 // example of manually generated report, this could be also
281 // used in wxApp::OnAssert()
282 wxGetApp().GenerateReport(wxDebugReport::Context_Current);
283}
284
285void MyFrame::OnReportPaint(wxCommandEvent& WXUNUSED(event))
286{
287 // this will result in a crash in OnPaint()
288 m_numLines = 0;
289
290 // ensure it's called immediately
291 Refresh();
292}
293
294void MyFrame::OnReportUpload(wxCommandEvent& event)
295{
296 wxGetApp().UploadReport(event.IsChecked());
297}
298
299void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
300{
301 wxMessageBox
302 (
303 wxT("wxDebugReport sample\n(c) 2005 Vadim Zeitlin <vadim@wxwindows.org>"),
304 wxT("wxWidgets Debug Report Sample"),
305 wxOK | wxICON_INFORMATION,
306 this
307 );
308}
309
310void MyFrame::OnPaint(wxPaintEvent& WXUNUSED(event))
311{
312 wxPaintDC dc(this);
313 const wxSize size = GetClientSize();
314 for ( wxCoord x = 0; x < size.x; x += size.x/m_numLines )
315 dc.DrawLine(x, 0, x, size.y);
316}
317
318// ----------------------------------------------------------------------------
319// MyApp
320// ----------------------------------------------------------------------------
321
322MyApp::MyApp()
323{
324 // user needs to explicitly enable this
325 m_uploadReport = false;
326
327 // call this to tell the library to call our OnFatalException()
328 wxHandleFatalExceptions();
329}
330
331bool MyApp::OnInit()
332{
333 if ( !wxApp::OnInit() )
334 return false;
335
336 new MyFrame;
337
338 return true;
339}
340
341void MyApp::OnFatalException()
342{
343 GenerateReport(wxDebugReport::Context_Exception);
344}
345
346void MyApp::GenerateReport(wxDebugReport::Context ctx)
347{
348 wxDebugReportCompress *report = m_uploadReport ? new MyDebugReport
349 : new wxDebugReportCompress;
350
351 // add all standard files: currently this means just a minidump and an
352 // XML file with system info and stack trace
353 report->AddAll(ctx);
354
355 // you can also call report->AddFile(...) with your own log files, files
356 // created using wxRegKey::Export() and so on, here we just add a test
357 // file containing the date of the crash
358 wxFileName fn(report->GetDirectory(), wxT("timestamp.my"));
359 wxFFile file(fn.GetFullPath(), wxT("w"));
360 if ( file.IsOpened() )
361 {
362 wxDateTime dt = wxDateTime::Now();
363 file.Write(dt.FormatISODate() + wxT(' ') + dt.FormatISOTime());
364 file.Close();
365 }
366
367 report->AddFile(fn.GetFullName(), wxT("timestamp of this report"));
368
369 // can also add an existing file directly, it will be copied
370 // automatically
371#ifdef __WXMSW__
372 report->AddFile(wxT("c:\\autoexec.bat"), wxT("DOS startup file"));
373#else
374 report->AddFile(wxT("/etc/motd"), wxT("Message of the day"));
375#endif
376
377 // calling Show() is not mandatory, but is more polite
378 if ( wxDebugReportPreviewStd().Show(*report) )
379 {
380 if ( report->Process() )
381 {
382 if ( m_uploadReport )
383 {
384 wxLogMessage(wxT("Report successfully uploaded."));
385 }
386 else
387 {
388 wxLogMessage(wxT("Report generated in \"%s\"."),
389 report->GetCompressedFileName().c_str());
390 report->Reset();
391 }
392 }
393 }
394 //else: user cancelled the report
395
396 delete report;
397}
398