]>
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 without GUI!"
40 #include "wx/filedlg.h"
41 #include "wx/msgdlg.h"
42 #include "wx/textctrl.h"
46 #include "wx/textfile.h"
49 // for OutputDebugString()
50 #include "wx/msw/private.h"
53 // ----------------------------------------------------------------------------
55 // ----------------------------------------------------------------------------
57 // we use a global variable to store the frame pointer for wxLogStatus - bad,
58 // but it's he easiest way
59 static wxFrame
*gs_pFrame
; // FIXME MT-unsafe
61 // ============================================================================
63 // ============================================================================
65 // ----------------------------------------------------------------------------
67 // ----------------------------------------------------------------------------
69 // accepts an additional argument which tells to which frame the output should
71 void wxLogStatus(wxFrame
*pFrame
, const wxChar
*szFormat
, ...)
75 wxLog
*pLog
= wxLog::GetActiveTarget();
78 va_start(argptr
, szFormat
);
79 msg
.PrintfV(szFormat
, argptr
);
82 wxASSERT( gs_pFrame
== NULL
); // should be reset!
84 wxLog::OnLog(wxLOG_Status
, msg
, time(NULL
));
85 gs_pFrame
= (wxFrame
*) NULL
;
89 // ----------------------------------------------------------------------------
90 // wxLogTextCtrl implementation
91 // ----------------------------------------------------------------------------
93 wxLogTextCtrl::wxLogTextCtrl(wxTextCtrl
*pTextCtrl
)
95 m_pTextCtrl
= pTextCtrl
;
98 void wxLogTextCtrl::DoLogString(const wxChar
*szString
, time_t WXUNUSED(t
))
102 msg
<< szString
<< wxT('\n');
104 m_pTextCtrl
->AppendText(msg
);
107 // ----------------------------------------------------------------------------
108 // wxLogGui implementation (FIXME MT-unsafe)
109 // ----------------------------------------------------------------------------
116 void wxLogGui::Clear()
118 m_bErrors
= m_bWarnings
= FALSE
;
123 void wxLogGui::Flush()
125 if ( !m_bHasMessages
)
128 // do it right now to block any new calls to Flush() while we're here
129 m_bHasMessages
= FALSE
;
131 // concatenate all strings (but not too many to not overfill the msg box)
134 nMsgCount
= m_aMessages
.Count();
136 // start from the most recent message
137 for ( size_t n
= nMsgCount
; n
> 0; n
-- ) {
138 // for Windows strings longer than this value are wrapped (NT 4.0)
139 const size_t nMsgLineWidth
= 156;
141 nLines
+= (m_aMessages
[n
- 1].Len() + nMsgLineWidth
- 1) / nMsgLineWidth
;
143 if ( nLines
> 25 ) // don't put too many lines in message box
146 str
<< m_aMessages
[n
- 1] << wxT("\n");
156 else if ( m_bWarnings
) {
157 title
= _("Warning");
158 style
= wxICON_EXCLAMATION
;
161 title
= _("Information");
162 style
= wxICON_INFORMATION
;
165 wxMessageBox(str
, title
, wxOK
| style
);
167 // no undisplayed messages whatsoever
171 m_bHasMessages
= FALSE
;
174 // the default behaviour is to discard all informational messages if there
175 // are any errors/warnings.
176 void wxLogGui::DoLog(wxLogLevel level
, const wxChar
*szString
, time_t t
)
183 m_aMessages
.Add(szString
);
184 m_aTimes
.Add((long)t
);
185 m_bHasMessages
= TRUE
;
192 // find the top window and set it's status text if it has any
193 wxFrame
*pFrame
= gs_pFrame
;
194 if ( pFrame
== NULL
) {
195 wxWindow
*pWin
= wxTheApp
->GetTopWindow();
196 if ( pWin
!= NULL
&& pWin
->IsKindOf(CLASSINFO(wxFrame
)) ) {
197 pFrame
= (wxFrame
*)pWin
;
201 if ( pFrame
&& pFrame
->GetStatusBar() )
202 pFrame
->SetStatusText(szString
);
204 #endif // wxUSE_STATUSBAR
212 // don't prepend debug/trace here: it goes to the
213 // debug window anyhow, but do put a timestamp
216 str
<< szString
<< wxT("\n\r");
217 OutputDebugString(str
);
219 // send them to stderr
220 wxFprintf(stderr
, wxT("%s: %s\n"),
221 level
== wxLOG_Trace
? wxT("Trace")
227 #endif // __WXDEBUG__
231 case wxLOG_FatalError
:
232 // show this one immediately
233 wxMessageBox(szString
, _("Fatal error"), wxICON_HAND
);
237 // discard earlier informational messages if this is the 1st
238 // error because they might not make sense any more
248 // for the warning we don't discard the info messages
252 m_aMessages
.Add(szString
);
253 m_aTimes
.Add((long)t
);
254 m_bHasMessages
= TRUE
;
259 // ----------------------------------------------------------------------------
260 // wxLogWindow and wxLogFrame implementation
261 // ----------------------------------------------------------------------------
265 class wxLogFrame
: public wxFrame
269 wxLogFrame(wxFrame
*pParent
, wxLogWindow
*log
, const wxChar
*szTitle
);
270 virtual ~wxLogFrame();
273 void OnClose(wxCommandEvent
& event
);
274 void OnCloseWindow(wxCloseEvent
& event
);
276 void OnSave (wxCommandEvent
& event
);
278 void OnClear(wxCommandEvent
& event
);
280 void OnIdle(wxIdleEvent
&);
283 wxTextCtrl
*TextCtrl() const { return m_pTextCtrl
; }
293 // instead of closing just hide the window to be able to Show() it later
294 void DoClose() { Show(FALSE
); }
296 wxTextCtrl
*m_pTextCtrl
;
299 DECLARE_EVENT_TABLE()
302 BEGIN_EVENT_TABLE(wxLogFrame
, wxFrame
)
303 // wxLogWindow menu events
304 EVT_MENU(Menu_Close
, wxLogFrame::OnClose
)
306 EVT_MENU(Menu_Save
, wxLogFrame::OnSave
)
308 EVT_MENU(Menu_Clear
, wxLogFrame::OnClear
)
310 EVT_CLOSE(wxLogFrame::OnCloseWindow
)
313 wxLogFrame::wxLogFrame(wxFrame
*pParent
, wxLogWindow
*log
, const wxChar
*szTitle
)
314 : wxFrame(pParent
, -1, szTitle
)
318 m_pTextCtrl
= new wxTextCtrl(this, -1, wxEmptyString
, wxDefaultPosition
,
325 wxMenuBar
*pMenuBar
= new wxMenuBar
;
326 wxMenu
*pMenu
= new wxMenu
;
328 pMenu
->Append(Menu_Save
, _("&Save..."), _("Save log contents to file"));
330 pMenu
->Append(Menu_Clear
, _("C&lear"), _("Clear the log contents"));
331 pMenu
->AppendSeparator();
332 pMenu
->Append(Menu_Close
, _("&Close"), _("Close this window"));
333 pMenuBar
->Append(pMenu
, _("&Log"));
334 SetMenuBar(pMenuBar
);
337 // status bar for menu prompts
339 #endif // wxUSE_STATUSBAR
341 m_log
->OnFrameCreate(this);
344 void wxLogFrame::OnClose(wxCommandEvent
& WXUNUSED(event
))
349 void wxLogFrame::OnCloseWindow(wxCloseEvent
& WXUNUSED(event
))
355 void wxLogFrame::OnSave(wxCommandEvent
& WXUNUSED(event
))
359 const wxChar
*szFileName
= wxSaveFileSelector(wxT("log"), wxT("txt"), wxT("log.txt"));
360 if ( szFileName
== NULL
) {
369 if ( wxFile::Exists(szFileName
) ) {
370 bool bAppend
= FALSE
;
372 strMsg
.Printf(_("Append log to file '%s' "
373 "(choosing [No] will overwrite it)?"), szFileName
);
374 switch ( wxMessageBox(strMsg
, _("Question"), wxYES_NO
| wxCANCEL
) ) {
387 wxFAIL_MSG(_("invalid message box return value"));
391 bOk
= file
.Open(szFileName
, wxFile::write_append
);
394 bOk
= file
.Create(szFileName
, TRUE
/* overwrite */);
398 bOk
= file
.Create(szFileName
);
401 // retrieve text and save it
402 // -------------------------
403 int nLines
= m_pTextCtrl
->GetNumberOfLines();
404 for ( int nLine
= 0; bOk
&& nLine
< nLines
; nLine
++ ) {
405 bOk
= file
.Write(m_pTextCtrl
->GetLineText(nLine
) +
406 // we're not going to pull in the whole wxTextFile if all we need is this...
409 #else // !wxUSE_TEXTFILE
411 #endif // wxUSE_TEXTFILE
419 wxLogError(_("Can't save log contents to file."));
422 wxLogStatus(this, _("Log saved to the file '%s'."), szFileName
);
427 void wxLogFrame::OnClear(wxCommandEvent
& WXUNUSED(event
))
429 m_pTextCtrl
->Clear();
432 wxLogFrame::~wxLogFrame()
434 m_log
->OnFrameDelete(this);
439 wxLogWindow::wxLogWindow(wxFrame
*pParent
,
440 const wxChar
*szTitle
,
444 m_bPassMessages
= bDoPass
;
446 m_pLogFrame
= new wxLogFrame(pParent
, this, szTitle
);
447 m_pOldLog
= wxLog::SetActiveTarget(this);
450 m_pLogFrame
->Show(TRUE
);
453 void wxLogWindow::Show(bool bShow
)
455 m_pLogFrame
->Show(bShow
);
458 void wxLogWindow::Flush()
460 if ( m_pOldLog
!= NULL
)
463 m_bHasMessages
= FALSE
;
466 void wxLogWindow::DoLog(wxLogLevel level
, const wxChar
*szString
, time_t t
)
468 // first let the previous logger show it
469 if ( m_pOldLog
!= NULL
&& m_bPassMessages
) {
470 // FIXME why can't we access protected wxLog method from here (we derive
471 // from wxLog)? gcc gives "DoLog is protected in this context", what
472 // does this mean? Anyhow, the cast is harmless and let's us do what
474 ((wxLogWindow
*)m_pOldLog
)->DoLog(level
, szString
, t
);
480 // by default, these messages are ignored by wxLog, so process
482 if ( !wxIsEmpty(szString
) )
485 str
<< _("Status: ") << szString
;
490 // don't put trace messages in the text window for 2 reasons:
491 // 1) there are too many of them
492 // 2) they may provoke other trace messages thus sending a program
493 // into an infinite loop
498 // and this will format it nicely and call our DoLogString()
499 wxLog::DoLog(level
, szString
, t
);
503 m_bHasMessages
= TRUE
;
506 void wxLogWindow::DoLogString(const wxChar
*szString
, time_t WXUNUSED(t
))
508 // put the text into our window
509 wxTextCtrl
*pText
= m_pLogFrame
->TextCtrl();
511 // remove selection (WriteText is in fact ReplaceSelection)
513 long nLen
= pText
->GetLastPosition();
514 pText
->SetSelection(nLen
, nLen
);
519 msg
<< szString
<< wxT('\n');
521 pText
->AppendText(msg
);
523 // TODO ensure that the line can be seen
526 wxFrame
*wxLogWindow::GetFrame() const
531 void wxLogWindow::OnFrameCreate(wxFrame
* WXUNUSED(frame
))
535 void wxLogWindow::OnFrameDelete(wxFrame
* WXUNUSED(frame
))
537 m_pLogFrame
= (wxLogFrame
*)NULL
;
540 wxLogWindow::~wxLogWindow()
544 // may be NULL if log frame already auto destroyed itself