From: Vadim Zeitlin Date: Thu, 11 Sep 2008 13:58:54 +0000 (+0000) Subject: made wxLogGui more flexible and documented it and added example of customizing it... X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/9ad2fe62d167bd7764b3d7eade75baa84a2a00e4?ds=sidebyside made wxLogGui more flexible and documented it and added example of customizing it to the dialogs sample git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@55552 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/docs/doxygen/overviews/log.h b/docs/doxygen/overviews/log.h index c7c4a69caa..048f291d39 100644 --- a/docs/doxygen/overviews/log.h +++ b/docs/doxygen/overviews/log.h @@ -24,6 +24,13 @@ Classes: @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 @@ -108,6 +115,9 @@ classes are. Some of advantages in using wxWidgets log functions are: 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. @@ -170,5 +180,27 @@ messages somewhere else (for example, to a log file) but also process them as 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. + */ diff --git a/include/wx/generic/logg.h b/include/wx/generic/logg.h index 0227317323..269c65921a 100644 --- a/include/wx/generic/logg.h +++ b/include/wx/generic/logg.h @@ -63,9 +63,18 @@ protected: 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 @@ -73,6 +82,19 @@ protected: 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 diff --git a/samples/dialogs/dialogs.cpp b/samples/dialogs/dialogs.cpp index 7549454956..d0e24dea09 100644 --- a/samples/dialogs/dialogs.cpp +++ b/samples/dialogs/dialogs.cpp @@ -22,6 +22,7 @@ #include "../sample.xpm" +#include "wx/apptrait.h" #include "wx/datetime.h" #include "wx/image.h" #include "wx/bookctrl.h" @@ -83,10 +84,7 @@ #include "wx/fdrepdlg.h" #endif // wxUSE_FINDREPLDLG -#if wxUSE_SPINCTRL #include "wx/spinctrl.h" -#endif - #include "wx/propdlg.h" #include "dialogs.h" @@ -2327,3 +2325,29 @@ void TestMessageBoxDialog::OnClose(wxCommandEvent& WXUNUSED(event)) } #endif // USE_SETTINGS_DIALOG + +#if wxUSE_LOG + +// ---------------------------------------------------------------------------- +// custom log target +// ---------------------------------------------------------------------------- + +class MyLogGui : public wxLogGui +{ +private: + virtual void DoShowSingleLogMessage(const wxString& message, + const wxString& title, + int style) + { + wxMessageDialog dlg(NULL, message, title, wxOK | style); + dlg.SetExtendedMessage("Note that this is a custom log dialog."); + dlg.ShowModal(); + } +}; + +wxLog *MyAppTraits::CreateLogTarget() +{ + return new MyLogGui; +} + +#endif // wxUSE_LOG diff --git a/samples/dialogs/dialogs.h b/samples/dialogs/dialogs.h index 7be46aaf50..ad8956acfb 100644 --- a/samples/dialogs/dialogs.h +++ b/samples/dialogs/dialogs.h @@ -98,15 +98,31 @@ of MSW, MAC and OS2 #define USE_SETTINGS_DIALOG 0 #endif +#if wxUSE_LOG + +// Custom application traits class which we use to override the default log +// target creation +class MyAppTraits : public wxGUIAppTraits +{ +public: + virtual wxLog *CreateLogTarget(); +}; + +#endif // wxUSE_LOG // Define a new application type class MyApp: public wxApp { public: - bool OnInit(); + virtual bool OnInit(); wxFont m_canvasFont; wxColour m_canvasTextColour; + +protected: +#if wxUSE_LOG + virtual wxAppTraits *CreateTraits() { return new MyAppTraits; } +#endif // wxUSE_LOG }; #if USE_MODAL_PRESENTATION diff --git a/src/generic/logg.cpp b/src/generic/logg.cpp index f0c18bb999..80aab72d47 100644 --- a/src/generic/logg.cpp +++ b/src/generic/logg.cpp @@ -281,6 +281,74 @@ void wxLogGui::Clear() 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 ) @@ -289,85 +357,45 @@ void wxLogGui::Flush() // 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