@li wxLogInterposerTemp
@li wxStreamToTextRedirector
+@li @ref overview_log_introduction
+@li @ref overview_log_targets
+@li @ref overview_log_customize
+
+
+@section overview_log_introduction Introduction
+
This is a general overview of logging classes provided by wxWidgets. The word
logging here has a broad sense, including all of the program output, not only
non-interactive messages. The logging facilities included in wxWidgets provide
error message) will be given to the user together with "high level" message
about data file writing error.
+
+@section overview_log_targets Log Targets
+
After having enumerated all the functions which are normally used to log the
messages, and why would you want to use them we now describe how all this
works.
normally. For this the wxLogChain, wxLogInterposer, and wxLogInterposerTemp can
be used.
+
+@section overview_log_customize Logging Customization
+
+To completely change the logging behaviour you may define a custom log target.
+For example, you could define a class inheriting from wxLog which shows all the
+log messages in some part of your main application window reserved for the
+message output without interrupting the user work flow with modal message
+boxes.
+
+To use your custom log target you may either call wxLog::SetActiveTarget() with
+your custom log object or create a wxAppTraits-derived class and override
+CreateLogTarget() virtual method in it and also override wxApp::CreateTraits()
+to return an instance of your custom traits object. Notice that in the latter
+case you should be prepared for logging messages early during the program
+startup and also during program shutdown so you shouldn't rely on existence of
+the main application window, for example. You can however safely assume that
+GUI is (already/still) available when your log target as used as wxWidgets
+automatically switches to using wxLogStderr if it isn't.
+
+The dialog sample illustrates this approach by defining a custom log target
+customizing the dialog used by wxLogGui for the single messages.
+
*/
wxSUPPRESS_DOLOG_HIDE_WARNING()
+ // return the title to be used for the log dialog, depending on m_bErrors
+ // and m_bWarnings values
+ wxString GetTitle() const;
+
+ // return the icon (one of wxICON_XXX constants) to be used for the dialog
+ // depending on m_bErrors/m_bWarnings
+ int GetSeverityIcon() const;
+
// empty everything
void Clear();
+
wxArrayString m_aMessages; // the log message texts
wxArrayInt m_aSeverity; // one of wxLOG_XXX values
wxArrayLong m_aTimes; // the time of each message
m_bWarnings, // any warnings?
m_bHasMessages; // any messages at all?
+private:
+ // this method is called to show a single log message, it uses
+ // wxMessageBox() by default
+ virtual void DoShowSingleLogMessage(const wxString& message,
+ const wxString& title,
+ int style);
+
+ // this method is called to show multiple log messages, it uses wxLogDialog
+ virtual void DoShowMultipleLogMessages(const wxArrayString& messages,
+ const wxArrayInt& severities,
+ const wxArrayLong& times,
+ const wxString& title,
+ int style);
};
#endif // wxUSE_LOGGUI
m_aTimes.Empty();
}
+int wxLogGui::GetSeverityIcon() const
+{
+ return m_bErrors ? wxICON_STOP
+ : m_bWarnings ? wxICON_EXCLAMATION
+ : wxICON_INFORMATION;
+}
+
+wxString wxLogGui::GetTitle() const
+{
+ wxString titleFormat;
+ switch ( GetSeverityIcon() )
+ {
+ case wxICON_STOP:
+ titleFormat = _("%s Error");
+ break;
+
+ case wxICON_EXCLAMATION:
+ titleFormat = _("%s Warning");
+ break;
+
+ default:
+ wxFAIL_MSG( "unexpected icon severity" );
+ // fall through
+
+ case wxICON_INFORMATION:
+ titleFormat = _("%s Information");
+ }
+
+ return wxString::Format(titleFormat, wxTheApp->GetAppDisplayName());
+}
+
+void
+wxLogGui::DoShowSingleLogMessage(const wxString& message,
+ const wxString& title,
+ int style)
+{
+ wxMessageBox(message, title, wxOK | style);
+}
+
+void
+wxLogGui::DoShowMultipleLogMessages(const wxArrayString& messages,
+ const wxArrayInt& severities,
+ const wxArrayLong& times,
+ const wxString& title,
+ int style)
+{
+#if wxUSE_LOG_DIALOG
+ wxLogDialog dlg(NULL,
+ messages, severities, times,
+ title, style);
+
+ // clear the message list before showing the dialog because while it's
+ // shown some new messages may appear
+ Clear();
+
+ (void)dlg.ShowModal();
+#else // !wxUSE_LOG_DIALOG
+ // start from the most recent message
+ wxString message;
+ str.reserve(nMsgCount*100);
+ for ( size_t n = nMsgCount; n > 0; n-- ) {
+ message << m_aMessages[n - 1] << wxT("\n");
+ }
+
+ DoShowSingleLogMessage(message, title, style);
+#endif // wxUSE_LOG_DIALOG/!wxUSE_LOG_DIALOG
+}
+
void wxLogGui::Flush()
{
if ( !m_bHasMessages )
// do it right now to block any new calls to Flush() while we're here
m_bHasMessages = false;
+ // note that this must be done before examining m_aMessages as it may log
+ // yet another message
const unsigned repeatCount = LogLastRepeatIfNeeded();
- wxString appName = wxTheApp->GetAppDisplayName();
+ const size_t nMsgCount = m_aMessages.size();
- long style;
- wxString titleFormat;
- if ( m_bErrors ) {
- titleFormat = _("%s Error");
- style = wxICON_STOP;
- }
- else if ( m_bWarnings ) {
- titleFormat = _("%s Warning");
- style = wxICON_EXCLAMATION;
- }
- else {
- titleFormat = _("%s Information");
- style = wxICON_INFORMATION;
+ if ( repeatCount > 0 )
+ {
+ m_aMessages[nMsgCount - 1] << " (" << m_aMessages[nMsgCount - 2] << ")";
}
- wxString title;
- title.Printf(titleFormat, appName.c_str());
-
- size_t nMsgCount = m_aMessages.GetCount();
+ const wxString title = GetTitle();
+ const int style = GetSeverityIcon();
// avoid showing other log dialogs until we're done with the dialog we're
// showing right now: nested modal dialogs make for really bad UI!
Suspend();
- wxString str;
if ( nMsgCount == 1 )
{
- str = m_aMessages[0];
+ // make a copy before calling Clear()
+ const wxString message(m_aMessages[0]);
+ Clear();
+
+ DoShowSingleLogMessage(message, title, style);
}
else // more than one message
{
-#if wxUSE_LOG_DIALOG
-
- if ( repeatCount > 0 )
- {
- m_aMessages[nMsgCount - 1]
- << " (" << m_aMessages[nMsgCount - 2] << ")";
- }
+ wxArrayString messages;
+ wxArrayInt severities;
+ wxArrayLong times;
- wxLogDialog dlg(NULL,
- m_aMessages, m_aSeverity, m_aTimes,
- title, style);
+ messages.swap(m_aMessages);
+ severities.swap(m_aSeverity);
+ times.swap(m_aTimes);
- // clear the message list before showing the dialog because while it's
- // shown some new messages may appear
Clear();
- (void)dlg.ShowModal();
-#else // !wxUSE_LOG_DIALOG
- // concatenate all strings (but not too many to not overfill the msg box)
- size_t nLines = 0;
-
- // start from the most recent message
- for ( size_t n = nMsgCount; n > 0; n-- ) {
- // for Windows strings longer than this value are wrapped (NT 4.0)
- const size_t nMsgLineWidth = 156;
-
- nLines += (m_aMessages[n - 1].Len() + nMsgLineWidth - 1) / nMsgLineWidth;
-
- if ( nLines > 25 ) // don't put too many lines in message box
- break;
-
- str << m_aMessages[n - 1] << wxT("\n");
- }
-#endif // wxUSE_LOG_DIALOG/!wxUSE_LOG_DIALOG
- }
-
- // this catches both cases of 1 message with wxUSE_LOG_DIALOG and any
- // situation without it
- if ( !str.empty() )
- {
- wxMessageBox(str, title, wxOK | style);
-
- // no undisplayed messages whatsoever
- Clear();
+ DoShowMultipleLogMessages(messages, severities, times, title, style);
}
// allow flushing the logs again