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 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. | ||||
|  | ||||
| */ | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -281,59 +281,55 @@ void wxLogGui::Clear() | ||||
|     m_aTimes.Empty(); | ||||
| } | ||||
|  | ||||
| void wxLogGui::Flush() | ||||
| int wxLogGui::GetSeverityIcon() const | ||||
| { | ||||
|     if ( !m_bHasMessages ) | ||||
|         return; | ||||
|     return m_bErrors ? wxICON_STOP | ||||
|                      : m_bWarnings ? wxICON_EXCLAMATION | ||||
|                                    : wxICON_INFORMATION; | ||||
| } | ||||
|  | ||||
|     // do it right now to block any new calls to Flush() while we're here | ||||
|     m_bHasMessages = false; | ||||
|  | ||||
|     const unsigned repeatCount = LogLastRepeatIfNeeded(); | ||||
|  | ||||
|     wxString appName = wxTheApp->GetAppDisplayName(); | ||||
|  | ||||
|     long style; | ||||
| wxString wxLogGui::GetTitle() const | ||||
| { | ||||
|     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; | ||||
|     } | ||||
|  | ||||
|     wxString title; | ||||
|     title.Printf(titleFormat, appName.c_str()); | ||||
|  | ||||
|     size_t nMsgCount = m_aMessages.GetCount(); | ||||
|  | ||||
|     // 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 ) | ||||
|     switch ( GetSeverityIcon() ) | ||||
|     { | ||||
|         str = m_aMessages[0]; | ||||
|         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"); | ||||
|     } | ||||
|     else // more than one message | ||||
|  | ||||
|     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 | ||||
|  | ||||
|         if ( repeatCount > 0 ) | ||||
|         { | ||||
|             m_aMessages[nMsgCount - 1] | ||||
|                 << " (" << m_aMessages[nMsgCount - 2] << ")"; | ||||
|         } | ||||
|  | ||||
|     wxLogDialog dlg(NULL, | ||||
|                         m_aMessages, m_aSeverity, m_aTimes, | ||||
|                     messages, severities, times, | ||||
|                     title, style); | ||||
|  | ||||
|     // clear the message list before showing the dialog because while it's | ||||
| @@ -342,32 +338,64 @@ void wxLogGui::Flush() | ||||
|  | ||||
|     (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 | ||||
|     wxString message; | ||||
|     str.reserve(nMsgCount*100); | ||||
|     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"); | ||||
|         message << m_aMessages[n - 1] << wxT("\n"); | ||||
|     } | ||||
|  | ||||
|     DoShowSingleLogMessage(message, title, style); | ||||
| #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() ) | ||||
| void wxLogGui::Flush() | ||||
| { | ||||
|         wxMessageBox(str, title, wxOK | style); | ||||
|     if ( !m_bHasMessages ) | ||||
|         return; | ||||
|  | ||||
|         // no undisplayed messages whatsoever | ||||
|     // 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(); | ||||
|  | ||||
|     const size_t nMsgCount = m_aMessages.size(); | ||||
|  | ||||
|     if ( repeatCount > 0 ) | ||||
|     { | ||||
|         m_aMessages[nMsgCount - 1] << " (" << m_aMessages[nMsgCount - 2] << ")"; | ||||
|     } | ||||
|  | ||||
|     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(); | ||||
|  | ||||
|     if ( nMsgCount == 1 ) | ||||
|     { | ||||
|         // make a copy before calling Clear() | ||||
|         const wxString message(m_aMessages[0]); | ||||
|         Clear(); | ||||
|  | ||||
|         DoShowSingleLogMessage(message, title, style); | ||||
|     } | ||||
|     else // more than one message | ||||
|     { | ||||
|         wxArrayString messages; | ||||
|         wxArrayInt severities; | ||||
|         wxArrayLong times; | ||||
|  | ||||
|         messages.swap(m_aMessages); | ||||
|         severities.swap(m_aSeverity); | ||||
|         times.swap(m_aTimes); | ||||
|  | ||||
|         Clear(); | ||||
|  | ||||
|         DoShowMultipleLogMessages(messages, severities, times, title, style); | ||||
|     } | ||||
|  | ||||
|     // allow flushing the logs again | ||||
|   | ||||
		Reference in New Issue
	
	Block a user