1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/logg.cpp
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 licence
11 /////////////////////////////////////////////////////////////////////////////
13 // ============================================================================
15 // ============================================================================
17 // ----------------------------------------------------------------------------
19 // ----------------------------------------------------------------------------
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
30 #include "wx/button.h"
35 #include "wx/filedlg.h"
36 #include "wx/msgdlg.h"
37 #include "wx/textctrl.h"
39 #include "wx/statbmp.h"
40 #include "wx/settings.h"
41 #include "wx/wxcrtvararg.h"
44 #if wxUSE_LOGGUI || wxUSE_LOGWINDOW
47 #include "wx/textfile.h"
48 #include "wx/statline.h"
49 #include "wx/artprov.h"
50 #include "wx/collpane.h"
51 #include "wx/arrstr.h"
54 #include "wx/thread.h"
55 #endif // wxUSE_THREADS
58 // for OutputDebugString()
59 #include "wx/msw/private.h"
68 #include "wx/listctrl.h"
69 #include "wx/imaglist.h"
71 #endif // wxUSE_LOG_DIALOG/!wxUSE_LOG_DIALOG
73 #if defined(__MWERKS__) && wxUSE_UNICODE
77 #include "wx/datetime.h"
79 // the suffix we add to the button to show that the dialog can be expanded
80 #define EXPAND_SUFFIX _T(" >>")
82 // ----------------------------------------------------------------------------
84 // ----------------------------------------------------------------------------
88 // this function is a wrapper around strftime(3)
89 // allows to exclude the usage of wxDateTime
90 static wxString
TimeStamp(const wxString
& format
, time_t t
)
95 if ( !wxStrftime(buf
, WXSIZEOF(buf
), format
, wxLocaltime_r(&t
, &tm
)) )
97 // buffer is too small?
98 wxFAIL_MSG(_T("strftime() failed"));
100 return wxString(buf
);
101 #else // !wxUSE_DATETIME
102 return wxEmptyString
;
103 #endif // wxUSE_DATETIME/!wxUSE_DATETIME
107 class wxLogDialog
: public wxDialog
110 wxLogDialog(wxWindow
*parent
,
111 const wxArrayString
& messages
,
112 const wxArrayInt
& severity
,
113 const wxArrayLong
& timess
,
114 const wxString
& caption
,
116 virtual ~wxLogDialog();
119 void OnOk(wxCommandEvent
& event
);
121 void OnSave(wxCommandEvent
& event
);
123 void OnListSelect(wxListEvent
& event
);
124 void OnListItemActivated(wxListEvent
& event
);
127 // create controls needed for the details display
128 void CreateDetailsControls(wxWindow
*);
130 // if necessary truncates the given string and adds an ellipsis
131 wxString
EllipsizeString(const wxString
&text
)
133 if (ms_maxLength
> 0 &&
134 text
.length() > ms_maxLength
)
137 ret
.Truncate(ms_maxLength
);
145 // the data for the listctrl
146 wxArrayString m_messages
;
147 wxArrayInt m_severity
;
150 // the controls which are not shown initially (but only when details
151 // button is pressed)
152 wxListCtrl
*m_listctrl
;
153 #ifndef __SMARTPHONE__
155 wxStaticLine
*m_statline
;
156 #endif // wxUSE_STATLINE
160 #endif // __SMARTPHONE__
162 // the translated "Details" string
163 static wxString ms_details
;
165 // the maximum length of the log message
166 static size_t ms_maxLength
;
168 DECLARE_EVENT_TABLE()
169 DECLARE_NO_COPY_CLASS(wxLogDialog
)
172 BEGIN_EVENT_TABLE(wxLogDialog
, wxDialog
)
173 EVT_BUTTON(wxID_OK
, wxLogDialog::OnOk
)
175 EVT_BUTTON(wxID_SAVE
, wxLogDialog::OnSave
)
177 EVT_LIST_ITEM_SELECTED(wxID_ANY
, wxLogDialog::OnListSelect
)
178 EVT_LIST_ITEM_ACTIVATED(wxID_ANY
, wxLogDialog::OnListItemActivated
)
181 #endif // wxUSE_LOG_DIALOG
183 // ----------------------------------------------------------------------------
185 // ----------------------------------------------------------------------------
187 #if wxUSE_FILE && wxUSE_FILEDLG
189 // pass an uninitialized file object, the function will ask the user for the
190 // filename and try to open it, returns true on success (file was opened),
191 // false if file couldn't be opened/created and -1 if the file selection
192 // dialog was cancelled
193 static int OpenLogFile(wxFile
& file
, wxString
*filename
= NULL
, wxWindow
*parent
= NULL
);
197 // ----------------------------------------------------------------------------
199 // ----------------------------------------------------------------------------
201 // we use a global variable to store the frame pointer for wxLogStatus - bad,
202 // but it's the easiest way
203 static wxFrame
*gs_pFrame
= NULL
; // FIXME MT-unsafe
205 // ============================================================================
207 // ============================================================================
209 // ----------------------------------------------------------------------------
211 // ----------------------------------------------------------------------------
213 // accepts an additional argument which tells to which frame the output should
215 void wxVLogStatus(wxFrame
*pFrame
, const wxString
& format
, va_list argptr
)
219 wxLog
*pLog
= wxLog::GetActiveTarget();
220 if ( pLog
!= NULL
) {
221 msg
.PrintfV(format
, argptr
);
223 wxASSERT( gs_pFrame
== NULL
); // should be reset!
226 wxLog::OnLog(wxLOG_Status
, msg
, 0);
228 wxLog::OnLog(wxLOG_Status
, msg
, time(NULL
));
230 gs_pFrame
= (wxFrame
*) NULL
;
234 #if !wxUSE_UTF8_LOCALE_ONLY
235 void wxDoLogStatusWchar(wxFrame
*pFrame
, const wxChar
*format
, ...)
238 va_start(argptr
, format
);
239 wxVLogStatus(pFrame
, format
, argptr
);
242 #endif // !wxUSE_UTF8_LOCALE_ONLY
244 #if wxUSE_UNICODE_UTF8
245 void wxDoLogStatusUtf8(wxFrame
*pFrame
, const char *format
, ...)
248 va_start(argptr
, format
);
249 wxVLogStatus(pFrame
, format
, argptr
);
252 #endif // wxUSE_UNICODE_UTF8
254 // ----------------------------------------------------------------------------
255 // wxLogGui implementation (FIXME MT-unsafe)
256 // ----------------------------------------------------------------------------
265 void wxLogGui::Clear()
269 m_bHasMessages
= false;
276 void wxLogGui::Flush()
278 if ( !m_bHasMessages
)
281 // do it right now to block any new calls to Flush() while we're here
282 m_bHasMessages
= false;
284 const unsigned repeatCount
= LogLastRepeatIfNeeded();
286 wxString appName
= wxTheApp
->GetAppDisplayName();
289 wxString titleFormat
;
291 titleFormat
= _("%s Error");
294 else if ( m_bWarnings
) {
295 titleFormat
= _("%s Warning");
296 style
= wxICON_EXCLAMATION
;
299 titleFormat
= _("%s Information");
300 style
= wxICON_INFORMATION
;
304 title
.Printf(titleFormat
, appName
.c_str());
306 size_t nMsgCount
= m_aMessages
.GetCount();
308 // avoid showing other log dialogs until we're done with the dialog we're
309 // showing right now: nested modal dialogs make for really bad UI!
313 if ( nMsgCount
== 1 )
315 str
= m_aMessages
[0];
317 else // more than one message
321 if ( repeatCount
> 0 )
323 m_aMessages
[nMsgCount
- 1]
324 << " (" << m_aMessages
[nMsgCount
- 2] << ")";
327 wxLogDialog
dlg(NULL
,
328 m_aMessages
, m_aSeverity
, m_aTimes
,
331 // clear the message list before showing the dialog because while it's
332 // shown some new messages may appear
335 (void)dlg
.ShowModal();
336 #else // !wxUSE_LOG_DIALOG
337 // concatenate all strings (but not too many to not overfill the msg box)
340 // start from the most recent message
341 for ( size_t n
= nMsgCount
; n
> 0; n
-- ) {
342 // for Windows strings longer than this value are wrapped (NT 4.0)
343 const size_t nMsgLineWidth
= 156;
345 nLines
+= (m_aMessages
[n
- 1].Len() + nMsgLineWidth
- 1) / nMsgLineWidth
;
347 if ( nLines
> 25 ) // don't put too many lines in message box
350 str
<< m_aMessages
[n
- 1] << wxT("\n");
352 #endif // wxUSE_LOG_DIALOG/!wxUSE_LOG_DIALOG
355 // this catches both cases of 1 message with wxUSE_LOG_DIALOG and any
356 // situation without it
359 wxMessageBox(str
, title
, wxOK
| style
);
361 // no undisplayed messages whatsoever
365 // allow flushing the logs again
369 // log all kinds of messages
370 void wxLogGui::DoLog(wxLogLevel level
, const wxString
& szString
, time_t t
)
377 m_aMessages
.Add(szString
);
378 m_aSeverity
.Add(wxLOG_Message
);
379 m_aTimes
.Add((long)t
);
380 m_bHasMessages
= true;
387 // find the top window and set it's status text if it has any
388 wxFrame
*pFrame
= gs_pFrame
;
389 if ( pFrame
== NULL
) {
390 wxWindow
*pWin
= wxTheApp
->GetTopWindow();
391 if ( pWin
!= NULL
&& pWin
->IsKindOf(CLASSINFO(wxFrame
)) ) {
392 pFrame
= (wxFrame
*)pWin
;
396 if ( pFrame
&& pFrame
->GetStatusBar() )
397 pFrame
->SetStatusText(szString
);
399 #endif // wxUSE_STATUSBAR
410 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
411 // don't prepend debug/trace here: it goes to the
412 // debug window anyhow
414 OutputDebugString(str
.wx_str());
416 // send them to stderr
417 wxFprintf(stderr
, wxT("[%s] %s\n"),
418 level
== wxLOG_Trace
? wxT("Trace")
424 #endif // __WXDEBUG__
428 case wxLOG_FatalError
:
429 // show this one immediately
430 wxMessageBox(szString
, _("Fatal error"), wxICON_HAND
);
436 #if !wxUSE_LOG_DIALOG
437 // discard earlier informational messages if this is the 1st
438 // error because they might not make sense any more and showing
439 // them in a message box might be confusing
443 #endif // wxUSE_LOG_DIALOG
450 // for the warning we don't discard the info messages
454 m_aMessages
.Add(szString
);
455 m_aSeverity
.Add((int)level
);
456 m_aTimes
.Add((long)t
);
457 m_bHasMessages
= true;
462 #endif // wxUSE_LOGGUI
464 // ----------------------------------------------------------------------------
465 // wxLogWindow and wxLogFrame implementation
466 // ----------------------------------------------------------------------------
472 class wxLogFrame
: public wxFrame
476 wxLogFrame(wxWindow
*pParent
, wxLogWindow
*log
, const wxString
& szTitle
);
477 virtual ~wxLogFrame();
480 void OnClose(wxCommandEvent
& event
);
481 void OnCloseWindow(wxCloseEvent
& event
);
483 void OnSave (wxCommandEvent
& event
);
485 void OnClear(wxCommandEvent
& event
);
487 // this function is safe to call from any thread (notice that it should be
488 // also called from the main thread to ensure that the messages logged from
489 // it appear in correct order with the messages from the other threads)
490 void AddLogMessage(const wxString
& message
);
492 // actually append the messages logged from secondary threads to the text
493 // control during idle time in the main thread
494 virtual void OnInternalIdle();
497 // use standard ids for our commands!
500 Menu_Close
= wxID_CLOSE
,
501 Menu_Save
= wxID_SAVE
,
502 Menu_Clear
= wxID_CLEAR
505 // common part of OnClose() and OnCloseWindow()
508 // do show the message in the text control
509 void DoShowLogMessage(const wxString
& message
)
511 m_pTextCtrl
->AppendText(message
);
514 wxTextCtrl
*m_pTextCtrl
;
517 // queue of messages logged from other threads which need to be displayed
518 wxArrayString m_pendingMessages
;
521 // critical section to protect access to m_pendingMessages
522 wxCriticalSection m_critSection
;
523 #endif // wxUSE_THREADS
526 DECLARE_EVENT_TABLE()
527 DECLARE_NO_COPY_CLASS(wxLogFrame
)
530 BEGIN_EVENT_TABLE(wxLogFrame
, wxFrame
)
531 // wxLogWindow menu events
532 EVT_MENU(Menu_Close
, wxLogFrame::OnClose
)
534 EVT_MENU(Menu_Save
, wxLogFrame::OnSave
)
536 EVT_MENU(Menu_Clear
, wxLogFrame::OnClear
)
538 EVT_CLOSE(wxLogFrame::OnCloseWindow
)
541 wxLogFrame::wxLogFrame(wxWindow
*pParent
, wxLogWindow
*log
, const wxString
& szTitle
)
542 : wxFrame(pParent
, wxID_ANY
, szTitle
)
546 m_pTextCtrl
= new wxTextCtrl(this, wxID_ANY
, wxEmptyString
, wxDefaultPosition
,
550 // needed for Win32 to avoid 65Kb limit but it doesn't work well
551 // when using RichEdit 2.0 which we always do in the Unicode build
554 #endif // !wxUSE_UNICODE
559 wxMenuBar
*pMenuBar
= new wxMenuBar
;
560 wxMenu
*pMenu
= new wxMenu
;
562 pMenu
->Append(Menu_Save
, _("&Save..."), _("Save log contents to file"));
564 pMenu
->Append(Menu_Clear
, _("C&lear"), _("Clear the log contents"));
565 pMenu
->AppendSeparator();
566 pMenu
->Append(Menu_Close
, _("&Close"), _("Close this window"));
567 pMenuBar
->Append(pMenu
, _("&Log"));
568 SetMenuBar(pMenuBar
);
569 #endif // wxUSE_MENUS
572 // status bar for menu prompts
574 #endif // wxUSE_STATUSBAR
576 m_log
->OnFrameCreate(this);
579 void wxLogFrame::DoClose()
581 if ( m_log
->OnFrameClose(this) )
583 // instead of closing just hide the window to be able to Show() it
589 void wxLogFrame::OnClose(wxCommandEvent
& WXUNUSED(event
))
594 void wxLogFrame::OnCloseWindow(wxCloseEvent
& WXUNUSED(event
))
600 void wxLogFrame::OnSave(wxCommandEvent
& WXUNUSED(event
))
605 int rc
= OpenLogFile(file
, &filename
, this);
614 // retrieve text and save it
615 // -------------------------
616 int nLines
= m_pTextCtrl
->GetNumberOfLines();
617 for ( int nLine
= 0; bOk
&& nLine
< nLines
; nLine
++ ) {
618 bOk
= file
.Write(m_pTextCtrl
->GetLineText(nLine
) +
619 wxTextFile::GetEOL());
626 wxLogError(_("Can't save log contents to file."));
629 wxLogStatus((wxFrame
*)this, _("Log saved to the file '%s'."), filename
.c_str());
635 void wxLogFrame::OnClear(wxCommandEvent
& WXUNUSED(event
))
637 m_pTextCtrl
->Clear();
640 void wxLogFrame::OnInternalIdle()
643 wxCRIT_SECT_LOCKER(locker
, m_critSection
);
645 const size_t count
= m_pendingMessages
.size();
646 for ( size_t n
= 0; n
< count
; n
++ )
648 DoShowLogMessage(m_pendingMessages
[n
]);
651 m_pendingMessages
.clear();
652 } // release m_critSection
654 wxFrame::OnInternalIdle();
657 void wxLogFrame::AddLogMessage(const wxString
& message
)
659 wxCRIT_SECT_LOCKER(locker
, m_critSection
);
662 if ( !wxThread::IsMain() || !m_pendingMessages
.empty() )
664 // message needs to be queued for later showing
665 m_pendingMessages
.Add(message
);
669 else // we are the main thread and no messages are queued, so we can
670 // log the message directly
671 #endif // wxUSE_THREADS
673 DoShowLogMessage(message
);
677 wxLogFrame::~wxLogFrame()
679 m_log
->OnFrameDelete(this);
685 wxLogWindow::wxLogWindow(wxWindow
*pParent
,
686 const wxString
& szTitle
,
690 PassMessages(bDoPass
);
692 m_pLogFrame
= new wxLogFrame(pParent
, this, szTitle
);
698 void wxLogWindow::Show(bool bShow
)
700 m_pLogFrame
->Show(bShow
);
703 void wxLogWindow::DoLog(wxLogLevel level
, const wxString
& szString
, time_t t
)
705 // first let the previous logger show it
706 wxLogPassThrough::DoLog(level
, szString
, t
);
711 // by default, these messages are ignored by wxLog, so process
713 if ( !szString
.empty() )
716 str
<< _("Status: ") << szString
;
721 // don't put trace messages in the text window for 2 reasons:
722 // 1) there are too many of them
723 // 2) they may provoke other trace messages thus sending a program
724 // into an infinite loop
729 // and this will format it nicely and call our DoLogString()
730 wxLog::DoLog(level
, szString
, t
);
735 void wxLogWindow::DoLogString(const wxString
& szString
, time_t WXUNUSED(t
))
740 msg
<< szString
<< wxT('\n');
742 m_pLogFrame
->AddLogMessage(msg
);
745 wxFrame
*wxLogWindow::GetFrame() const
750 void wxLogWindow::OnFrameCreate(wxFrame
* WXUNUSED(frame
))
754 bool wxLogWindow::OnFrameClose(wxFrame
* WXUNUSED(frame
))
760 void wxLogWindow::OnFrameDelete(wxFrame
* WXUNUSED(frame
))
762 m_pLogFrame
= (wxLogFrame
*)NULL
;
765 wxLogWindow::~wxLogWindow()
767 // may be NULL if log frame already auto destroyed itself
771 #endif // wxUSE_LOGWINDOW
773 // ----------------------------------------------------------------------------
775 // ----------------------------------------------------------------------------
779 #ifndef __SMARTPHONE__
780 static const size_t MARGIN
= 10;
782 static const size_t MARGIN
= 0;
785 wxString
wxLogDialog::ms_details
;
786 size_t wxLogDialog::ms_maxLength
= 0;
788 wxLogDialog::wxLogDialog(wxWindow
*parent
,
789 const wxArrayString
& messages
,
790 const wxArrayInt
& severity
,
791 const wxArrayLong
& times
,
792 const wxString
& caption
,
794 : wxDialog(parent
, wxID_ANY
, caption
,
795 wxDefaultPosition
, wxDefaultSize
,
796 wxDEFAULT_DIALOG_STYLE
| wxRESIZE_BORDER
)
798 // init the static variables:
800 if ( ms_details
.empty() )
802 // ensure that we won't loop here if wxGetTranslation()
803 // happens to pop up a Log message while translating this :-)
804 ms_details
= wxTRANSLATE("&Details");
805 ms_details
= wxGetTranslation(ms_details
);
806 #ifdef __SMARTPHONE__
807 ms_details
= wxStripMenuCodes(ms_details
);
811 if ( ms_maxLength
== 0 )
813 ms_maxLength
= (2 * wxGetDisplaySize().x
/3) / GetCharWidth();
816 size_t count
= messages
.GetCount();
817 m_messages
.Alloc(count
);
818 m_severity
.Alloc(count
);
819 m_times
.Alloc(count
);
821 for ( size_t n
= 0; n
< count
; n
++ )
823 m_messages
.Add(messages
[n
]);
824 m_severity
.Add(severity
[n
]);
825 m_times
.Add(times
[n
]);
828 m_listctrl
= (wxListCtrl
*)NULL
;
830 #ifndef __SMARTPHONE__
833 m_statline
= (wxStaticLine
*)NULL
;
834 #endif // wxUSE_STATLINE
837 m_btnSave
= (wxButton
*)NULL
;
840 #endif // __SMARTPHONE__
842 bool isPda
= (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA
);
844 // create the controls which are always shown and layout them: we use
845 // sizers even though our window is not resizeable to calculate the size of
846 // the dialog properly
847 wxBoxSizer
*sizerTop
= new wxBoxSizer(wxVERTICAL
);
848 wxBoxSizer
*sizerAll
= new wxBoxSizer(isPda
? wxVERTICAL
: wxHORIZONTAL
);
852 wxStaticBitmap
*icon
= new wxStaticBitmap
856 wxArtProvider::GetMessageBoxIcon(style
)
858 sizerAll
->Add(icon
, 0, wxALIGN_CENTRE_VERTICAL
);
861 // create the text sizer with a minimal size so that we are sure it won't be too small
862 wxString message
= EllipsizeString(messages
.Last());
863 wxSizer
*szText
= CreateTextSizer(message
);
864 szText
->SetMinSize(wxMin(300, wxGetDisplaySize().x
/ 3), -1);
866 sizerAll
->Add(szText
, 1,
867 wxALIGN_CENTRE_VERTICAL
| wxLEFT
| wxRIGHT
, MARGIN
);
869 wxButton
*btnOk
= new wxButton(this, wxID_OK
);
870 sizerAll
->Add(btnOk
, 0, isPda
? wxCENTRE
: wxCENTRE
|wxBOTTOM
, MARGIN
/2);
872 sizerTop
->Add(sizerAll
, 0, wxALL
| wxEXPAND
, MARGIN
);
875 // add the details pane
877 #ifndef __SMARTPHONE__
878 wxCollapsiblePane
*collpane
= new wxCollapsiblePane(this, wxID_ANY
, ms_details
);
879 sizerTop
->Add(collpane
, 1, wxGROW
|wxALL
, MARGIN
);
881 wxWindow
*win
= collpane
->GetPane();
882 wxSizer
*paneSz
= new wxBoxSizer(wxVERTICAL
);
884 CreateDetailsControls(win
);
886 paneSz
->Add(m_listctrl
, 1, wxEXPAND
| wxTOP
, MARGIN
);
888 #if wxUSE_FILE && !defined(__SMARTPHONE__)
889 paneSz
->Add(m_btnSave
, 0, wxALIGN_RIGHT
| wxTOP
, MARGIN
);
892 win
->SetSizer(paneSz
);
893 paneSz
->SetSizeHints(win
);
894 #else // __SMARTPHONE__
895 SetLeftMenu(wxID_OK
);
896 SetRightMenu(wxID_MORE
, ms_details
+ EXPAND_SUFFIX
);
897 #endif // __SMARTPHONE__/!__SMARTPHONE__
899 SetSizerAndFit(sizerTop
);
905 // Move up the screen so that when we expand the dialog,
906 // there's enough space.
907 Move(wxPoint(GetPosition().x
, GetPosition().y
/ 2));
911 void wxLogDialog::CreateDetailsControls(wxWindow
*parent
)
913 #ifndef __SMARTPHONE__
914 // create the save button and separator line if possible
916 m_btnSave
= new wxButton(parent
, wxID_SAVE
);
919 #endif // __SMARTPHONE__
921 // create the list ctrl now
922 m_listctrl
= new wxListCtrl(parent
, wxID_ANY
,
923 wxDefaultPosition
, wxDefaultSize
,
929 // This makes a big aesthetic difference on WinCE but I
930 // don't want to risk problems on other platforms
934 // no need to translate these strings as they're not shown to the
935 // user anyhow (we use wxLC_NO_HEADER style)
936 m_listctrl
->InsertColumn(0, _T("Message"));
937 m_listctrl
->InsertColumn(1, _T("Time"));
939 // prepare the imagelist
940 static const int ICON_SIZE
= 16;
941 wxImageList
*imageList
= new wxImageList(ICON_SIZE
, ICON_SIZE
);
943 // order should be the same as in the switch below!
944 static const wxChar
* icons
[] =
951 bool loadedIcons
= true;
953 for ( size_t icon
= 0; icon
< WXSIZEOF(icons
); icon
++ )
955 wxBitmap bmp
= wxArtProvider::GetBitmap(icons
[icon
], wxART_MESSAGE_BOX
,
956 wxSize(ICON_SIZE
, ICON_SIZE
));
958 // This may very well fail if there are insufficient colours available.
959 // Degrade gracefully.
970 m_listctrl
->SetImageList(imageList
, wxIMAGE_LIST_SMALL
);
973 wxString fmt
= wxLog::GetTimestamp();
980 size_t count
= m_messages
.GetCount();
981 for ( size_t n
= 0; n
< count
; n
++ )
987 switch ( m_severity
[n
] )
1001 else // failed to load images
1006 wxString msg
= m_messages
[n
];
1007 msg
.Replace(wxT("\n"), wxT(" "));
1008 msg
= EllipsizeString(msg
);
1010 m_listctrl
->InsertItem(n
, msg
, image
);
1011 m_listctrl
->SetItem(n
, 1, TimeStamp(fmt
, (time_t)m_times
[n
]));
1014 // let the columns size themselves
1015 m_listctrl
->SetColumnWidth(0, wxLIST_AUTOSIZE
);
1016 m_listctrl
->SetColumnWidth(1, wxLIST_AUTOSIZE
);
1018 // calculate an approximately nice height for the listctrl
1019 int height
= GetCharHeight()*(count
+ 4);
1021 // but check that the dialog won't fall fown from the screen
1023 // we use GetMinHeight() to get the height of the dialog part without the
1024 // details and we consider that the "Save" button below and the separator
1025 // line (and the margins around it) take about as much, hence double it
1026 int heightMax
= wxGetDisplaySize().y
- GetPosition().y
- 2*GetMinHeight();
1028 // we should leave a margin
1032 m_listctrl
->SetSize(wxDefaultCoord
, wxMin(height
, heightMax
));
1035 void wxLogDialog::OnListSelect(wxListEvent
& event
)
1037 // we can't just disable the control because this looks ugly under Windows
1038 // (wrong bg colour, no scrolling...), but we still want to disable
1039 // selecting items - it makes no sense here
1040 m_listctrl
->SetItemState(event
.GetIndex(), 0, wxLIST_STATE_SELECTED
);
1043 void wxLogDialog::OnListItemActivated(wxListEvent
& event
)
1045 // show the activated item in a message box
1046 // This allow the user to correctly display the logs which are longer
1047 // than the listctrl and thus gets truncated or those which contains
1051 // wxString str = m_listctrl->GetItemText(event.GetIndex());
1052 // as there's a 260 chars limit on the items inside a wxListCtrl in wxMSW.
1053 wxString str
= m_messages
[event
.GetIndex()];
1055 // wxMessageBox will nicely handle the '\n' in the string (if any)
1056 // and supports long strings
1057 wxMessageBox(str
, wxT("Log message"), wxOK
, this);
1060 void wxLogDialog::OnOk(wxCommandEvent
& WXUNUSED(event
))
1067 void wxLogDialog::OnSave(wxCommandEvent
& WXUNUSED(event
))
1071 int rc
= OpenLogFile(file
, NULL
, this);
1080 wxString fmt
= wxLog::GetTimestamp();
1087 size_t count
= m_messages
.GetCount();
1088 for ( size_t n
= 0; ok
&& (n
< count
); n
++ )
1091 line
<< TimeStamp(fmt
, (time_t)m_times
[n
])
1094 << wxTextFile::GetEOL();
1096 ok
= file
.Write(line
);
1103 wxLogError(_("Can't save log contents to file."));
1104 #endif // wxUSE_FILEDLG
1107 #endif // wxUSE_FILE
1109 wxLogDialog::~wxLogDialog()
1113 delete m_listctrl
->GetImageList(wxIMAGE_LIST_SMALL
);
1117 #endif // wxUSE_LOG_DIALOG
1119 #if wxUSE_FILE && wxUSE_FILEDLG
1121 // pass an uninitialized file object, the function will ask the user for the
1122 // filename and try to open it, returns true on success (file was opened),
1123 // false if file couldn't be opened/created and -1 if the file selection
1124 // dialog was cancelled
1125 static int OpenLogFile(wxFile
& file
, wxString
*pFilename
, wxWindow
*parent
)
1127 // get the file name
1128 // -----------------
1129 wxString filename
= wxSaveFileSelector(wxT("log"), wxT("txt"), wxT("log.txt"), parent
);
1138 if ( wxFile::Exists(filename
) ) {
1139 bool bAppend
= false;
1141 strMsg
.Printf(_("Append log to file '%s' (choosing [No] will overwrite it)?"),
1143 switch ( wxMessageBox(strMsg
, _("Question"),
1144 wxICON_QUESTION
| wxYES_NO
| wxCANCEL
) ) {
1157 wxFAIL_MSG(_("invalid message box return value"));
1161 bOk
= file
.Open(filename
, wxFile::write_append
);
1164 bOk
= file
.Create(filename
, true /* overwrite */);
1168 bOk
= file
.Create(filename
);
1172 *pFilename
= filename
;
1177 #endif // wxUSE_FILE
1179 #endif // !(wxUSE_LOGGUI || wxUSE_LOGWINDOW)
1181 #if wxUSE_LOG && wxUSE_TEXTCTRL
1183 // ----------------------------------------------------------------------------
1184 // wxLogTextCtrl implementation
1185 // ----------------------------------------------------------------------------
1187 wxLogTextCtrl::wxLogTextCtrl(wxTextCtrl
*pTextCtrl
)
1189 m_pTextCtrl
= pTextCtrl
;
1192 void wxLogTextCtrl::DoLogString(const wxString
& szString
, time_t WXUNUSED(t
))
1197 msg
<< szString
<< wxT('\n');
1198 m_pTextCtrl
->AppendText(msg
);
1201 #endif // wxUSE_LOG && wxUSE_TEXTCTRL