Compilation fix
[wxWidgets.git] / samples / debugrpt / debugrpt.cpp
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 // RCS-ID: $Id$
8 // Copyright: (c) 2005 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // License: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ----------------------------------------------------------------------------
13 // headers
14 // ----------------------------------------------------------------------------
15
16 #include "wx/app.h"
17 #include "wx/log.h"
18 #include "wx/frame.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 #if !defined(__WXMSW__) && !defined(__WXPM__)
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)
48 class MyDebugReport : public wxDebugReportUpload
49 {
50 public:
51 MyDebugReport() : wxDebugReportUpload
52 (
53 _T("http://your.url.here/"),
54 _T("report:file"),
55 _T("action")
56 )
57 {
58 }
59
60 protected:
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(_T("Didn't receive the expected server reply."));
69 return false;
70 }
71
72 wxString s(_T("Server replied:\n"));
73
74 const size_t count = reply.GetCount();
75 for ( size_t n = 0; n < count; n++ )
76 {
77 s << _T('\t') << reply[n] << _T('\n');
78 }
79
80 wxLogMessage(_T("%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
92 class MyDebugReport : public wxDebugReportCompress
93 {
94 public:
95 virtual bool DoProcess()
96 {
97 if ( !wxDebugReportCompress::DoProcess() )
98 return false;
99 wxMailMessage msg(GetReportName() + _T(" crash report"),
100 _T("vadim@wxwindows.org"),
101 wxEmptyString, // mail body
102 wxEmptyString, // from address
103 GetCompressedFileName(),
104 _T("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
117 static void bar(const wxChar *p)
118 {
119 char *pc = 0;
120 *pc = *p;
121
122 printf("bar: %s\n", p);
123 }
124
125 void baz(const wxString& s)
126 {
127 printf("baz: %s\n", s.c_str());
128 }
129
130 void foo(int n)
131 {
132 if ( n % 2 )
133 baz(wxT("odd"));
134 else
135 bar(wxT("even"));
136 }
137
138 // ----------------------------------------------------------------------------
139 // main window
140 // ----------------------------------------------------------------------------
141
142 enum
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
152 class MyFrame : public wxFrame
153 {
154 public:
155 MyFrame();
156
157 private:
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 DECLARE_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
183 class MyApp : public wxApp
184 {
185 public:
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
203 private:
204 bool m_uploadReport;
205
206 DECLARE_NO_COPY_CLASS(MyApp)
207 };
208
209 IMPLEMENT_APP(MyApp)
210
211 // ============================================================================
212 // implementation
213 // ============================================================================
214
215 // ----------------------------------------------------------------------------
216 // MyFrame
217 // ----------------------------------------------------------------------------
218
219 BEGIN_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)
228 END_EVENT_TABLE()
229
230 MyFrame::MyFrame()
231 : wxFrame(NULL, wxID_ANY, _T("wxWidgets Debug Report Sample"))
232 {
233 m_numLines = 10;
234
235 SetIcon(wxICON(sample));
236
237 wxMenu *menuFile = new wxMenu;
238 menuFile->Append(DebugRpt_Quit, _T("E&xit\tAlt-X"));
239
240 wxMenu *menuReport = new wxMenu;
241 menuReport->Append(DebugRpt_Crash, _T("Report for &crash\tCtrl-C"),
242 _T("Provoke a crash inside the program and create report for it"));
243 menuReport->Append(DebugRpt_Current, _T("Report for c&urrent context\tCtrl-U"),
244 _T("Create report for the current program context"));
245 menuReport->Append(DebugRpt_Paint, _T("Report for &paint handler\tCtrl-P"),
246 _T("Provoke a repeatable crash in wxEVT_PAINT handler"));
247 menuReport->AppendSeparator();
248 menuReport->AppendCheckItem(DebugRpt_Upload, _T("Up&load debug report"),
249 _T("You need to configure a web server accepting debug report uploads to use this function"));
250
251 wxMenu *menuHelp = new wxMenu;
252 menuHelp->Append(DebugRpt_About, _T("&About...\tF1"));
253
254 wxMenuBar *mbar = new wxMenuBar();
255 mbar->Append(menuFile, _T("&File"));
256 mbar->Append(menuReport, _T("&Report"));
257 mbar->Append(menuHelp, _T("&Help"));
258 SetMenuBar(mbar);
259
260 CreateStatusBar();
261
262 Show();
263 }
264
265 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
266 {
267 Close(true);
268 }
269
270 void MyFrame::OnReportForCrash(wxCommandEvent& WXUNUSED(event))
271 {
272 // this call is going to crash
273 foo(32);
274 foo(17);
275 }
276
277 void MyFrame::OnReportForCurrent(wxCommandEvent& WXUNUSED(event))
278 {
279 // example of manually generated report, this could be also
280 // used in wxApp::OnAssert()
281 wxGetApp().GenerateReport(wxDebugReport::Context_Current);
282 }
283
284 void MyFrame::OnReportPaint(wxCommandEvent& WXUNUSED(event))
285 {
286 // this will result in a crash in OnPaint()
287 m_numLines = 0;
288
289 // ensure it's called immediately
290 Refresh();
291 }
292
293 void MyFrame::OnReportUpload(wxCommandEvent& event)
294 {
295 wxGetApp().UploadReport(event.IsChecked());
296 }
297
298 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
299 {
300 wxMessageBox
301 (
302 _T("wxDebugReport sample\n(c) 2005 Vadim Zeitlin <vadim@wxwindows.org>"),
303 _T("wxWidgets Debug Report Sample"),
304 wxOK | wxICON_INFORMATION,
305 this
306 );
307 }
308
309 void MyFrame::OnPaint(wxPaintEvent& WXUNUSED(event))
310 {
311 wxPaintDC dc(this);
312 const wxSize size = GetClientSize();
313 for ( wxCoord x = 0; x < size.x; x += size.x/m_numLines )
314 dc.DrawLine(x, 0, x, size.y);
315 }
316
317 // ----------------------------------------------------------------------------
318 // MyApp
319 // ----------------------------------------------------------------------------
320
321 MyApp::MyApp()
322 {
323 // user needs to explicitely enable this
324 m_uploadReport = false;
325
326 // call this to tell the library to call our OnFatalException()
327 wxHandleFatalExceptions();
328 }
329
330 bool MyApp::OnInit()
331 {
332 if ( !wxApp::OnInit() )
333 return false;
334
335 new MyFrame;
336
337 return true;
338 }
339
340 void MyApp::OnFatalException()
341 {
342 GenerateReport(wxDebugReport::Context_Exception);
343 }
344
345 void MyApp::GenerateReport(wxDebugReport::Context ctx)
346 {
347 wxDebugReportCompress *report = m_uploadReport ? new MyDebugReport
348 : new wxDebugReportCompress;
349
350 // add all standard files: currently this means just a minidump and an
351 // XML file with system info and stack trace
352 report->AddAll(ctx);
353
354 // you can also call report->AddFile(...) with your own log files, files
355 // created using wxRegKey::Export() and so on, here we just add a test
356 // file containing the date of the crash
357 wxFileName fn(report->GetDirectory(), _T("timestamp.my"));
358 wxFFile file(fn.GetFullPath(), _T("w"));
359 if ( file.IsOpened() )
360 {
361 wxDateTime dt = wxDateTime::Now();
362 file.Write(dt.FormatISODate() + _T(' ') + dt.FormatISOTime());
363 file.Close();
364 }
365
366 report->AddFile(fn.GetFullName(), _T("timestamp of this report"));
367
368 // can also add an existing file directly, it will be copied
369 // automatically
370 #ifdef __WXMSW__
371 report->AddFile(_T("c:\\autoexec.bat"), _T("DOS startup file"));
372 #else
373 report->AddFile(_T("/etc/motd"), _T("Message of the day"));
374 #endif
375
376 // calling Show() is not mandatory, but is more polite
377 if ( wxDebugReportPreviewStd().Show(*report) )
378 {
379 if ( report->Process() )
380 {
381 if ( m_uploadReport )
382 {
383 wxLogMessage(_T("Report successfully uploaded."));
384 }
385 else
386 {
387 wxLogMessage(_T("Report generated in \"%s\"."),
388 report->GetCompressedFileName().c_str());
389 report->Reset();
390 }
391 }
392 }
393 //else: user cancelled the report
394
395 delete report;
396 }
397