]> git.saurik.com Git - wxWidgets.git/blame - src/generic/logg.cpp
fixed crash in OnChar() after m_key_current was deleted
[wxWidgets.git] / src / generic / logg.cpp
CommitLineData
dd85fc6b
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: logg.cpp
3// Purpose: wxLog-derived classes which need GUI support (the rest is in
4// src/common/log.cpp)
5// Author: Vadim Zeitlin
6// Modified by:
7// Created: 20.09.99 (extracted from src/common/log.cpp)
8// RCS-ID: $Id$
9// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
10// Licence: wxWindows license
11/////////////////////////////////////////////////////////////////////////////
12
13// ============================================================================
14// declarations
15// ============================================================================
16
17// ----------------------------------------------------------------------------
18// headers
19// ----------------------------------------------------------------------------
20
21// no #pragma implementation "log.h" because it's already in src/common/log.cpp
22
23// For compilers that support precompilation, includes "wx.h".
24#include "wx/wxprec.h"
25
26#ifdef __BORLANDC__
27 #pragma hdrstop
28#endif
29
e90c1d2a
VZ
30#if !wxUSE_GUI
31 #error "This file can't be compiled without GUI!"
dd85fc6b
VZ
32#endif
33
34#ifndef WX_PRECOMP
35 #include "wx/app.h"
36 #include "wx/intl.h"
37 #include "wx/log.h"
38 #include "wx/menu.h"
39 #include "wx/frame.h"
40 #include "wx/filedlg.h"
8ca2f11c 41 #include "wx/msgdlg.h"
dd85fc6b 42 #include "wx/textctrl.h"
f1df0927
VZ
43 #include "wx/sizer.h"
44 #include "wx/statbmp.h"
dd85fc6b
VZ
45#endif // WX_PRECOMP
46
47#include "wx/file.h"
48#include "wx/textfile.h"
49
39a7c7e1
VZ
50#ifdef __WXMSW__
51 // for OutputDebugString()
52 #include "wx/msw/private.h"
53#endif // Windows
54
f1df0927
VZ
55// may be defined to 0 for old behavior (using wxMessageBox) - shouldn't be
56// changed normally (that's why it's here and not in setup.h)
57#define wxUSE_LOG_DIALOG 1
58
59#if wxUSE_LOG_DIALOG
60 #include "wx/datetime.h"
61 #include "wx/listctrl.h"
62 #include "wx/image.h"
63#else // !wxUSE_TEXTFILE
64 #include "wx/msgdlg.h"
65#endif // wxUSE_LOG_DIALOG/!wxUSE_LOG_DIALOG
66
67// ----------------------------------------------------------------------------
68// private classes
69// ----------------------------------------------------------------------------
70
71#if wxUSE_LOG_DIALOG
72
73class wxLogDialog : public wxDialog
74{
75public:
76 wxLogDialog(wxWindow *parent,
77 const wxArrayString& messages,
78 const wxArrayInt& severity,
79 const wxArrayLong& timess,
80 const wxString& caption,
81 long style);
82 virtual ~wxLogDialog();
83
84 // event handlers
85 void OnOk(wxCommandEvent& event);
86 void OnDetails(wxCommandEvent& event);
4aff28fc 87 void OnListSelect(wxListEvent& event);
f1df0927
VZ
88
89private:
90 // the data for the listctrl
224ff7a5
VZ
91 wxArrayString m_messages;
92 wxArrayInt m_severity;
93 wxArrayLong m_times;
f1df0927
VZ
94
95 // the "toggle" button and its state
96 wxButton *m_btnDetails;
97 bool m_showingDetails;
98
99 // the listctrl (not shown initially)
100 wxListCtrl *m_listctrl;
101
5f170f33
VZ
102 // the translated "Details" string
103 static wxString ms_details;
104
f1df0927
VZ
105 DECLARE_EVENT_TABLE()
106};
107
108BEGIN_EVENT_TABLE(wxLogDialog, wxDialog)
109 EVT_BUTTON(wxID_OK, wxLogDialog::OnOk)
110 EVT_BUTTON(wxID_MORE, wxLogDialog::OnDetails)
4aff28fc 111 EVT_LIST_ITEM_SELECTED(-1, wxLogDialog::OnListSelect)
f1df0927
VZ
112END_EVENT_TABLE()
113
114#endif // wxUSE_LOG_DIALOG
115
dd85fc6b
VZ
116// ----------------------------------------------------------------------------
117// global variables
118// ----------------------------------------------------------------------------
119
120// we use a global variable to store the frame pointer for wxLogStatus - bad,
121// but it's he easiest way
122static wxFrame *gs_pFrame; // FIXME MT-unsafe
123
124// ============================================================================
125// implementation
126// ============================================================================
127
128// ----------------------------------------------------------------------------
129// global functions
130// ----------------------------------------------------------------------------
131
132// accepts an additional argument which tells to which frame the output should
133// be directed
134void wxLogStatus(wxFrame *pFrame, const wxChar *szFormat, ...)
135{
136 wxString msg;
137
138 wxLog *pLog = wxLog::GetActiveTarget();
139 if ( pLog != NULL ) {
140 va_list argptr;
141 va_start(argptr, szFormat);
142 msg.PrintfV(szFormat, argptr);
143 va_end(argptr);
144
145 wxASSERT( gs_pFrame == NULL ); // should be reset!
146 gs_pFrame = pFrame;
147 wxLog::OnLog(wxLOG_Status, msg, time(NULL));
148 gs_pFrame = (wxFrame *) NULL;
149 }
150}
151
152// ----------------------------------------------------------------------------
153// wxLogTextCtrl implementation
154// ----------------------------------------------------------------------------
155
156wxLogTextCtrl::wxLogTextCtrl(wxTextCtrl *pTextCtrl)
157{
158 m_pTextCtrl = pTextCtrl;
159}
160
5e0201ea 161void wxLogTextCtrl::DoLogString(const wxChar *szString, time_t WXUNUSED(t))
dd85fc6b
VZ
162{
163 wxString msg;
164 TimeStamp(&msg);
223d09f6 165 msg << szString << wxT('\n');
dd85fc6b
VZ
166
167 m_pTextCtrl->AppendText(msg);
168}
169
170// ----------------------------------------------------------------------------
171// wxLogGui implementation (FIXME MT-unsafe)
172// ----------------------------------------------------------------------------
173
174wxLogGui::wxLogGui()
175{
5f170f33
VZ
176 // we must translate them here in the very beginning or we risk to have
177 // reentrancy problems when called from inside wxGetTranslation() leading
178 // to inifnite recursion
179 m_error = _("Error");
180 m_warning = _("Warning");
181 m_info = _("Information");
182
dd85fc6b
VZ
183 Clear();
184}
185
186void wxLogGui::Clear()
187{
5f170f33
VZ
188 m_bErrors =
189 m_bWarnings =
190 m_bHasMessages = FALSE;
191
dd85fc6b 192 m_aMessages.Empty();
f1df0927 193 m_aSeverity.Empty();
dd85fc6b
VZ
194 m_aTimes.Empty();
195}
196
197void wxLogGui::Flush()
198{
199 if ( !m_bHasMessages )
200 return;
201
202 // do it right now to block any new calls to Flush() while we're here
203 m_bHasMessages = FALSE;
204
f1df0927
VZ
205 wxString title = wxTheApp->GetAppName();
206 if ( !!title )
207 {
208 title[0u] = wxToupper(title[0u]);
209 title += _T(' ');
210 }
211
212 long style;
213 if ( m_bErrors ) {
5f170f33 214 title += m_error;
f1df0927
VZ
215 style = wxICON_STOP;
216 }
217 else if ( m_bWarnings ) {
5f170f33 218 title += m_warning;
f1df0927
VZ
219 style = wxICON_EXCLAMATION;
220 }
221 else {
5f170f33 222 title += m_info;
f1df0927
VZ
223 style = wxICON_INFORMATION;
224 }
225
23f681ec
VZ
226 // this is the best we can do here
227 wxWindow *parent = wxTheApp->GetTopWindow();
224ff7a5 228
23f681ec 229 size_t nMsgCount = m_aMessages.Count();
224ff7a5 230
23f681ec
VZ
231 wxString str;
232 if ( nMsgCount == 1 )
233 {
234 str = m_aMessages[0];
235 }
236 else // more than one message
237 {
238#if wxUSE_LOG_DIALOG
239 wxLogDialog dlg(parent,
240 m_aMessages, m_aSeverity, m_aTimes,
241 title, style);
f1df0927 242
23f681ec
VZ
243 // clear the message list before showing the dialog because while it's
244 // shown some new messages may appear
245 Clear();
246
247 (void)dlg.ShowModal();
f1df0927 248#else // !wxUSE_LOG_DIALOG
23f681ec
VZ
249 // concatenate all strings (but not too many to not overfill the msg box)
250 size_t nLines = 0;
dd85fc6b 251
23f681ec
VZ
252 // start from the most recent message
253 for ( size_t n = nMsgCount; n > 0; n-- ) {
254 // for Windows strings longer than this value are wrapped (NT 4.0)
255 const size_t nMsgLineWidth = 156;
dd85fc6b 256
23f681ec 257 nLines += (m_aMessages[n - 1].Len() + nMsgLineWidth - 1) / nMsgLineWidth;
dd85fc6b 258
23f681ec
VZ
259 if ( nLines > 25 ) // don't put too many lines in message box
260 break;
dd85fc6b 261
23f681ec
VZ
262 str << m_aMessages[n - 1] << wxT("\n");
263 }
264#endif // wxUSE_LOG_DIALOG/!wxUSE_LOG_DIALOG
dd85fc6b
VZ
265 }
266
23f681ec
VZ
267 // this catches both cases of 1 message with wxUSE_LOG_DIALOG and any
268 // situation without it
269 if ( !!str )
270 {
271 wxMessageBox(str, title, wxOK | style, parent);
dd85fc6b 272
23f681ec
VZ
273 // no undisplayed messages whatsoever
274 Clear();
275 }
dd85fc6b
VZ
276}
277
23f681ec 278// log all kinds of messages
dd85fc6b
VZ
279void wxLogGui::DoLog(wxLogLevel level, const wxChar *szString, time_t t)
280{
281 switch ( level ) {
282 case wxLOG_Info:
283 if ( GetVerbose() )
284 case wxLOG_Message:
f1df0927 285 {
dd85fc6b
VZ
286 if ( !m_bErrors ) {
287 m_aMessages.Add(szString);
f1df0927 288 m_aSeverity.Add(wxLOG_Message);
dd85fc6b
VZ
289 m_aTimes.Add((long)t);
290 m_bHasMessages = TRUE;
291 }
f1df0927
VZ
292 }
293 break;
dd85fc6b
VZ
294
295 case wxLOG_Status:
296#if wxUSE_STATUSBAR
f1df0927
VZ
297 {
298 // find the top window and set it's status text if it has any
299 wxFrame *pFrame = gs_pFrame;
300 if ( pFrame == NULL ) {
301 wxWindow *pWin = wxTheApp->GetTopWindow();
302 if ( pWin != NULL && pWin->IsKindOf(CLASSINFO(wxFrame)) ) {
303 pFrame = (wxFrame *)pWin;
dd85fc6b 304 }
dd85fc6b 305 }
f1df0927
VZ
306
307 if ( pFrame && pFrame->GetStatusBar() )
308 pFrame->SetStatusText(szString);
309 }
dd85fc6b 310#endif // wxUSE_STATUSBAR
f1df0927 311 break;
dd85fc6b
VZ
312
313 case wxLOG_Trace:
314 case wxLOG_Debug:
f1df0927
VZ
315 #ifdef __WXDEBUG__
316 {
317 #ifdef __WXMSW__
318 // don't prepend debug/trace here: it goes to the
319 // debug window anyhow, but do put a timestamp
320 wxString str;
321 TimeStamp(&str);
322 str << szString << wxT("\n\r");
323 OutputDebugString(str);
324 #else
325 // send them to stderr
326 wxFprintf(stderr, wxT("%s: %s\n"),
327 level == wxLOG_Trace ? wxT("Trace")
328 : wxT("Debug"),
329 szString);
330 fflush(stderr);
331 #endif
332 }
333 #endif // __WXDEBUG__
dd85fc6b 334
f1df0927 335 break;
dd85fc6b
VZ
336
337 case wxLOG_FatalError:
f1df0927
VZ
338 // show this one immediately
339 wxMessageBox(szString, _("Fatal error"), wxICON_HAND);
a2a0d40d 340 wxExit();
f1df0927 341 break;
dd85fc6b
VZ
342
343 case wxLOG_Error:
f1df0927
VZ
344 if ( !m_bErrors ) {
345#if !wxUSE_LOG_DIALOG
dd85fc6b 346 // discard earlier informational messages if this is the 1st
f1df0927
VZ
347 // error because they might not make sense any more and showing
348 // them in a message box might be confusing
349 m_aMessages.Empty();
350 m_aSeverity.Empty();
351 m_aTimes.Empty();
352#endif // wxUSE_LOG_DIALOG
353 m_bErrors = TRUE;
354 }
355 // fall through
dd85fc6b
VZ
356
357 case wxLOG_Warning:
f1df0927
VZ
358 if ( !m_bErrors ) {
359 // for the warning we don't discard the info messages
360 m_bWarnings = TRUE;
361 }
362
363 m_aMessages.Add(szString);
06b466c7 364 m_aSeverity.Add((int)level);
f1df0927
VZ
365 m_aTimes.Add((long)t);
366 m_bHasMessages = TRUE;
367 break;
dd85fc6b
VZ
368 }
369}
370
371// ----------------------------------------------------------------------------
372// wxLogWindow and wxLogFrame implementation
373// ----------------------------------------------------------------------------
374
375// log frame class
376// ---------------
377class wxLogFrame : public wxFrame
378{
379public:
380 // ctor & dtor
381 wxLogFrame(wxFrame *pParent, wxLogWindow *log, const wxChar *szTitle);
382 virtual ~wxLogFrame();
383
384 // menu callbacks
385 void OnClose(wxCommandEvent& event);
386 void OnCloseWindow(wxCloseEvent& event);
387#if wxUSE_FILE
388 void OnSave (wxCommandEvent& event);
389#endif // wxUSE_FILE
390 void OnClear(wxCommandEvent& event);
391
392 void OnIdle(wxIdleEvent&);
393
394 // accessors
395 wxTextCtrl *TextCtrl() const { return m_pTextCtrl; }
396
397private:
857eb081 398 // use standard ids for our commands!
dd85fc6b
VZ
399 enum
400 {
857eb081
VZ
401 Menu_Close = wxID_CLOSE,
402 Menu_Save = wxID_SAVE,
403 Menu_Clear = wxID_CLEAR
dd85fc6b
VZ
404 };
405
406 // instead of closing just hide the window to be able to Show() it later
407 void DoClose() { Show(FALSE); }
408
409 wxTextCtrl *m_pTextCtrl;
410 wxLogWindow *m_log;
411
412 DECLARE_EVENT_TABLE()
413};
414
415BEGIN_EVENT_TABLE(wxLogFrame, wxFrame)
416 // wxLogWindow menu events
417 EVT_MENU(Menu_Close, wxLogFrame::OnClose)
418#if wxUSE_FILE
419 EVT_MENU(Menu_Save, wxLogFrame::OnSave)
420#endif // wxUSE_FILE
421 EVT_MENU(Menu_Clear, wxLogFrame::OnClear)
422
423 EVT_CLOSE(wxLogFrame::OnCloseWindow)
424END_EVENT_TABLE()
425
426wxLogFrame::wxLogFrame(wxFrame *pParent, wxLogWindow *log, const wxChar *szTitle)
427 : wxFrame(pParent, -1, szTitle)
428{
429 m_log = log;
430
431 m_pTextCtrl = new wxTextCtrl(this, -1, wxEmptyString, wxDefaultPosition,
432 wxDefaultSize,
433 wxTE_MULTILINE |
434 wxHSCROLL |
435 wxTE_READONLY);
436
437 // create menu
438 wxMenuBar *pMenuBar = new wxMenuBar;
439 wxMenu *pMenu = new wxMenu;
440#if wxUSE_FILE
441 pMenu->Append(Menu_Save, _("&Save..."), _("Save log contents to file"));
442#endif // wxUSE_FILE
443 pMenu->Append(Menu_Clear, _("C&lear"), _("Clear the log contents"));
444 pMenu->AppendSeparator();
445 pMenu->Append(Menu_Close, _("&Close"), _("Close this window"));
446 pMenuBar->Append(pMenu, _("&Log"));
447 SetMenuBar(pMenuBar);
448
449#if wxUSE_STATUSBAR
450 // status bar for menu prompts
451 CreateStatusBar();
452#endif // wxUSE_STATUSBAR
453
454 m_log->OnFrameCreate(this);
455}
456
457void wxLogFrame::OnClose(wxCommandEvent& WXUNUSED(event))
458{
459 DoClose();
460}
461
462void wxLogFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
463{
464 DoClose();
465}
466
467#if wxUSE_FILE
468void wxLogFrame::OnSave(wxCommandEvent& WXUNUSED(event))
469{
470 // get the file name
471 // -----------------
223d09f6 472 const wxChar *szFileName = wxSaveFileSelector(wxT("log"), wxT("txt"), wxT("log.txt"));
dd85fc6b
VZ
473 if ( szFileName == NULL ) {
474 // cancelled
475 return;
476 }
477
478 // open file
479 // ---------
480 wxFile file;
481 bool bOk = FALSE;
482 if ( wxFile::Exists(szFileName) ) {
483 bool bAppend = FALSE;
484 wxString strMsg;
485 strMsg.Printf(_("Append log to file '%s' "
486 "(choosing [No] will overwrite it)?"), szFileName);
487 switch ( wxMessageBox(strMsg, _("Question"), wxYES_NO | wxCANCEL) ) {
488 case wxYES:
489 bAppend = TRUE;
490 break;
491
492 case wxNO:
493 bAppend = FALSE;
494 break;
495
496 case wxCANCEL:
497 return;
498
499 default:
500 wxFAIL_MSG(_("invalid message box return value"));
501 }
502
503 if ( bAppend ) {
504 bOk = file.Open(szFileName, wxFile::write_append);
505 }
506 else {
507 bOk = file.Create(szFileName, TRUE /* overwrite */);
508 }
509 }
510 else {
511 bOk = file.Create(szFileName);
512 }
513
514 // retrieve text and save it
515 // -------------------------
516 int nLines = m_pTextCtrl->GetNumberOfLines();
517 for ( int nLine = 0; bOk && nLine < nLines; nLine++ ) {
518 bOk = file.Write(m_pTextCtrl->GetLineText(nLine) +
519 // we're not going to pull in the whole wxTextFile if all we need is this...
520#if wxUSE_TEXTFILE
521 wxTextFile::GetEOL()
522#else // !wxUSE_TEXTFILE
523 '\n'
524#endif // wxUSE_TEXTFILE
525 );
526 }
527
528 if ( bOk )
529 bOk = file.Close();
530
531 if ( !bOk ) {
532 wxLogError(_("Can't save log contents to file."));
533 }
534 else {
535 wxLogStatus(this, _("Log saved to the file '%s'."), szFileName);
536 }
537}
538#endif // wxUSE_FILE
539
540void wxLogFrame::OnClear(wxCommandEvent& WXUNUSED(event))
541{
542 m_pTextCtrl->Clear();
543}
544
545wxLogFrame::~wxLogFrame()
546{
547 m_log->OnFrameDelete(this);
548}
549
550// wxLogWindow
551// -----------
552wxLogWindow::wxLogWindow(wxFrame *pParent,
553 const wxChar *szTitle,
554 bool bShow,
555 bool bDoPass)
556{
557 m_bPassMessages = bDoPass;
558
559 m_pLogFrame = new wxLogFrame(pParent, this, szTitle);
560 m_pOldLog = wxLog::SetActiveTarget(this);
561
562 if ( bShow )
563 m_pLogFrame->Show(TRUE);
564}
565
566void wxLogWindow::Show(bool bShow)
567{
568 m_pLogFrame->Show(bShow);
569}
570
571void wxLogWindow::Flush()
572{
573 if ( m_pOldLog != NULL )
574 m_pOldLog->Flush();
575
576 m_bHasMessages = FALSE;
577}
578
579void wxLogWindow::DoLog(wxLogLevel level, const wxChar *szString, time_t t)
580{
581 // first let the previous logger show it
582 if ( m_pOldLog != NULL && m_bPassMessages ) {
f1df0927 583 // bogus cast just to access protected DoLog
dd85fc6b
VZ
584 ((wxLogWindow *)m_pOldLog)->DoLog(level, szString, t);
585 }
586
587 if ( m_pLogFrame ) {
588 switch ( level ) {
589 case wxLOG_Status:
590 // by default, these messages are ignored by wxLog, so process
591 // them ourselves
592 if ( !wxIsEmpty(szString) )
593 {
594 wxString str;
595 str << _("Status: ") << szString;
596 DoLogString(str, t);
597 }
598 break;
599
600 // don't put trace messages in the text window for 2 reasons:
601 // 1) there are too many of them
602 // 2) they may provoke other trace messages thus sending a program
603 // into an infinite loop
604 case wxLOG_Trace:
605 break;
606
607 default:
608 // and this will format it nicely and call our DoLogString()
609 wxLog::DoLog(level, szString, t);
610 }
611 }
612
613 m_bHasMessages = TRUE;
614}
615
616void wxLogWindow::DoLogString(const wxChar *szString, time_t WXUNUSED(t))
617{
618 // put the text into our window
619 wxTextCtrl *pText = m_pLogFrame->TextCtrl();
620
621 // remove selection (WriteText is in fact ReplaceSelection)
622#ifdef __WXMSW__
623 long nLen = pText->GetLastPosition();
624 pText->SetSelection(nLen, nLen);
625#endif // Windows
626
627 wxString msg;
628 TimeStamp(&msg);
223d09f6 629 msg << szString << wxT('\n');
dd85fc6b
VZ
630
631 pText->AppendText(msg);
632
633 // TODO ensure that the line can be seen
634}
635
636wxFrame *wxLogWindow::GetFrame() const
637{
638 return m_pLogFrame;
639}
640
641void wxLogWindow::OnFrameCreate(wxFrame * WXUNUSED(frame))
642{
643}
644
645void wxLogWindow::OnFrameDelete(wxFrame * WXUNUSED(frame))
646{
647 m_pLogFrame = (wxLogFrame *)NULL;
648}
649
650wxLogWindow::~wxLogWindow()
651{
652 delete m_pOldLog;
653
654 // may be NULL if log frame already auto destroyed itself
655 delete m_pLogFrame;
656}
657
f1df0927
VZ
658// ----------------------------------------------------------------------------
659// wxLogDialog
660// ----------------------------------------------------------------------------
661
662#if wxUSE_LOG_DIALOG
663
664static const size_t MARGIN = 10;
665
5f170f33
VZ
666wxString wxLogDialog::ms_details;
667
f1df0927
VZ
668wxLogDialog::wxLogDialog(wxWindow *parent,
669 const wxArrayString& messages,
670 const wxArrayInt& severity,
671 const wxArrayLong& times,
672 const wxString& caption,
673 long style)
4aff28fc 674 : wxDialog(parent, -1, caption )
f1df0927 675{
5f170f33
VZ
676 if ( ms_details )
677 {
678 // ensure that we won't try to call wxGetTranslation() twice
679 ms_details = _T("&Details");
680 ms_details = wxGetTranslation(ms_details);
681 }
682
4aff28fc
VZ
683 size_t count = messages.GetCount();
684 m_messages.Alloc(count);
685 m_severity.Alloc(count);
686 m_times.Alloc(count);
687
688 for ( size_t n = 0; n < count; n++ )
689 {
690 wxString msg = messages[n];
691 do
692 {
693 m_messages.Add(msg.BeforeFirst(_T('\n')));
694 msg = msg.AfterFirst(_T('\n'));
695
696 m_severity.Add(severity[n]);
697 m_times.Add(times[n]);
698 }
699 while ( !!msg );
700 }
701
f1df0927
VZ
702 m_showingDetails = FALSE; // not initially
703 m_listctrl = (wxListCtrl *)NULL;
704
705 // create the controls which are always shown and layout them: we use
706 // sizers even though our window is not resizeable to calculate the size of
707 // the dialog properly
708 wxBoxSizer *sizerTop = new wxBoxSizer(wxVERTICAL);
709 wxBoxSizer *sizerButtons = new wxBoxSizer(wxVERTICAL);
710 wxBoxSizer *sizerAll = new wxBoxSizer(wxHORIZONTAL);
711
5f170f33 712 wxButton *btnOk = new wxButton(this, wxID_OK, _("OK"));
f1df0927 713 sizerButtons->Add(btnOk, 0, wxCENTRE|wxBOTTOM, MARGIN/2);
5f170f33 714 m_btnDetails = new wxButton(this, wxID_MORE, ms_details + _T(" >>"));
f1df0927
VZ
715 sizerButtons->Add(m_btnDetails, 0, wxCENTRE|wxTOP, MARGIN/2 - 1);
716
06b466c7 717 wxIcon icon = wxTheApp->GetStdIcon((int)(style & wxICON_MASK));
f1df0927
VZ
718 sizerAll->Add(new wxStaticBitmap(this, -1, icon), 0, wxCENTRE);
719 const wxString& message = messages.Last();
720 sizerAll->Add(CreateTextSizer(message), 0, wxCENTRE|wxLEFT|wxRIGHT, MARGIN);
721 sizerAll->Add(sizerButtons, 0, wxALIGN_RIGHT|wxLEFT, MARGIN);
722
723 sizerTop->Add(sizerAll, 0, wxCENTRE|wxALL, MARGIN);
724
725 SetAutoLayout(TRUE);
726 SetSizer(sizerTop);
727
728 sizerTop->SetSizeHints(this);
729 sizerTop->Fit(this);
730
731 btnOk->SetFocus();
732
23f681ec
VZ
733 // this can't happen any more as we don't use this dialog in this case
734#if 0
4aff28fc 735 if ( count == 1 )
50af7fa9
VZ
736 {
737 // no details... it's easier to disable a button than to change the
738 // dialog layout depending on whether we have details or not
739 m_btnDetails->Disable();
740 }
23f681ec 741#endif // 0
50af7fa9 742
f1df0927
VZ
743 Centre();
744}
745
4aff28fc
VZ
746void wxLogDialog::OnListSelect(wxListEvent& event)
747{
748 // we can't just disable the control because this looks ugly under Windows
749 // (wrong bg colour, no scrolling...), but we still want to disable
750 // selecting items - it makes no sense here
225fe9d6 751 m_listctrl->SetItemState(event.GetIndex(), 0, wxLIST_STATE_SELECTED);
4aff28fc
VZ
752}
753
f1df0927
VZ
754void wxLogDialog::OnOk(wxCommandEvent& WXUNUSED(event))
755{
756 EndModal(wxID_OK);
757}
758
759void wxLogDialog::OnDetails(wxCommandEvent& WXUNUSED(event))
760{
761 wxSizer *sizer = GetSizer();
762
763 if ( m_showingDetails )
764 {
5f170f33 765 m_btnDetails->SetLabel(ms_details + _T(">>"));
f1df0927
VZ
766
767 sizer->Remove(m_listctrl);
768 }
769 else // show details now
770 {
5f170f33 771 m_btnDetails->SetLabel(wxString(_T("<< ")) + ms_details);
f1df0927
VZ
772
773 if ( !m_listctrl )
774 {
775 // create it now
776 m_listctrl = new wxListCtrl(this, -1,
777 wxDefaultPosition, wxDefaultSize,
224ff7a5
VZ
778 wxSUNKEN_BORDER |
779 wxLC_REPORT |
4aff28fc
VZ
780 wxLC_NO_HEADER |
781 wxLC_SINGLE_SEL);
5f170f33
VZ
782 // no need to translate these strings as they're not shown to the
783 // user anyhow (we use wxLC_NO_HEADER style)
784 m_listctrl->InsertColumn(0, _T("Message"));
785 m_listctrl->InsertColumn(1, _T("Time"));
f1df0927
VZ
786
787 // prepare the imagelist
788 static const int ICON_SIZE = 16;
789 wxImageList *imageList = new wxImageList(ICON_SIZE, ICON_SIZE);
790
791 // order should be the same as in the switch below!
792 static const int icons[] =
793 {
794 wxICON_ERROR,
795 wxICON_EXCLAMATION,
796 wxICON_INFORMATION
797 };
798
799 for ( size_t icon = 0; icon < WXSIZEOF(icons); icon++ )
800 {
801 wxBitmap bmp = wxTheApp->GetStdIcon(icons[icon]);
802 imageList->Add(wxImage(bmp).
803 Rescale(ICON_SIZE, ICON_SIZE).
804 ConvertToBitmap());
805 }
806
807 m_listctrl->SetImageList(imageList, wxIMAGE_LIST_SMALL);
808
809 // and fill it
810 wxString fmt = wxLog::GetTimestamp();
811 if ( !fmt )
812 {
813 // default format
814 fmt = _T("%X");
815 }
816
817 size_t count = m_messages.GetCount();
818 for ( size_t n = 0; n < count; n++ )
819 {
820 int image;
821 switch ( m_severity[n] )
822 {
823 case wxLOG_Error:
824 image = 0;
825 break;
826
827 case wxLOG_Warning:
828 image = 1;
829 break;
830
831 default:
832 image = 2;
833 }
834
835 m_listctrl->InsertItem(n, m_messages[n], image);
836 m_listctrl->SetItem(n, 1,
837 wxDateTime((time_t)m_times[n]).Format(fmt));
838 }
839
50af7fa9 840 // let the columns size themselves
f1df0927
VZ
841 m_listctrl->SetColumnWidth(0, wxLIST_AUTOSIZE);
842 m_listctrl->SetColumnWidth(1, wxLIST_AUTOSIZE);
843
844 // get the approx height of the listctrl
845 wxFont font = GetFont();
846 if ( !font.Ok() )
847 font = *wxSWISS_FONT;
848
849 int y;
850 GetTextExtent(_T("H"), (int*)NULL, &y, (int*)NULL, (int*)NULL, &font);
851 int height = wxMin(y*(count + 3), 100);
852 m_listctrl->SetSize(-1, height);
853 }
854
855 sizer->Add(m_listctrl, 1, wxEXPAND|(wxALL & ~wxTOP), MARGIN);
856 }
857
858 m_showingDetails = !m_showingDetails;
859
860 // in any case, our size changed - update
ea451729 861 sizer->SetSizeHints(this);
f1df0927
VZ
862 sizer->Fit(this);
863}
864
865wxLogDialog::~wxLogDialog()
866{
867 if ( m_listctrl )
868 {
869 delete m_listctrl->GetImageList(wxIMAGE_LIST_SMALL);
870 }
871}
872
873#endif // wxUSE_LOG_DIALOG