]>
git.saurik.com Git - wxWidgets.git/blob - src/generic/logg.cpp
1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxLog-derived classes which need GUI support (the rest is in
5 // Author: Vadim Zeitlin
7 // Created: 20.09.99 (extracted from src/common/log.cpp)
9 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
10 // Licence: wxWindows license
11 /////////////////////////////////////////////////////////////////////////////
13 // ============================================================================
15 // ============================================================================
17 // ----------------------------------------------------------------------------
19 // ----------------------------------------------------------------------------
21 // no #pragma implementation "log.h" because it's already in src/common/log.cpp
23 // For compilers that support precompilation, includes "wx.h".
24 #include "wx/wxprec.h"
31 #error "This file can't be compiled in NOGUI mode!"
40 #include "wx/filedlg.h"
41 #include "wx/msgdlg.h"
42 #include "wx/textctrl.h"
46 #include "wx/textfile.h"
48 // ----------------------------------------------------------------------------
50 // ----------------------------------------------------------------------------
52 // we use a global variable to store the frame pointer for wxLogStatus - bad,
53 // but it's he easiest way
54 static wxFrame
*gs_pFrame
; // FIXME MT-unsafe
56 // ============================================================================
58 // ============================================================================
60 // ----------------------------------------------------------------------------
62 // ----------------------------------------------------------------------------
64 // accepts an additional argument which tells to which frame the output should
66 void wxLogStatus(wxFrame
*pFrame
, const wxChar
*szFormat
, ...)
70 wxLog
*pLog
= wxLog::GetActiveTarget();
73 va_start(argptr
, szFormat
);
74 msg
.PrintfV(szFormat
, argptr
);
77 wxASSERT( gs_pFrame
== NULL
); // should be reset!
79 wxLog::OnLog(wxLOG_Status
, msg
, time(NULL
));
80 gs_pFrame
= (wxFrame
*) NULL
;
84 // ----------------------------------------------------------------------------
85 // wxLogTextCtrl implementation
86 // ----------------------------------------------------------------------------
88 wxLogTextCtrl::wxLogTextCtrl(wxTextCtrl
*pTextCtrl
)
90 m_pTextCtrl
= pTextCtrl
;
93 void wxLogTextCtrl::DoLogString(const wxChar
*szString
, time_t t
)
97 msg
<< szString
<< _T('\n');
99 m_pTextCtrl
->AppendText(msg
);
102 // ----------------------------------------------------------------------------
103 // wxLogGui implementation (FIXME MT-unsafe)
104 // ----------------------------------------------------------------------------
111 void wxLogGui::Clear()
113 m_bErrors
= m_bWarnings
= FALSE
;
118 void wxLogGui::Flush()
120 if ( !m_bHasMessages
)
123 // do it right now to block any new calls to Flush() while we're here
124 m_bHasMessages
= FALSE
;
126 // concatenate all strings (but not too many to not overfill the msg box)
129 nMsgCount
= m_aMessages
.Count();
131 // start from the most recent message
132 for ( size_t n
= nMsgCount
; n
> 0; n
-- ) {
133 // for Windows strings longer than this value are wrapped (NT 4.0)
134 const size_t nMsgLineWidth
= 156;
136 nLines
+= (m_aMessages
[n
- 1].Len() + nMsgLineWidth
- 1) / nMsgLineWidth
;
138 if ( nLines
> 25 ) // don't put too many lines in message box
141 str
<< m_aMessages
[n
- 1] << _T("\n");
151 else if ( m_bWarnings
) {
152 title
= _("Warning");
153 style
= wxICON_EXCLAMATION
;
156 title
= _("Information");
157 style
= wxICON_INFORMATION
;
160 wxMessageBox(str
, title
, wxOK
| style
);
162 // no undisplayed messages whatsoever
166 m_bHasMessages
= FALSE
;
169 // the default behaviour is to discard all informational messages if there
170 // are any errors/warnings.
171 void wxLogGui::DoLog(wxLogLevel level
, const wxChar
*szString
, time_t t
)
178 m_aMessages
.Add(szString
);
179 m_aTimes
.Add((long)t
);
180 m_bHasMessages
= TRUE
;
187 // find the top window and set it's status text if it has any
188 wxFrame
*pFrame
= gs_pFrame
;
189 if ( pFrame
== NULL
) {
190 wxWindow
*pWin
= wxTheApp
->GetTopWindow();
191 if ( pWin
!= NULL
&& pWin
->IsKindOf(CLASSINFO(wxFrame
)) ) {
192 pFrame
= (wxFrame
*)pWin
;
196 if ( pFrame
!= NULL
)
197 pFrame
->SetStatusText(szString
);
199 #endif // wxUSE_STATUSBAR
207 // don't prepend debug/trace here: it goes to the
208 // debug window anyhow, but do put a timestamp
211 str
<< szString
<< _T("\n\r");
212 OutputDebugString(str
);
214 // send them to stderr
215 wxFprintf(stderr
, _T("%s: %s\n"),
216 level
== wxLOG_Trace
? _T("Trace")
222 #endif // __WXDEBUG__
226 case wxLOG_FatalError
:
227 // show this one immediately
228 wxMessageBox(szString
, _("Fatal error"), wxICON_HAND
);
232 // discard earlier informational messages if this is the 1st
233 // error because they might not make sense any more
243 // for the warning we don't discard the info messages
247 m_aMessages
.Add(szString
);
248 m_aTimes
.Add((long)t
);
249 m_bHasMessages
= TRUE
;
254 // ----------------------------------------------------------------------------
255 // wxLogWindow and wxLogFrame implementation
256 // ----------------------------------------------------------------------------
260 class wxLogFrame
: public wxFrame
264 wxLogFrame(wxFrame
*pParent
, wxLogWindow
*log
, const wxChar
*szTitle
);
265 virtual ~wxLogFrame();
268 void OnClose(wxCommandEvent
& event
);
269 void OnCloseWindow(wxCloseEvent
& event
);
271 void OnSave (wxCommandEvent
& event
);
273 void OnClear(wxCommandEvent
& event
);
275 void OnIdle(wxIdleEvent
&);
278 wxTextCtrl
*TextCtrl() const { return m_pTextCtrl
; }
288 // instead of closing just hide the window to be able to Show() it later
289 void DoClose() { Show(FALSE
); }
291 wxTextCtrl
*m_pTextCtrl
;
294 DECLARE_EVENT_TABLE()
297 BEGIN_EVENT_TABLE(wxLogFrame
, wxFrame
)
298 // wxLogWindow menu events
299 EVT_MENU(Menu_Close
, wxLogFrame::OnClose
)
301 EVT_MENU(Menu_Save
, wxLogFrame::OnSave
)
303 EVT_MENU(Menu_Clear
, wxLogFrame::OnClear
)
305 EVT_CLOSE(wxLogFrame::OnCloseWindow
)
308 wxLogFrame::wxLogFrame(wxFrame
*pParent
, wxLogWindow
*log
, const wxChar
*szTitle
)
309 : wxFrame(pParent
, -1, szTitle
)
313 m_pTextCtrl
= new wxTextCtrl(this, -1, wxEmptyString
, wxDefaultPosition
,
320 wxMenuBar
*pMenuBar
= new wxMenuBar
;
321 wxMenu
*pMenu
= new wxMenu
;
323 pMenu
->Append(Menu_Save
, _("&Save..."), _("Save log contents to file"));
325 pMenu
->Append(Menu_Clear
, _("C&lear"), _("Clear the log contents"));
326 pMenu
->AppendSeparator();
327 pMenu
->Append(Menu_Close
, _("&Close"), _("Close this window"));
328 pMenuBar
->Append(pMenu
, _("&Log"));
329 SetMenuBar(pMenuBar
);
332 // status bar for menu prompts
334 #endif // wxUSE_STATUSBAR
336 m_log
->OnFrameCreate(this);
339 void wxLogFrame::OnClose(wxCommandEvent
& WXUNUSED(event
))
344 void wxLogFrame::OnCloseWindow(wxCloseEvent
& WXUNUSED(event
))
350 void wxLogFrame::OnSave(wxCommandEvent
& WXUNUSED(event
))
354 const wxChar
*szFileName
= wxSaveFileSelector(_T("log"), _T("txt"), _T("log.txt"));
355 if ( szFileName
== NULL
) {
364 if ( wxFile::Exists(szFileName
) ) {
365 bool bAppend
= FALSE
;
367 strMsg
.Printf(_("Append log to file '%s' "
368 "(choosing [No] will overwrite it)?"), szFileName
);
369 switch ( wxMessageBox(strMsg
, _("Question"), wxYES_NO
| wxCANCEL
) ) {
382 wxFAIL_MSG(_("invalid message box return value"));
386 bOk
= file
.Open(szFileName
, wxFile::write_append
);
389 bOk
= file
.Create(szFileName
, TRUE
/* overwrite */);
393 bOk
= file
.Create(szFileName
);
396 // retrieve text and save it
397 // -------------------------
398 int nLines
= m_pTextCtrl
->GetNumberOfLines();
399 for ( int nLine
= 0; bOk
&& nLine
< nLines
; nLine
++ ) {
400 bOk
= file
.Write(m_pTextCtrl
->GetLineText(nLine
) +
401 // we're not going to pull in the whole wxTextFile if all we need is this...
404 #else // !wxUSE_TEXTFILE
406 #endif // wxUSE_TEXTFILE
414 wxLogError(_("Can't save log contents to file."));
417 wxLogStatus(this, _("Log saved to the file '%s'."), szFileName
);
422 void wxLogFrame::OnClear(wxCommandEvent
& WXUNUSED(event
))
424 m_pTextCtrl
->Clear();
427 wxLogFrame::~wxLogFrame()
429 m_log
->OnFrameDelete(this);
434 wxLogWindow::wxLogWindow(wxFrame
*pParent
,
435 const wxChar
*szTitle
,
439 m_bPassMessages
= bDoPass
;
441 m_pLogFrame
= new wxLogFrame(pParent
, this, szTitle
);
442 m_pOldLog
= wxLog::SetActiveTarget(this);
445 m_pLogFrame
->Show(TRUE
);
448 void wxLogWindow::Show(bool bShow
)
450 m_pLogFrame
->Show(bShow
);
453 void wxLogWindow::Flush()
455 if ( m_pOldLog
!= NULL
)
458 m_bHasMessages
= FALSE
;
461 void wxLogWindow::DoLog(wxLogLevel level
, const wxChar
*szString
, time_t t
)
463 // first let the previous logger show it
464 if ( m_pOldLog
!= NULL
&& m_bPassMessages
) {
465 // FIXME why can't we access protected wxLog method from here (we derive
466 // from wxLog)? gcc gives "DoLog is protected in this context", what
467 // does this mean? Anyhow, the cast is harmless and let's us do what
469 ((wxLogWindow
*)m_pOldLog
)->DoLog(level
, szString
, t
);
475 // by default, these messages are ignored by wxLog, so process
477 if ( !wxIsEmpty(szString
) )
480 str
<< _("Status: ") << szString
;
485 // don't put trace messages in the text window for 2 reasons:
486 // 1) there are too many of them
487 // 2) they may provoke other trace messages thus sending a program
488 // into an infinite loop
493 // and this will format it nicely and call our DoLogString()
494 wxLog::DoLog(level
, szString
, t
);
498 m_bHasMessages
= TRUE
;
501 void wxLogWindow::DoLogString(const wxChar
*szString
, time_t WXUNUSED(t
))
503 // put the text into our window
504 wxTextCtrl
*pText
= m_pLogFrame
->TextCtrl();
506 // remove selection (WriteText is in fact ReplaceSelection)
508 long nLen
= pText
->GetLastPosition();
509 pText
->SetSelection(nLen
, nLen
);
514 msg
<< szString
<< _T('\n');
516 pText
->AppendText(msg
);
518 // TODO ensure that the line can be seen
521 wxFrame
*wxLogWindow::GetFrame() const
526 void wxLogWindow::OnFrameCreate(wxFrame
* WXUNUSED(frame
))
530 void wxLogWindow::OnFrameDelete(wxFrame
* WXUNUSED(frame
))
532 m_pLogFrame
= (wxLogFrame
*)NULL
;
535 wxLogWindow::~wxLogWindow()
539 // may be NULL if log frame already auto destroyed itself