wxLogWindoe changed again: now takes a parent frame in ctor
[wxWidgets.git] / src / common / log.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: log.cpp
3 // Purpose: Assorted wxLogXXX functions, and wxLog (sink for logs)
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 29/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19 #ifdef __GNUG__
20 #pragma implementation "log.h"
21 #endif
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 // wxWindows
31 #ifndef WX_PRECOMP
32 #include <wx/app.h>
33 #include <wx/string.h>
34 #include <wx/intl.h>
35 #include <wx/menu.h>
36
37 #include <wx/generic/msgdlgg.h>
38 #include <wx/filedlg.h>
39 #include <wx/textctrl.h>
40 #endif //WX_PRECOMP
41
42 #include <wx/file.h>
43 #include <wx/textfile.h>
44 #include <wx/utils.h>
45 #include <wx/log.h>
46
47 // other standard headers
48 #include <errno.h>
49 #include <stdlib.h>
50 #include <time.h>
51
52 #ifdef __WXMSW__
53 #include <windows.h>
54 #else //Unix
55 #include <signal.h>
56 #endif //Win/Unix
57
58 // ----------------------------------------------------------------------------
59 // non member functions
60 // ----------------------------------------------------------------------------
61
62 // define this to enable wrapping of log messages
63 //#define LOG_PRETTY_WRAP
64
65 #ifdef LOG_PRETTY_WRAP
66 static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz);
67 #endif
68
69 // ----------------------------------------------------------------------------
70 // global variables
71 // ----------------------------------------------------------------------------
72
73 // we use a global variable to store the frame pointer for wxLogStatus - bad,
74 // but it's he easiest way
75 static wxFrame *gs_pFrame;
76
77 // ============================================================================
78 // implementation
79 // ============================================================================
80
81 // ----------------------------------------------------------------------------
82 // implementation of Log functions
83 //
84 // NB: unfortunately we need all these distinct functions, we can't make them
85 // macros and not all compilers inline vararg functions.
86 // ----------------------------------------------------------------------------
87
88 // log functions can't allocate memory (LogError("out of memory...") should
89 // work!), so we use a static buffer for all log messages
90 #define LOG_BUFFER_SIZE (4096)
91
92 // static buffer for error messages (@@@ MT-unsafe)
93 static char s_szBuf[LOG_BUFFER_SIZE];
94
95 // generic log function
96 void wxLogGeneric(wxLogLevel level, const char *szFormat, ...)
97 {
98 if ( wxLog::GetActiveTarget() != NULL ) {
99 va_list argptr;
100 va_start(argptr, szFormat);
101 vsprintf(s_szBuf, szFormat, argptr);
102 va_end(argptr);
103
104 wxLog::OnLog(level, s_szBuf);
105 }
106 }
107
108 #define IMPLEMENT_LOG_FUNCTION(level) \
109 void wxLog##level(const char *szFormat, ...) \
110 { \
111 if ( wxLog::GetActiveTarget() != NULL ) { \
112 va_list argptr; \
113 va_start(argptr, szFormat); \
114 vsprintf(s_szBuf, szFormat, argptr); \
115 va_end(argptr); \
116 \
117 wxLog::OnLog(wxLOG_##level, s_szBuf); \
118 } \
119 }
120
121 IMPLEMENT_LOG_FUNCTION(FatalError)
122 IMPLEMENT_LOG_FUNCTION(Error)
123 IMPLEMENT_LOG_FUNCTION(Warning)
124 IMPLEMENT_LOG_FUNCTION(Message)
125 IMPLEMENT_LOG_FUNCTION(Info)
126 IMPLEMENT_LOG_FUNCTION(Status)
127
128 // accepts an additional argument which tells to which frame the output should
129 // be directed
130 void wxLogStatus(wxFrame *pFrame, const char *szFormat, ...)
131 {
132 wxLog *pLog = wxLog::GetActiveTarget();
133 if ( pLog != NULL ) {
134 va_list argptr;
135 va_start(argptr, szFormat);
136 vsprintf(s_szBuf, szFormat, argptr);
137 va_end(argptr);
138
139 wxASSERT( gs_pFrame == NULL ); // should be reset!
140 gs_pFrame = pFrame;
141 wxLog::OnLog(wxLOG_Status, s_szBuf);
142 gs_pFrame = NULL;
143 }
144 }
145
146 // same as info, but only if 'verbose' mode is on
147 void wxLogVerbose(const char *szFormat, ...)
148 {
149 wxLog *pLog = wxLog::GetActiveTarget();
150 if ( pLog != NULL && pLog->GetVerbose() ) {
151 va_list argptr;
152 va_start(argptr, szFormat);
153 vsprintf(s_szBuf, szFormat, argptr);
154 va_end(argptr);
155
156 wxLog::OnLog(wxLOG_Info, s_szBuf);
157 }
158 }
159
160 // debug functions
161 #ifdef __WXDEBUG__
162 #define IMPLEMENT_LOG_DEBUG_FUNCTION(level) \
163 void wxLog##level(const char *szFormat, ...) \
164 { \
165 if ( wxLog::GetActiveTarget() != NULL ) { \
166 va_list argptr; \
167 va_start(argptr, szFormat); \
168 vsprintf(s_szBuf, szFormat, argptr); \
169 va_end(argptr); \
170 \
171 wxLog::OnLog(wxLOG_##level, s_szBuf); \
172 } \
173 }
174
175 void wxLogTrace(wxTraceMask mask, const char *szFormat, ...)
176 {
177 wxLog *pLog = wxLog::GetActiveTarget();
178
179 // we check that all of mask bits are set in the current mask, so
180 // that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something
181 // if both bits are set.
182 if ( pLog != NULL && ((pLog->GetTraceMask() & mask) == mask) ) {
183 va_list argptr;
184 va_start(argptr, szFormat);
185 vsprintf(s_szBuf, szFormat, argptr);
186 va_end(argptr);
187
188 wxLog::OnLog(wxLOG_Trace, s_szBuf);
189 }
190 }
191
192 #else // release
193 #define IMPLEMENT_LOG_DEBUG_FUNCTION(level)
194 #endif
195
196 IMPLEMENT_LOG_DEBUG_FUNCTION(Debug)
197 IMPLEMENT_LOG_DEBUG_FUNCTION(Trace)
198
199 // wxLogSysError: one uses the last error code, for other you must give it
200 // explicitly
201
202 // common part of both wxLogSysError
203 void wxLogSysErrorHelper(long lErrCode)
204 {
205 char szErrMsg[LOG_BUFFER_SIZE / 2];
206 sprintf(szErrMsg, _(" (error %ld: %s)"), lErrCode, wxSysErrorMsg(lErrCode));
207 strncat(s_szBuf, szErrMsg, WXSIZEOF(s_szBuf) - strlen(s_szBuf));
208
209 wxLog::OnLog(wxLOG_Error, s_szBuf);
210 }
211
212 void WXDLLEXPORT wxLogSysError(const char *szFormat, ...)
213 {
214 va_list argptr;
215 va_start(argptr, szFormat);
216 vsprintf(s_szBuf, szFormat, argptr);
217 va_end(argptr);
218
219 wxLogSysErrorHelper(wxSysErrorCode());
220 }
221
222 void WXDLLEXPORT wxLogSysError(long lErrCode, const char *szFormat, ...)
223 {
224 va_list argptr;
225 va_start(argptr, szFormat);
226 vsprintf(s_szBuf, szFormat, argptr);
227 va_end(argptr);
228
229 wxLogSysErrorHelper(lErrCode);
230 }
231
232 // ----------------------------------------------------------------------------
233 // wxLog class implementation
234 // ----------------------------------------------------------------------------
235
236 wxLog::wxLog()
237 {
238 m_bHasMessages = FALSE;
239 m_bVerbose = FALSE;
240 m_szTimeFormat = "[%d/%b/%y %H:%M:%S] ";
241 }
242
243 wxLog *wxLog::GetActiveTarget()
244 {
245 if ( ms_bAutoCreate && ms_pLogger == NULL ) {
246 // prevent infinite recursion if someone calls wxLogXXX() from
247 // wxApp::CreateLogTarget()
248 static bool s_bInGetActiveTarget = FALSE;
249 if ( !s_bInGetActiveTarget ) {
250 s_bInGetActiveTarget = TRUE;
251
252 #ifdef WX_TEST_MINIMAL
253 ms_pLogger = new wxLogStderr;
254 #else
255 // ask the application to create a log target for us
256 if ( wxTheApp != NULL )
257 ms_pLogger = wxTheApp->CreateLogTarget();
258 #endif
259
260 // do nothing if it fails - what can we do?
261 }
262 }
263
264 return ms_pLogger;
265 }
266
267 wxLog *wxLog::SetActiveTarget(wxLog *pLogger)
268 {
269 // flush the old messages before changing
270 if ( ms_pLogger != NULL )
271 ms_pLogger->Flush();
272
273 wxLog *pOldLogger = ms_pLogger;
274 ms_pLogger = pLogger;
275 return pOldLogger;
276 }
277
278 wxString wxLog::TimeStamp() const
279 {
280 wxString str;
281
282 if ( !IsEmpty(m_szTimeFormat) ) {
283 char szBuf[128];
284 time_t timeNow;
285 struct tm *ptmNow;
286
287 time(&timeNow);
288 ptmNow = localtime(&timeNow);
289
290 strftime(szBuf, WXSIZEOF(szBuf), m_szTimeFormat, ptmNow);
291 str = szBuf;
292 }
293
294 return str;
295 }
296
297 void wxLog::DoLog(wxLogLevel level, const char *szString)
298 {
299 // prepend a timestamp if not disabled
300 wxString str = TimeStamp();
301
302 switch ( level ) {
303 case wxLOG_FatalError:
304 DoLogString(str << _("Fatal error: ") << szString);
305 DoLogString(_("Program aborted."));
306 Flush();
307 abort();
308 break;
309
310 case wxLOG_Error:
311 DoLogString(str << _("Error: ") << szString);
312 break;
313
314 case wxLOG_Warning:
315 DoLogString(str << _("Warning: ") << szString);
316 break;
317
318 case wxLOG_Info:
319 if ( GetVerbose() )
320 case wxLOG_Message:
321 DoLogString(str + szString);
322 // fall through
323
324 case wxLOG_Status:
325 // nothing to do
326 break;
327
328 case wxLOG_Trace:
329 case wxLOG_Debug:
330 #ifdef __WXDEBUG__
331 DoLogString(str << (level == wxLOG_Trace ? _("Trace") : _("Debug"))
332 << ": " << szString);
333 #endif
334
335 break;
336
337 default:
338 wxFAIL_MSG(_("unknown log level in wxLog::DoLog"));
339 }
340 }
341
342 void wxLog::DoLogString(const char *WXUNUSED(szString))
343 {
344 wxFAIL_MSG(_("DoLogString must be overrided if it's called."));
345 }
346
347 void wxLog::Flush()
348 {
349 // do nothing
350 }
351
352 // ----------------------------------------------------------------------------
353 // wxLogStderr class implementation
354 // ----------------------------------------------------------------------------
355
356 wxLogStderr::wxLogStderr(FILE *fp)
357 {
358 if ( fp == NULL )
359 m_fp = stderr;
360 else
361 m_fp = fp;
362 }
363
364 void wxLogStderr::DoLogString(const char *szString)
365 {
366 fputs(szString, m_fp);
367 fputc('\n', m_fp);
368 fflush(m_fp);
369 }
370
371 // ----------------------------------------------------------------------------
372 // wxLogStream implementation
373 // ----------------------------------------------------------------------------
374
375 wxLogStream::wxLogStream(ostream *ostr)
376 {
377 if ( ostr == NULL )
378 m_ostr = &cerr;
379 else
380 m_ostr = ostr;
381 }
382
383 void wxLogStream::DoLogString(const char *szString)
384 {
385 (*m_ostr) << szString << endl << flush;
386 }
387
388 // ----------------------------------------------------------------------------
389 // wxLogTextCtrl implementation
390 // ----------------------------------------------------------------------------
391 wxLogTextCtrl::wxLogTextCtrl(wxTextCtrl *pTextCtrl)
392 // @@@ TODO: in wxGTK wxTextCtrl doesn't derive from streambuf
393
394 // Also, in DLL mode in wxMSW, can't use it.
395 #if defined(NO_TEXT_WINDOW_STREAM)
396 #else
397 : wxLogStream(new ostream(pTextCtrl))
398 #endif
399 {
400 }
401
402 wxLogTextCtrl::~wxLogTextCtrl()
403 {
404 delete m_ostr;
405 }
406
407 // ----------------------------------------------------------------------------
408 // wxLogGui implementation
409 // ----------------------------------------------------------------------------
410
411 #ifndef WX_TEST_MINIMAL
412
413 wxLogGui::wxLogGui()
414 {
415 m_bErrors = FALSE;
416 }
417
418 void wxLogGui::Flush()
419 {
420 if ( !m_bHasMessages )
421 return;
422
423 // @@@ ugly...
424
425 // concatenate all strings (but not too many to not overfill the msg box)
426 wxString str;
427 uint nLines = 0,
428 nMsgCount = m_aMessages.Count();
429
430 // start from the most recent message
431 for ( uint n = nMsgCount; n > 0; n-- ) {
432 // for Windows strings longer than this value are wrapped (NT 4.0)
433 const uint nMsgLineWidth = 156;
434
435 nLines += (m_aMessages[n - 1].Len() + nMsgLineWidth - 1) / nMsgLineWidth;
436
437 if ( nLines > 25 ) // don't put too many lines in message box
438 break;
439
440 str << m_aMessages[n - 1] << "\n";
441 }
442
443 if ( m_bErrors ) {
444 wxMessageBox(str, _("Error"), wxOK | wxICON_EXCLAMATION);
445 }
446 else {
447 wxMessageBox(str, _("Information"), wxOK | wxICON_INFORMATION);
448 }
449
450 // no undisplayed messages whatsoever
451 m_bHasMessages =
452 m_bErrors = FALSE;
453 m_aMessages.Empty();
454 }
455
456 // the default behaviour is to discard all informational messages if there
457 // are any errors/warnings.
458 void wxLogGui::DoLog(wxLogLevel level, const char *szString)
459 {
460 switch ( level ) {
461 case wxLOG_Info:
462 if ( GetVerbose() )
463 case wxLOG_Message:
464 if ( !m_bErrors ) {
465 m_aMessages.Add(szString);
466 m_bHasMessages = TRUE;
467 }
468 break;
469
470 case wxLOG_Status:
471 {
472 // find the top window and set it's status text if it has any
473 wxFrame *pFrame = gs_pFrame;
474 if ( pFrame == NULL ) {
475 wxWindow *pWin = wxTheApp->GetTopWindow();
476 if ( pWin != NULL && pWin->IsKindOf(CLASSINFO(wxFrame)) ) {
477 pFrame = (wxFrame *)pWin;
478 }
479 }
480
481 if ( pFrame != NULL )
482 pFrame->SetStatusText(szString);
483 }
484 break;
485
486 case wxLOG_Trace:
487 case wxLOG_Debug:
488 #ifdef __WXDEBUG__
489 {
490 wxString strTime = TimeStamp();
491
492 #ifdef __WIN32__
493 // don't prepend debug/trace here: it goes to the debug window
494 // anyhow, but do put a timestamp
495 OutputDebugString(strTime + szString + "\n\r");
496 #else //!WIN32
497 // send them to stderr
498 fprintf(stderr, "%s %s: %s\n",
499 strTime.c_str(),
500 level == wxLOG_Trace ? _("Trace") : _("Debug"),
501 szString);
502 fflush(stderr);
503 #endif // WIN32
504 }
505 #endif
506 break;
507
508 case wxLOG_FatalError:
509 // show this one immediately
510 wxMessageBox(szString, _("Fatal error"), wxICON_HAND);
511 break;
512
513 case wxLOG_Error:
514 case wxLOG_Warning:
515 // discard earlier informational messages if this is the 1st error
516 if ( !m_bErrors ) {
517 m_aMessages.Empty();
518 m_bHasMessages = TRUE;
519 m_bErrors = TRUE;
520 }
521
522 m_aMessages.Add(szString);
523 break;
524
525 default:
526 wxFAIL_MSG(_("unknown log level in wxLogGui::DoLog"));
527 }
528 }
529
530 // ----------------------------------------------------------------------------
531 // wxLogWindow and wxLogFrame implementation
532 // ----------------------------------------------------------------------------
533
534 // log frame class
535 // ---------------
536 class wxLogFrame : public wxFrame
537 {
538 public:
539 // ctor & dtor
540 wxLogFrame(wxFrame *pParent, wxLogWindow *log, const char *szTitle);
541 virtual ~wxLogFrame();
542
543 // menu callbacks
544 void OnClose(wxCommandEvent& event);
545 void OnCloseWindow(wxCloseEvent& event);
546 void OnSave (wxCommandEvent& event);
547 void OnClear(wxCommandEvent& event);
548
549 void OnIdle(wxIdleEvent&);
550
551 // accessors
552 wxTextCtrl *TextCtrl() const { return m_pTextCtrl; }
553
554 private:
555 enum
556 {
557 Menu_Close = 100,
558 Menu_Save,
559 Menu_Clear
560 };
561
562 // instead of closing just hide the window to be able to Show() it later
563 void DoClose() { Show(FALSE); }
564
565 wxTextCtrl *m_pTextCtrl;
566 wxLogWindow *m_log;
567
568 DECLARE_EVENT_TABLE()
569 };
570
571 BEGIN_EVENT_TABLE(wxLogFrame, wxFrame)
572 // wxLogWindow menu events
573 EVT_MENU(Menu_Close, wxLogFrame::OnClose)
574 EVT_MENU(Menu_Save, wxLogFrame::OnSave)
575 EVT_MENU(Menu_Clear, wxLogFrame::OnClear)
576
577 EVT_CLOSE(wxLogFrame::OnCloseWindow)
578 END_EVENT_TABLE()
579
580 wxLogFrame::wxLogFrame(wxFrame *pParent, wxLogWindow *log, const char *szTitle)
581 : wxFrame(pParent, -1, szTitle)
582 {
583 m_log = log;
584
585 // @@ kludge: wxSIMPLE_BORDER is simply to prevent wxWindows from creating
586 // a rich edit control instead of a normal one we want in wxMSW
587 m_pTextCtrl = new wxTextCtrl(this, -1, wxEmptyString, wxDefaultPosition,
588 wxDefaultSize,
589 //wxSIMPLE_BORDER |
590 wxTE_MULTILINE |
591 wxHSCROLL |
592 wxTE_READONLY);
593
594 // create menu
595 wxMenuBar *pMenuBar = new wxMenuBar;
596 wxMenu *pMenu = new wxMenu;
597 pMenu->Append(Menu_Save, _("&Save..."), _("Save log contents to file"));
598 pMenu->Append(Menu_Clear, _("C&lear"), _("Clear the log contents"));
599 pMenu->AppendSeparator();
600 pMenu->Append(Menu_Close, _("&Close"), _("Close this window"));
601 pMenuBar->Append(pMenu, _("&Log"));
602 SetMenuBar(pMenuBar);
603
604 // status bar for menu prompts
605 CreateStatusBar();
606
607 m_log->OnFrameCreate(this);
608 }
609
610 void wxLogFrame::OnClose(wxCommandEvent& WXUNUSED(event))
611 {
612 DoClose();
613 }
614
615 void wxLogFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
616 {
617 DoClose();
618 }
619
620 void wxLogFrame::OnSave(wxCommandEvent& WXUNUSED(event))
621 {
622 // get the file name
623 // -----------------
624 const char *szFileName = wxSaveFileSelector("log", "txt", "log.txt");
625 if ( szFileName == NULL ) {
626 // cancelled
627 return;
628 }
629
630 // open file
631 // ---------
632 wxFile file;
633 bool bOk = FALSE;
634 if ( wxFile::Exists(szFileName) ) {
635 bool bAppend = FALSE;
636 wxString strMsg;
637 strMsg.Printf(_("Append log to file '%s' "
638 "(choosing [No] will overwrite it)?"), szFileName);
639 switch ( wxMessageBox(strMsg, _("Question"), wxYES_NO | wxCANCEL) ) {
640 case wxYES:
641 bAppend = TRUE;
642 break;
643
644 case wxNO:
645 bAppend = FALSE;
646 break;
647
648 case wxCANCEL:
649 return;
650
651 default:
652 wxFAIL_MSG(_("invalid message box return value"));
653 }
654
655 if ( bAppend ) {
656 bOk = file.Open(szFileName, wxFile::write_append);
657 }
658 else {
659 bOk = file.Create(szFileName, TRUE /* overwrite */);
660 }
661 }
662 else {
663 bOk = file.Create(szFileName);
664 }
665
666 // retrieve text and save it
667 // -------------------------
668 #ifdef __WXGTK__
669 // @@@@ TODO: no GetNumberOfLines and GetLineText in wxGTK yet
670 wxLogError(_("Sorry, this function is not implemented under GTK"));
671 #else
672 int nLines = m_pTextCtrl->GetNumberOfLines();
673 for ( int nLine = 0; bOk && nLine < nLines; nLine++ ) {
674 bOk = file.Write(m_pTextCtrl->GetLineText(nLine) + wxTextFile::GetEOL());
675 }
676 #endif //GTK
677
678 if ( bOk )
679 bOk = file.Close();
680
681 if ( !bOk ) {
682 wxLogError(_("Can't save log contents to file."));
683 return;
684 }
685 }
686
687 void wxLogFrame::OnClear(wxCommandEvent& WXUNUSED(event))
688 {
689 m_pTextCtrl->Clear();
690 }
691
692 wxLogFrame::~wxLogFrame()
693 {
694 m_log->OnFrameDelete(this);
695 }
696
697 // wxLogWindow
698 // -----------
699 wxLogWindow::wxLogWindow(wxFrame *pParent,
700 const char *szTitle,
701 bool bShow,
702 bool bDoPass)
703 {
704 m_bPassMessages = bDoPass;
705
706 m_pLogFrame = new wxLogFrame(pParent, this, szTitle);
707 m_pOldLog = wxLog::SetActiveTarget(this);
708
709 if ( bShow )
710 m_pLogFrame->Show(TRUE);
711 }
712
713 void wxLogWindow::Show(bool bShow)
714 {
715 m_pLogFrame->Show(bShow);
716 }
717
718 void wxLogWindow::Flush()
719 {
720 if ( m_pOldLog != NULL )
721 m_pOldLog->Flush();
722
723 m_bHasMessages = FALSE;
724 }
725
726 void wxLogWindow::DoLog(wxLogLevel level, const char *szString)
727 {
728 // first let the previous logger show it
729 if ( m_pOldLog != NULL && m_bPassMessages ) {
730 // @@@ why can't we access protected wxLog method from here (we derive
731 // from wxLog)? gcc gives "DoLog is protected in this context", what
732 // does this mean? Anyhow, the cast is harmless and let's us do what
733 // we want.
734 ((wxLogWindow *)m_pOldLog)->DoLog(level, szString);
735 }
736
737 // don't put trace messages in the text window for 2 reasons:
738 // 1) there are too many of them
739 // 2) they may provoke other trace messages thus sending a program into an
740 // infinite loop
741 if ( m_pLogFrame && level != wxLOG_Trace ) {
742 // and this will format it nicely and call our DoLogString()
743 wxLog::DoLog(level, szString);
744 }
745
746 m_bHasMessages = TRUE;
747 }
748
749 void wxLogWindow::DoLogString(const char *szString)
750 {
751 // put the text into our window
752 wxTextCtrl *pText = m_pLogFrame->TextCtrl();
753
754 // remove selection (WriteText is in fact ReplaceSelection)
755 #ifdef __WXMSW__
756 long nLen = pText->GetLastPosition();
757 pText->SetSelection(nLen, nLen);
758 #endif // Windows
759
760 pText->WriteText(szString);
761 pText->WriteText("\n"); // "\n" ok here (_not_ "\r\n")
762
763 // ensure that the line can be seen
764 // @@@ TODO
765 }
766
767 wxFrame *wxLogWindow::GetFrame() const
768 {
769 return m_pLogFrame;
770 }
771
772 void wxLogWindow::OnFrameCreate(wxFrame *frame)
773 {
774 }
775
776 void wxLogWindow::OnFrameDelete(wxFrame *frame)
777 {
778 m_pLogFrame = NULL;
779 }
780
781 wxLogWindow::~wxLogWindow()
782 {
783 // may be NULL if log frame already auto destroyed itself
784 delete m_pLogFrame;
785 }
786
787 #endif //WX_TEST_MINIMAL
788
789 // ============================================================================
790 // Global functions/variables
791 // ============================================================================
792
793 // ----------------------------------------------------------------------------
794 // static variables
795 // ----------------------------------------------------------------------------
796 wxLog *wxLog::ms_pLogger = NULL;
797 bool wxLog::ms_bAutoCreate = TRUE;
798 wxTraceMask wxLog::ms_ulTraceMask = (wxTraceMask)0;
799
800 // ----------------------------------------------------------------------------
801 // stdout error logging helper
802 // ----------------------------------------------------------------------------
803
804 // helper function: wraps the message and justifies it under given position
805 // (looks more pretty on the terminal). Also adds newline at the end.
806 //
807 // @@ this is now disabled until I find a portable way of determining the
808 // terminal window size (ok, I found it but does anybody really cares?)
809 #ifdef LOG_PRETTY_WRAP
810 static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz)
811 {
812 size_t nMax = 80; // @@@@
813 size_t nStart = strlen(pszPrefix);
814 fputs(pszPrefix, f);
815
816 size_t n;
817 while ( *psz != '\0' ) {
818 for ( n = nStart; (n < nMax) && (*psz != '\0'); n++ )
819 putc(*psz++, f);
820
821 // wrapped?
822 if ( *psz != '\0' ) {
823 /*putc('\n', f);*/
824 for ( n = 0; n < nStart; n++ )
825 putc(' ', f);
826
827 // as we wrapped, squeeze all white space
828 while ( isspace(*psz) )
829 psz++;
830 }
831 }
832
833 putc('\n', f);
834 }
835 #endif //LOG_PRETTY_WRAP
836
837 // ----------------------------------------------------------------------------
838 // error code/error message retrieval functions
839 // ----------------------------------------------------------------------------
840
841 // get error code from syste
842 unsigned long wxSysErrorCode()
843 {
844 #ifdef __WXMSW__
845 #ifdef __WIN32__
846 return ::GetLastError();
847 #else //WIN16
848 // @@@@ what to do on Windows 3.1?
849 return 0;
850 #endif //WIN16/32
851 #else //Unix
852 return errno;
853 #endif //Win/Unix
854 }
855
856 // get error message from system
857 const char *wxSysErrorMsg(unsigned long nErrCode)
858 {
859 if ( nErrCode == 0 )
860 nErrCode = wxSysErrorCode();
861
862 #ifdef __WXMSW__
863 #ifdef __WIN32__
864 static char s_szBuf[LOG_BUFFER_SIZE / 2];
865
866 // get error message from system
867 LPVOID lpMsgBuf;
868 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
869 NULL, nErrCode,
870 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
871 (LPTSTR)&lpMsgBuf,
872 0, NULL);
873
874 // copy it to our buffer and free memory
875 strncpy(s_szBuf, (const char *)lpMsgBuf, WXSIZEOF(s_szBuf) - 1);
876 s_szBuf[WXSIZEOF(s_szBuf) - 1] = '\0';
877 LocalFree(lpMsgBuf);
878
879 // returned string is capitalized and ended with '\r\n' - bad
880 s_szBuf[0] = (char)wxToLower(s_szBuf[0]);
881 size_t len = strlen(s_szBuf);
882 if ( len > 0 ) {
883 // truncate string
884 if ( s_szBuf[len - 2] == '\r' )
885 s_szBuf[len - 2] = '\0';
886 }
887
888 return s_szBuf;
889 #else //Win16
890 // TODO @@@@
891 return NULL;
892 #endif // Win16/32
893 #else // Unix
894 return strerror(nErrCode);
895 #endif // Win/Unix
896 }
897
898 // ----------------------------------------------------------------------------
899 // debug helper
900 // ----------------------------------------------------------------------------
901
902 #ifdef __WXDEBUG__
903
904 void Trap()
905 {
906 #ifdef __WXMSW__
907 DebugBreak();
908 #else // Unix
909 raise(SIGTRAP);
910 #endif // Win/Unix
911 }
912
913 // this function is called when an assert fails
914 void wxOnAssert(const char *szFile, int nLine, const char *szMsg)
915 {
916 // this variable can be set to true to suppress "assert failure" messages
917 static bool s_bNoAsserts = FALSE;
918 static bool s_bInAssert = FALSE;
919
920 if ( s_bInAssert ) {
921 // He-e-e-e-elp!! we're trapped in endless loop
922 Trap();
923 }
924
925 s_bInAssert = TRUE;
926
927 char szBuf[LOG_BUFFER_SIZE];
928 sprintf(szBuf, _("Assert failed in file %s at line %d"), szFile, nLine);
929 if ( szMsg != NULL ) {
930 strcat(szBuf, ": ");
931 strcat(szBuf, szMsg);
932 }
933 else {
934 strcat(szBuf, ".");
935 }
936
937 if ( !s_bNoAsserts ) {
938 // send it to the normal log destination
939 wxLogDebug(szBuf);
940
941 strcat(szBuf, _("\nDo you want to stop the program?"
942 "\nYou can also choose [Cancel] to suppress "
943 "further warnings."));
944
945 switch ( wxMessageBox(szBuf, _("Debug"),
946 wxYES_NO | wxCANCEL | wxICON_STOP ) ) {
947 case wxYES:
948 Trap();
949 break;
950
951 case wxCANCEL:
952 s_bNoAsserts = TRUE;
953 break;
954
955 //case wxNO: nothing to do
956 }
957 }
958
959 s_bInAssert = FALSE;
960 }
961
962 #endif //WXDEBUG
963