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