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