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