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
This commit is contained in:
		| @@ -24,6 +24,13 @@ Classes: | |||||||
| @li wxLogInterposerTemp | @li wxLogInterposerTemp | ||||||
| @li wxStreamToTextRedirector | @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 | 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 | logging here has a broad sense, including all of the program output, not only | ||||||
| non-interactive messages. The logging facilities included in wxWidgets provide | 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 |     error message) will be given to the user together with "high level" message | ||||||
|     about data file writing error. |     about data file writing error. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @section overview_log_targets Log Targets | ||||||
|  |  | ||||||
| After having enumerated all the functions which are normally used to log the | 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 | messages, and why would you want to use them we now describe how all this | ||||||
| works. | 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 | normally. For this the wxLogChain, wxLogInterposer, and wxLogInterposerTemp can | ||||||
| be used. | 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. | ||||||
|  |  | ||||||
| */ | */ | ||||||
|  |  | ||||||
|   | |||||||
| @@ -63,9 +63,18 @@ protected: | |||||||
|  |  | ||||||
|     wxSUPPRESS_DOLOG_HIDE_WARNING() |     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 |     // empty everything | ||||||
|     void Clear(); |     void Clear(); | ||||||
|  |  | ||||||
|  |  | ||||||
|     wxArrayString m_aMessages;      // the log message texts |     wxArrayString m_aMessages;      // the log message texts | ||||||
|     wxArrayInt    m_aSeverity;      // one of wxLOG_XXX values |     wxArrayInt    m_aSeverity;      // one of wxLOG_XXX values | ||||||
|     wxArrayLong   m_aTimes;         // the time of each message |     wxArrayLong   m_aTimes;         // the time of each message | ||||||
| @@ -73,6 +82,19 @@ protected: | |||||||
|                   m_bWarnings,      // any warnings? |                   m_bWarnings,      // any warnings? | ||||||
|                   m_bHasMessages;   // any messages at all? |                   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 | #endif // wxUSE_LOGGUI | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ | |||||||
|  |  | ||||||
| #include "../sample.xpm" | #include "../sample.xpm" | ||||||
|  |  | ||||||
|  | #include "wx/apptrait.h" | ||||||
| #include "wx/datetime.h" | #include "wx/datetime.h" | ||||||
| #include "wx/image.h" | #include "wx/image.h" | ||||||
| #include "wx/bookctrl.h" | #include "wx/bookctrl.h" | ||||||
| @@ -83,10 +84,7 @@ | |||||||
|     #include "wx/fdrepdlg.h" |     #include "wx/fdrepdlg.h" | ||||||
| #endif // wxUSE_FINDREPLDLG | #endif // wxUSE_FINDREPLDLG | ||||||
|  |  | ||||||
| #if wxUSE_SPINCTRL |  | ||||||
| #include "wx/spinctrl.h" | #include "wx/spinctrl.h" | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #include "wx/propdlg.h" | #include "wx/propdlg.h" | ||||||
|  |  | ||||||
| #include "dialogs.h" | #include "dialogs.h" | ||||||
| @@ -2327,3 +2325,29 @@ void TestMessageBoxDialog::OnClose(wxCommandEvent& WXUNUSED(event)) | |||||||
| } | } | ||||||
|  |  | ||||||
| #endif // USE_SETTINGS_DIALOG | #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 | ||||||
|   | |||||||
| @@ -98,15 +98,31 @@ of MSW, MAC and OS2 | |||||||
|     #define USE_SETTINGS_DIALOG 0 |     #define USE_SETTINGS_DIALOG 0 | ||||||
| #endif | #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 | // Define a new application type | ||||||
| class MyApp: public wxApp | class MyApp: public wxApp | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     bool OnInit(); |     virtual bool OnInit(); | ||||||
|  |  | ||||||
|     wxFont       m_canvasFont; |     wxFont       m_canvasFont; | ||||||
|     wxColour     m_canvasTextColour; |     wxColour     m_canvasTextColour; | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  | #if wxUSE_LOG | ||||||
|  |     virtual wxAppTraits *CreateTraits() { return new MyAppTraits; } | ||||||
|  | #endif // wxUSE_LOG | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #if USE_MODAL_PRESENTATION | #if USE_MODAL_PRESENTATION | ||||||
|   | |||||||
| @@ -281,6 +281,74 @@ void wxLogGui::Clear() | |||||||
|     m_aTimes.Empty(); |     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() | void wxLogGui::Flush() | ||||||
| { | { | ||||||
|     if ( !m_bHasMessages ) |     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 |     // do it right now to block any new calls to Flush() while we're here | ||||||
|     m_bHasMessages = false; |     m_bHasMessages = false; | ||||||
|  |  | ||||||
|  |     // note that this must be done before examining m_aMessages as it may log | ||||||
|  |     // yet another message | ||||||
|     const unsigned repeatCount = LogLastRepeatIfNeeded(); |     const unsigned repeatCount = LogLastRepeatIfNeeded(); | ||||||
|  |  | ||||||
|     wxString appName = wxTheApp->GetAppDisplayName(); |     const size_t nMsgCount = m_aMessages.size(); | ||||||
|  |  | ||||||
|     long style; |     if ( repeatCount > 0 ) | ||||||
|     wxString titleFormat; |     { | ||||||
|     if ( m_bErrors ) { |         m_aMessages[nMsgCount - 1] << " (" << m_aMessages[nMsgCount - 2] << ")"; | ||||||
|         titleFormat = _("%s Error"); |  | ||||||
|         style = wxICON_STOP; |  | ||||||
|     } |  | ||||||
|     else if ( m_bWarnings ) { |  | ||||||
|         titleFormat = _("%s Warning"); |  | ||||||
|         style = wxICON_EXCLAMATION; |  | ||||||
|     } |  | ||||||
|     else { |  | ||||||
|         titleFormat = _("%s Information"); |  | ||||||
|         style = wxICON_INFORMATION; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     wxString title; |     const wxString title = GetTitle(); | ||||||
|     title.Printf(titleFormat, appName.c_str()); |     const int style = GetSeverityIcon(); | ||||||
|  |  | ||||||
|     size_t nMsgCount = m_aMessages.GetCount(); |  | ||||||
|  |  | ||||||
|     // avoid showing other log dialogs until we're done with the dialog we're |     // 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! |     // showing right now: nested modal dialogs make for really bad UI! | ||||||
|     Suspend(); |     Suspend(); | ||||||
|  |  | ||||||
|     wxString str; |  | ||||||
|     if ( nMsgCount == 1 ) |     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 |     else // more than one message | ||||||
|     { |     { | ||||||
| #if wxUSE_LOG_DIALOG |         wxArrayString messages; | ||||||
|  |         wxArrayInt severities; | ||||||
|  |         wxArrayLong times; | ||||||
|  |  | ||||||
|         if ( repeatCount > 0 ) |         messages.swap(m_aMessages); | ||||||
|         { |         severities.swap(m_aSeverity); | ||||||
|             m_aMessages[nMsgCount - 1] |         times.swap(m_aTimes); | ||||||
|                 << " (" << m_aMessages[nMsgCount - 2] << ")"; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         wxLogDialog dlg(NULL, |  | ||||||
|                         m_aMessages, m_aSeverity, m_aTimes, |  | ||||||
|                         title, style); |  | ||||||
|  |  | ||||||
|         // clear the message list before showing the dialog because while it's |  | ||||||
|         // shown some new messages may appear |  | ||||||
|         Clear(); |         Clear(); | ||||||
|  |  | ||||||
|         (void)dlg.ShowModal(); |         DoShowMultipleLogMessages(messages, severities, times, title, style); | ||||||
| #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(); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // allow flushing the logs again |     // allow flushing the logs again | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user