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:
Vadim Zeitlin 2008-09-11 13:58:54 +00:00
parent b2794028de
commit 9ad2fe62d1
5 changed files with 186 additions and 64 deletions

View File

@ -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.
*/

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
wxArrayString messages;
wxArrayInt severities;
wxArrayLong times;
if ( repeatCount > 0 )
{
m_aMessages[nMsgCount - 1]
<< " (" << m_aMessages[nMsgCount - 2] << ")";
}
messages.swap(m_aMessages);
severities.swap(m_aSeverity);
times.swap(m_aTimes);
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();
(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