use wxEventLoop::SetCriticalWindow() to ensure that we don't get more crashes in...
[wxWidgets.git] / src / generic / dbgrptg.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/dbgrptg.cpp
3 // Purpose: implementation of wxDebugReportPreviewStd
4 // Author: Vadim Zeitlin, Andrej Putrin
5 // Modified by:
6 // Created: 2005-01-21
7 // RCS-ID: $Id$
8 // Copyright: (c) 2005 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // License: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #ifndef WX_PRECOMP
27 #include "wx/sizer.h"
28 #include "wx/checklst.h"
29 #include "wx/textctrl.h"
30 #endif // WX_PRECOMP
31
32 #if wxUSE_DEBUGREPORT && wxUSE_XML
33
34 #include "wx/debugrpt.h"
35
36 #include "wx/intl.h"
37 #include "wx/filename.h"
38 #include "wx/ffile.h"
39 #include "wx/mimetype.h"
40
41 #include "wx/statline.h"
42 #include "wx/stattext.h"
43 #include "wx/filedlg.h"
44 #include "wx/valtext.h"
45
46 #ifdef __WXMSW__
47 #include "wx/evtloop.h" // for SetCriticalWindow()
48 #endif // __WXMSW__
49
50 // ----------------------------------------------------------------------------
51 // wxDumpPreviewDlg: simple class for showing ASCII preview of dump files
52 // ----------------------------------------------------------------------------
53
54 class wxDumpPreviewDlg : public wxDialog
55 {
56 public:
57 wxDumpPreviewDlg(wxWindow *parent,
58 const wxString& title,
59 const wxString& text);
60
61 private:
62 // the text we show
63 wxTextCtrl *m_text;
64
65 DECLARE_NO_COPY_CLASS(wxDumpPreviewDlg)
66 };
67
68 wxDumpPreviewDlg::wxDumpPreviewDlg(wxWindow *parent,
69 const wxString& title,
70 const wxString& text)
71 : wxDialog(parent, wxID_ANY, title,
72 wxDefaultPosition, wxDefaultSize,
73 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
74 {
75 // create controls
76 // ---------------
77
78 // use wxTE_RICH2 style to avoid 64kB limit under MSW and display big files
79 // faster than with wxTE_RICH
80 m_text = new wxTextCtrl(this, wxID_ANY, wxEmptyString,
81 wxPoint(0, 0), wxDefaultSize,
82 wxTE_MULTILINE |
83 wxTE_READONLY |
84 wxTE_NOHIDESEL |
85 wxTE_RICH2);
86 m_text->SetValue(text);
87
88 // use fixed-width font
89 m_text->SetFont(wxFont(12, wxFONTFAMILY_TELETYPE,
90 wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
91
92 wxButton *btnClose = new wxButton(this, wxID_CANCEL, _("Close"));
93
94
95 // layout them
96 // -----------
97
98 wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL),
99 *sizerBtns = new wxBoxSizer(wxHORIZONTAL);
100
101 sizerBtns->Add(btnClose, 0, 0, 1);
102
103 sizerTop->Add(m_text, 1, wxEXPAND);
104 sizerTop->Add(sizerBtns, 0, wxALIGN_RIGHT | wxTOP | wxBOTTOM | wxRIGHT, 1);
105
106 // set the sizer &c
107 // ----------------
108
109 // make the text window bigger to show more contents of the file
110 sizerTop->SetItemMinSize(m_text, 600, 300);
111 SetSizer(sizerTop);
112
113 Layout();
114 Fit();
115
116 m_text->SetFocus();
117 }
118
119 // ----------------------------------------------------------------------------
120 // wxDumpOpenExternalDlg: choose a command for opening the given file
121 // ----------------------------------------------------------------------------
122
123 class wxDumpOpenExternalDlg : public wxDialog
124 {
125 public:
126 wxDumpOpenExternalDlg(wxWindow *parent, const wxFileName& filename);
127
128 // return the command chosed by user to open this file
129 const wxString& GetCommand() const { return m_command; }
130
131 wxString m_command;
132
133 private:
134 void OnBrowse(wxCommandEvent& event);
135
136 DECLARE_EVENT_TABLE()
137 DECLARE_NO_COPY_CLASS(wxDumpOpenExternalDlg)
138 };
139
140 BEGIN_EVENT_TABLE(wxDumpOpenExternalDlg, wxDialog)
141 EVT_BUTTON(wxID_MORE, wxDumpOpenExternalDlg::OnBrowse)
142 END_EVENT_TABLE()
143
144
145 wxDumpOpenExternalDlg::wxDumpOpenExternalDlg(wxWindow *parent,
146 const wxFileName& filename)
147 : wxDialog(parent,
148 wxID_ANY,
149 wxString::Format
150 (
151 _("Open file \"%s\""),
152 filename.GetFullPath().c_str()
153 ))
154 {
155 // create controls
156 // ---------------
157
158 wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL);
159 sizerTop->Add(new wxStaticText(this, wxID_ANY,
160 wxString::Format
161 (
162 _("Enter command to open file \"%s\":"),
163 filename.GetFullName().c_str()
164 )),
165 wxSizerFlags().Border());
166
167 wxSizer *sizerH = new wxBoxSizer(wxHORIZONTAL);
168
169 wxTextCtrl *command = new wxTextCtrl
170 (
171 this,
172 wxID_ANY,
173 wxEmptyString,
174 wxDefaultPosition,
175 wxSize(250, wxDefaultCoord),
176 0
177 #if wxUSE_VALIDATORS
178 ,wxTextValidator(wxFILTER_NONE, &m_command)
179 #endif
180 );
181 sizerH->Add(command,
182 wxSizerFlags(1).Align(wxALIGN_CENTER_VERTICAL));
183 wxButton *browse = new wxButton(this, wxID_MORE, wxT(">>"),
184 wxDefaultPosition, wxDefaultSize,
185 wxBU_EXACTFIT);
186 sizerH->Add(browse,
187 wxSizerFlags(0).Align(wxALIGN_CENTER_VERTICAL). Border(wxLEFT));
188
189 sizerTop->Add(sizerH, wxSizerFlags(0).Expand().Border());
190
191 sizerTop->Add(new wxStaticLine(this), wxSizerFlags().Expand().Border());
192
193 sizerTop->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL),
194 wxSizerFlags().Align(wxALIGN_RIGHT).Border());
195
196 // set the sizer &c
197 // ----------------
198
199 SetSizer(sizerTop);
200
201 Layout();
202 Fit();
203
204 command->SetFocus();
205 }
206
207 void wxDumpOpenExternalDlg::OnBrowse(wxCommandEvent& )
208 {
209 wxFileName fname(m_command);
210 wxFileDialog dlg(this,
211 wxFileSelectorPromptStr,
212 fname.GetPathWithSep(),
213 fname.GetFullName()
214 #ifdef __WXMSW__
215 , _("Executable files (*.exe)|*.exe|All files (*.*)|*.*||")
216 #endif // __WXMSW__
217 );
218 if ( dlg.ShowModal() == wxID_OK )
219 {
220 m_command = dlg.GetPath();
221 TransferDataToWindow();
222 }
223 }
224
225
226 // ----------------------------------------------------------------------------
227 // wxDebugReportDialog: class showing debug report to the user
228 // ----------------------------------------------------------------------------
229
230 class wxDebugReportDialog : public wxDialog
231 {
232 public:
233 wxDebugReportDialog(wxDebugReport& dbgrpt);
234
235 virtual bool TransferDataToWindow();
236 virtual bool TransferDataFromWindow();
237
238 private:
239 void OnView(wxCommandEvent& );
240 void OnViewUpdate(wxUpdateUIEvent& );
241 void OnOpen(wxCommandEvent& );
242
243
244 // small helper: add wxEXPAND and wxALL flags
245 static wxSizerFlags SizerFlags(int proportion)
246 {
247 return wxSizerFlags(proportion).Expand().Border();
248 }
249
250
251 wxDebugReport& m_dbgrpt;
252
253 wxCheckListBox *m_checklst;
254 wxTextCtrl *m_notes;
255
256 wxArrayString m_files;
257
258 DECLARE_EVENT_TABLE()
259 DECLARE_NO_COPY_CLASS(wxDebugReportDialog)
260 };
261
262 // ============================================================================
263 // wxDebugReportDialog implementation
264 // ============================================================================
265
266 BEGIN_EVENT_TABLE(wxDebugReportDialog, wxDialog)
267 EVT_BUTTON(wxID_VIEW_DETAILS, wxDebugReportDialog::OnView)
268 EVT_UPDATE_UI(wxID_VIEW_DETAILS, wxDebugReportDialog::OnViewUpdate)
269 EVT_BUTTON(wxID_OPEN, wxDebugReportDialog::OnOpen)
270 EVT_UPDATE_UI(wxID_OPEN, wxDebugReportDialog::OnViewUpdate)
271 END_EVENT_TABLE()
272
273
274 // ----------------------------------------------------------------------------
275 // construction
276 // ----------------------------------------------------------------------------
277
278 wxDebugReportDialog::wxDebugReportDialog(wxDebugReport& dbgrpt)
279 : wxDialog(NULL, wxID_ANY,
280 wxString::Format(_("Debug report \"%s\""),
281 dbgrpt.GetReportName().c_str()),
282 wxDefaultPosition,
283 wxDefaultSize,
284 wxDEFAULT_DIALOG_STYLE | wxTHICK_FRAME),
285 m_dbgrpt(dbgrpt)
286 {
287 // upper part of the dialog: explanatory message
288 wxString msg;
289 msg << _("A debug report has been generated in the directory\n")
290 << _T('\n')
291 << _T(" \"") << dbgrpt.GetDirectory() << _T("\"\n")
292 << _T('\n')
293 << _("The report contains the files listed below. If any of these files contain private information,\nplease uncheck them and they will be removed from the report.\n")
294 << _T('\n')
295 << _("If you wish to suppress this debug report completely, please choose the \"Cancel\" button,\nbut be warned that it may hinder improving the program, so if\nat all possible please do continue with the report generation.\n")
296 << _T('\n')
297 << _(" Thank you and we're sorry for the inconvenience!\n")
298 << _T("\n\n"); // just some white space to separate from other stuff
299
300 const wxSizerFlags flagsFixed(SizerFlags(0));
301 const wxSizerFlags flagsExpand(SizerFlags(1));
302 const wxSizerFlags flagsExpand2(SizerFlags(2));
303
304 wxSizer *sizerPreview =
305 new wxStaticBoxSizer(wxVERTICAL, this, _("&Debug report preview:"));
306 sizerPreview->Add(CreateTextSizer(msg), SizerFlags(0).Centre());
307
308 // ... and the list of files in this debug report with buttons to view them
309 wxSizer *sizerFileBtns = new wxBoxSizer(wxVERTICAL);
310 sizerFileBtns->AddStretchSpacer(1);
311 sizerFileBtns->Add(new wxButton(this, wxID_VIEW_DETAILS, _T("&View...")),
312 wxSizerFlags().Border(wxBOTTOM));
313 sizerFileBtns->Add(new wxButton(this, wxID_OPEN, _T("&Open...")),
314 wxSizerFlags().Border(wxTOP));
315 sizerFileBtns->AddStretchSpacer(1);
316
317 m_checklst = new wxCheckListBox(this, wxID_ANY);
318
319 wxSizer *sizerFiles = new wxBoxSizer(wxHORIZONTAL);
320 sizerFiles->Add(m_checklst, flagsExpand);
321 sizerFiles->Add(sizerFileBtns, flagsFixed);
322
323 sizerPreview->Add(sizerFiles, flagsExpand2);
324
325
326 // lower part of the dialog: notes field
327 wxSizer *sizerNotes = new wxStaticBoxSizer(wxVERTICAL, this, _("&Notes:"));
328
329 msg = _("If you have any additional information pertaining to this bug\nreport, please enter it here and it will be joined to it:");
330
331 m_notes = new wxTextCtrl(this, wxID_ANY, wxEmptyString,
332 wxDefaultPosition, wxDefaultSize,
333 wxTE_MULTILINE);
334
335 sizerNotes->Add(CreateTextSizer(msg), flagsFixed);
336 sizerNotes->Add(m_notes, flagsExpand);
337
338
339 wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL);
340 sizerTop->Add(sizerPreview, flagsExpand2);
341 sizerTop->AddSpacer(5);
342 sizerTop->Add(sizerNotes, flagsExpand);
343 sizerTop->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL), flagsFixed);
344
345 SetSizerAndFit(sizerTop);
346 Layout();
347 CentreOnScreen();
348 }
349
350 // ----------------------------------------------------------------------------
351 // data exchange
352 // ----------------------------------------------------------------------------
353
354 bool wxDebugReportDialog::TransferDataToWindow()
355 {
356 // all files are included in the report by default
357 const size_t count = m_dbgrpt.GetFilesCount();
358 for ( size_t n = 0; n < count; n++ )
359 {
360 wxString name,
361 desc;
362 if ( m_dbgrpt.GetFile(n, &name, &desc) )
363 {
364 m_checklst->Append(name + _T(" (") + desc + _T(')'));
365 m_checklst->Check(n);
366
367 m_files.Add(name);
368 }
369 }
370
371 return true;
372 }
373
374 bool wxDebugReportDialog::TransferDataFromWindow()
375 {
376 // any unchecked files should be removed from the report
377 const size_t count = m_checklst->GetCount();
378 for ( size_t n = 0; n < count; n++ )
379 {
380 if ( !m_checklst->IsChecked(n) )
381 {
382 m_dbgrpt.RemoveFile(m_files[n]);
383 }
384 }
385
386 // if the user entered any notes, add them to the report
387 const wxString notes = m_notes->GetValue();
388 if ( !notes.empty() )
389 {
390 // for now filename fixed, could make it configurable in the future...
391 m_dbgrpt.AddText(_T("notes.txt"), notes, _T("user notes"));
392 }
393
394 return true;
395 }
396
397 // ----------------------------------------------------------------------------
398 // event handlers
399 // ----------------------------------------------------------------------------
400
401 void wxDebugReportDialog::OnView(wxCommandEvent& )
402 {
403 const int sel = m_checklst->GetSelection();
404 wxCHECK_RET( sel != -1, _T("invalid selection in OnView()") );
405
406 wxFileName fn(m_dbgrpt.GetDirectory(), m_files[sel]);
407 wxString str;
408
409 wxFFile file(fn.GetFullPath());
410 if ( file.IsOpened() && file.ReadAll(&str) )
411 {
412 wxDumpPreviewDlg dlg(this, m_files[sel], str);
413 dlg.ShowModal();
414 }
415 }
416
417 void wxDebugReportDialog::OnOpen(wxCommandEvent& )
418 {
419 const int sel = m_checklst->GetSelection();
420 wxCHECK_RET( sel != -1, _T("invalid selection in OnOpen()") );
421
422 wxFileName fn(m_dbgrpt.GetDirectory(), m_files[sel]);
423
424 // try to get the command to open this kind of files ourselves
425 wxString command;
426 #if wxUSE_MIMETYPE
427 wxFileType *
428 ft = wxTheMimeTypesManager->GetFileTypeFromExtension(fn.GetExt());
429 if ( ft )
430 {
431 command = ft->GetOpenCommand(fn.GetFullPath());
432 delete ft;
433 }
434 #endif // wxUSE_MIMETYPE
435
436 // if we couldn't, ask the user
437 if ( command.empty() )
438 {
439 wxDumpOpenExternalDlg dlg(this, fn);
440 if ( dlg.ShowModal() == wxID_OK )
441 {
442 // get the command chosen by the user and append file name to it
443
444 // if we don't have place marker for file name in the command...
445 wxString cmd = dlg.GetCommand();
446 if ( !cmd.empty() )
447 {
448 #if wxUSE_MIMETYPE
449 if ( cmd.find(_T('%')) != wxString::npos )
450 {
451 command = wxFileType::ExpandCommand(cmd, fn.GetFullPath());
452 }
453 else // no %s nor %1
454 #endif // wxUSE_MIMETYPE
455 {
456 // append the file name to the end
457 command << cmd << _T(" \"") << fn.GetFullPath() << _T('"');
458 }
459 }
460 }
461 }
462
463 if ( !command.empty() )
464 ::wxExecute(command);
465 }
466
467 void wxDebugReportDialog::OnViewUpdate(wxUpdateUIEvent& event)
468 {
469 int sel = m_checklst->GetSelection();
470 if (sel >= 0)
471 {
472 wxFileName fn(m_dbgrpt.GetDirectory(), m_files[sel]);
473 event.Enable(fn.FileExists());
474 }
475 else
476 event.Enable(false);
477 }
478
479
480 // ============================================================================
481 // wxDebugReportPreviewStd implementation
482 // ============================================================================
483
484 bool wxDebugReportPreviewStd::Show(wxDebugReport& dbgrpt) const
485 {
486 if ( !dbgrpt.GetFilesCount() )
487 return false;
488
489 wxDebugReportDialog dlg(dbgrpt);
490
491 #ifdef __WXMSW__
492 // before entering the event loop (from ShowModal()), block the event
493 // handling for all other windows as this could result in more crashes
494 wxEventLoop::SetCriticalWindow(&dlg);
495 #endif // __WXMSW__
496
497 return dlg.ShowModal() == wxID_OK && dbgrpt.GetFilesCount() != 0;
498 }
499
500 #endif // wxUSE_DEBUGREPORT
501