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