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