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