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