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