X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f6bcfd974ef26faf6f91a62cac09827e09463fd1..1b0b798d77b7b93b81d62162b290441bc9175e3e:/src/generic/logg.cpp diff --git a/src/generic/logg.cpp b/src/generic/logg.cpp index 1790b09bf5..fd60b1f972 100644 --- a/src/generic/logg.cpp +++ b/src/generic/logg.cpp @@ -44,8 +44,11 @@ #include "wx/sizer.h" #include "wx/statbmp.h" #include "wx/button.h" + #include "wx/settings.h" #endif // WX_PRECOMP +#if wxUSE_LOGGUI || wxUSE_LOGWINDOW + #include "wx/file.h" #include "wx/textfile.h" #include "wx/statline.h" @@ -55,16 +58,11 @@ #include "wx/msw/private.h" #endif // Windows -// may be defined to 0 for old behavior (using wxMessageBox) - shouldn't be -// changed normally (that's why it's here and not in setup.h) -#define wxUSE_LOG_DIALOG 1 - #if wxUSE_LOG_DIALOG - #include "wx/datetime.h" #include "wx/listctrl.h" #include "wx/imaglist.h" #include "wx/image.h" -#else // !wxUSE_TEXTFILE +#else // !wxUSE_LOG_DIALOG #include "wx/msgdlg.h" #endif // wxUSE_LOG_DIALOG/!wxUSE_LOG_DIALOG @@ -74,6 +72,20 @@ #if wxUSE_LOG_DIALOG +// this function is a wrapper around strftime(3) +// allows to exclude the usage of wxDateTime +static wxString TimeStamp(const wxChar *format, time_t t) +{ + wxChar buf[4096]; + if ( !wxStrftime(buf, WXSIZEOF(buf), format, localtime(&t)) ) + { + // buffer is too small? + wxFAIL_MSG(_T("strftime() failed")); + } + return wxString(buf); +} + + class wxLogDialog : public wxDialog { public: @@ -137,7 +149,7 @@ END_EVENT_TABLE() // private functions // ---------------------------------------------------------------------------- -#if wxUSE_FILE +#if wxUSE_FILE && wxUSE_FILEDLG // pass an uninitialized file object, the function will ask the user for the // filename and try to open it, returns TRUE on success (file was opened), @@ -152,8 +164,8 @@ static int OpenLogFile(wxFile& file, wxString *filename = NULL); // ---------------------------------------------------------------------------- // we use a global variable to store the frame pointer for wxLogStatus - bad, -// but it's he easiest way -static wxFrame *gs_pFrame; // FIXME MT-unsafe +// but it's the easiest way +static wxFrame *gs_pFrame = NULL; // FIXME MT-unsafe // ============================================================================ // implementation @@ -165,16 +177,13 @@ static wxFrame *gs_pFrame; // FIXME MT-unsafe // accepts an additional argument which tells to which frame the output should // be directed -void wxLogStatus(wxFrame *pFrame, const wxChar *szFormat, ...) +void wxVLogStatus(wxFrame *pFrame, const wxChar *szFormat, va_list argptr) { wxString msg; wxLog *pLog = wxLog::GetActiveTarget(); if ( pLog != NULL ) { - va_list argptr; - va_start(argptr, szFormat); msg.PrintfV(szFormat, argptr); - va_end(argptr); wxASSERT( gs_pFrame == NULL ); // should be reset! gs_pFrame = pFrame; @@ -183,22 +192,12 @@ void wxLogStatus(wxFrame *pFrame, const wxChar *szFormat, ...) } } -// ---------------------------------------------------------------------------- -// wxLogTextCtrl implementation -// ---------------------------------------------------------------------------- - -wxLogTextCtrl::wxLogTextCtrl(wxTextCtrl *pTextCtrl) -{ - m_pTextCtrl = pTextCtrl; -} - -void wxLogTextCtrl::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) +void wxLogStatus(wxFrame *pFrame, const wxChar *szFormat, ...) { - wxString msg; - TimeStamp(&msg); - msg << szString << wxT('\n'); - - m_pTextCtrl->AppendText(msg); + va_list argptr; + va_start(argptr, szFormat); + wxVLogStatus(pFrame, szFormat, argptr); + va_end(argptr); } // ---------------------------------------------------------------------------- @@ -247,15 +246,16 @@ void wxLogGui::Flush() titleFormat = _("%s Information"); style = wxICON_INFORMATION; } - + wxString title; title.Printf(titleFormat, appName.c_str()); - // this is the best we can do here - wxWindow *parent = wxTheApp->GetTopWindow(); - size_t nMsgCount = m_aMessages.Count(); + // 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 ) { @@ -264,7 +264,8 @@ void wxLogGui::Flush() else // more than one message { #if wxUSE_LOG_DIALOG - wxLogDialog dlg(parent, + + wxLogDialog dlg(NULL, m_aMessages, m_aSeverity, m_aTimes, title, style); @@ -296,11 +297,14 @@ void wxLogGui::Flush() // situation without it if ( !!str ) { - wxMessageBox(str, title, wxOK | style, parent); + wxMessageBox(str, title, wxOK | style); // no undisplayed messages whatsoever Clear(); } + + // allow flushing the logs again + Resume(); } // log all kinds of messages @@ -311,12 +315,10 @@ void wxLogGui::DoLog(wxLogLevel level, const wxChar *szString, time_t t) if ( GetVerbose() ) case wxLOG_Message: { - if ( !m_bErrors ) { - m_aMessages.Add(szString); - m_aSeverity.Add(wxLOG_Message); - m_aTimes.Add((long)t); - m_bHasMessages = TRUE; - } + m_aMessages.Add(szString); + m_aSeverity.Add(wxLOG_Message); + m_aTimes.Add((long)t); + m_bHasMessages = TRUE; } break; @@ -342,19 +344,21 @@ void wxLogGui::DoLog(wxLogLevel level, const wxChar *szString, time_t t) case wxLOG_Debug: #ifdef __WXDEBUG__ { - #ifdef __WXMSW__ + wxString str; + TimeStamp(&str); + str += szString; + + #if defined(__WXMSW__) && !defined(__WXMICROWIN__) // don't prepend debug/trace here: it goes to the - // debug window anyhow, but do put a timestamp - wxString str; - TimeStamp(&str); - str << szString << wxT("\n\r"); + // debug window anyhow + str += wxT("\r\n"); OutputDebugString(str); #else // send them to stderr - wxFprintf(stderr, wxT("%s: %s\n"), + wxFprintf(stderr, wxT("[%s] %s\n"), level == wxLOG_Trace ? wxT("Trace") : wxT("Debug"), - szString); + str.c_str()); fflush(stderr); #endif } @@ -460,8 +464,14 @@ wxLogFrame::wxLogFrame(wxFrame *pParent, wxLogWindow *log, const wxChar *szTitle wxDefaultSize, wxTE_MULTILINE | wxHSCROLL | + // needed for Win32 to avoid 65Kb limit but it doesn't work well + // when using RichEdit 2.0 which we always do in the Unicode build +#if !wxUSE_UNICODE + wxTE_RICH | +#endif // !wxUSE_UNICODE wxTE_READONLY); +#if wxUSE_MENUS // create menu wxMenuBar *pMenuBar = new wxMenuBar; wxMenu *pMenu = new wxMenu; @@ -473,6 +483,7 @@ wxLogFrame::wxLogFrame(wxFrame *pParent, wxLogWindow *log, const wxChar *szTitle pMenu->Append(Menu_Close, _("&Close"), _("Close this window")); pMenuBar->Append(pMenu, _("&Log")); SetMenuBar(pMenuBar); +#endif // wxUSE_MENUS #if wxUSE_STATUSBAR // status bar for menu prompts @@ -505,6 +516,7 @@ void wxLogFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) #if wxUSE_FILE void wxLogFrame::OnSave(wxCommandEvent& WXUNUSED(event)) { +#if wxUSE_FILEDLG wxString filename; wxFile file; int rc = OpenLogFile(file, &filename); @@ -533,6 +545,7 @@ void wxLogFrame::OnSave(wxCommandEvent& WXUNUSED(event)) else { wxLogStatus(this, _("Log saved to the file '%s'."), filename.c_str()); } +#endif } #endif // wxUSE_FILE @@ -548,15 +561,15 @@ wxLogFrame::~wxLogFrame() // wxLogWindow // ----------- + wxLogWindow::wxLogWindow(wxFrame *pParent, const wxChar *szTitle, bool bShow, bool bDoPass) { - m_bPassMessages = bDoPass; + PassMessages(bDoPass); m_pLogFrame = new wxLogFrame(pParent, this, szTitle); - m_pOldLog = wxLog::SetActiveTarget(this); if ( bShow ) m_pLogFrame->Show(TRUE); @@ -567,21 +580,10 @@ void wxLogWindow::Show(bool bShow) m_pLogFrame->Show(bShow); } -void wxLogWindow::Flush() -{ - if ( m_pOldLog != NULL ) - m_pOldLog->Flush(); - - m_bHasMessages = FALSE; -} - void wxLogWindow::DoLog(wxLogLevel level, const wxChar *szString, time_t t) { // first let the previous logger show it - if ( m_pOldLog != NULL && m_bPassMessages ) { - // bogus cast just to access protected DoLog - ((wxLogWindow *)m_pOldLog)->DoLog(level, szString, t); - } + wxLogPassThrough::DoLog(level, szString, t); if ( m_pLogFrame ) { switch ( level ) { @@ -654,8 +656,6 @@ void wxLogWindow::OnFrameDelete(wxFrame * WXUNUSED(frame)) wxLogWindow::~wxLogWindow() { - delete m_pOldLog; - // may be NULL if log frame already auto destroyed itself delete m_pLogFrame; } @@ -676,7 +676,9 @@ wxLogDialog::wxLogDialog(wxWindow *parent, const wxArrayLong& times, const wxString& caption, long style) - : wxDialog(parent, -1, caption) + : wxDialog(parent, -1, caption, + wxDefaultPosition, wxDefaultSize, + wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) { if ( ms_details.IsEmpty() ) { @@ -727,20 +729,21 @@ wxLogDialog::wxLogDialog(wxWindow *parent, // to close the log dialog with which wouldn't work otherwise (as it // translates into click on cancel button) wxButton *btnOk = new wxButton(this, wxID_CANCEL, _("OK")); - sizerButtons->Add(btnOk, 0, wxCENTRE|wxBOTTOM, MARGIN/2); + sizerButtons->Add(btnOk, 0, wxCENTRE | wxBOTTOM, MARGIN/2); m_btnDetails = new wxButton(this, wxID_MORE, ms_details + _T(" >>")); - sizerButtons->Add(m_btnDetails, 0, wxCENTRE|wxTOP, MARGIN/2 - 1); + sizerButtons->Add(m_btnDetails, 0, wxCENTRE | wxTOP, MARGIN/2 - 1); #ifndef __WIN16__ wxIcon icon = wxTheApp->GetStdIcon((int)(style & wxICON_MASK)); - sizerAll->Add(new wxStaticBitmap(this, -1, icon), 0, wxCENTRE); + sizerAll->Add(new wxStaticBitmap(this, -1, icon), 0); #endif // !Win16 const wxString& message = messages.Last(); - sizerAll->Add(CreateTextSizer(message), 0, wxCENTRE|wxLEFT|wxRIGHT, MARGIN); - sizerAll->Add(sizerButtons, 0, wxALIGN_RIGHT|wxLEFT, MARGIN); + sizerAll->Add(CreateTextSizer(message), 1, + wxALIGN_CENTRE_VERTICAL | wxLEFT | wxRIGHT, MARGIN); + sizerAll->Add(sizerButtons, 0, wxALIGN_RIGHT | wxLEFT, MARGIN); - sizerTop->Add(sizerAll, 0, wxCENTRE|wxALL, MARGIN); + sizerTop->Add(sizerAll, 0, wxALL | wxEXPAND, MARGIN); SetAutoLayout(TRUE); SetSizer(sizerTop); @@ -806,15 +809,17 @@ void wxLogDialog::CreateDetailsControls() { wxBitmap bmp = wxTheApp->GetStdIcon(icons[icon]); - // This may very well fail if there are insufficient - // colours available. Degrade gracefully. - - if (!bmp.Ok()) + // This may very well fail if there are insufficient colours available. + // Degrade gracefully. + if ( !bmp.Ok() ) + { loadedIcons = FALSE; - else - imageList->Add(wxImage(bmp). - Rescale(ICON_SIZE, ICON_SIZE). - ConvertToBitmap()); + + break; + } + + wxImage img(bmp); + imageList->Add(img.Rescale(ICON_SIZE, ICON_SIZE).ConvertToBitmap()); } m_listctrl->SetImageList(imageList, wxIMAGE_LIST_SMALL); @@ -831,48 +836,54 @@ void wxLogDialog::CreateDetailsControls() size_t count = m_messages.GetCount(); for ( size_t n = 0; n < count; n++ ) { - int image = -1; + int image; + #ifndef __WIN16__ - switch ( m_severity[n] ) + if ( loadedIcons ) { - case wxLOG_Error: - image = 0; - break; + switch ( m_severity[n] ) + { + case wxLOG_Error: + image = 0; + break; - case wxLOG_Warning: - image = 1; - break; + case wxLOG_Warning: + image = 1; + break; - default: - image = 2; + default: + image = 2; + } } + else // failed to load images #endif // !Win16 - - if (!loadedIcons) + { image = -1; + } - if (image > -1) - m_listctrl->InsertItem(n, m_messages[n], image); - else - m_listctrl->InsertItem(n, m_messages[n]); - - m_listctrl->SetItem(n, 1, - wxDateTime((time_t)m_times[n]).Format(fmt)); + m_listctrl->InsertItem(n, m_messages[n], image); + m_listctrl->SetItem(n, 1, TimeStamp(fmt, (time_t)m_times[n])); } // let the columns size themselves m_listctrl->SetColumnWidth(0, wxLIST_AUTOSIZE); m_listctrl->SetColumnWidth(1, wxLIST_AUTOSIZE); - // get the approx height of the listctrl - wxFont font = GetFont(); - if ( !font.Ok() ) - font = *wxSWISS_FONT; + // calculate an approximately nice height for the listctrl + int height = GetCharHeight()*(count + 4); - int y; - GetTextExtent(_T("H"), (int*)NULL, &y, (int*)NULL, (int*)NULL, &font); - int height = wxMax(y*(count + 3), 100); - m_listctrl->SetSize(-1, height); + // but check that the dialog won't fall fown from the screen + // + // we use GetMinHeight() to get the height of the dialog part without the + // details and we consider that the "Save" button below and the separator + // line (and the margins around it) take about as much, hence double it + int heightMax = wxGetDisplaySize().y - GetPosition().y - 2*GetMinHeight(); + + // we should leave a margin + heightMax *= 9; + heightMax /= 10; + + m_listctrl->SetSize(-1, wxMin(height, heightMax)); } void wxLogDialog::OnListSelect(wxListEvent& event) @@ -892,6 +903,7 @@ void wxLogDialog::OnOk(wxCommandEvent& WXUNUSED(event)) void wxLogDialog::OnSave(wxCommandEvent& WXUNUSED(event)) { +#if wxUSE_FILEDLG wxFile file; int rc = OpenLogFile(file); if ( rc == -1 ) @@ -913,7 +925,7 @@ void wxLogDialog::OnSave(wxCommandEvent& WXUNUSED(event)) for ( size_t n = 0; ok && (n < count); n++ ) { wxString line; - line << wxDateTime((time_t)m_times[n]).Format(fmt) + line << TimeStamp(fmt, (time_t)m_times[n]) << _T(": ") << m_messages[n] << wxTextFile::GetEOL(); @@ -926,6 +938,7 @@ void wxLogDialog::OnSave(wxCommandEvent& WXUNUSED(event)) if ( !ok ) wxLogError(_("Can't save log contents to file.")); +#endif // wxUSE_FILEDLG } #endif // wxUSE_FILE @@ -963,6 +976,15 @@ void wxLogDialog::OnDetails(wxCommandEvent& WXUNUSED(event)) sizer->Add(m_listctrl, 1, wxEXPAND | (wxALL & ~wxTOP), MARGIN); + // VZ: this doesn't work as this becomes the initial (and not only + // minimal) listctrl height as well - why? +#if 0 + // allow the user to make the dialog shorter than its initial height - + // without this it wouldn't work as the list ctrl would have been + // incompressible + sizer->SetItemMinSize(m_listctrl, 100, 3*GetCharHeight()); +#endif // 0 + #if wxUSE_FILE sizer->Add(m_btnSave, 0, wxALIGN_RIGHT | (wxALL & ~wxTOP), MARGIN); #endif // wxUSE_FILE @@ -992,7 +1014,7 @@ wxLogDialog::~wxLogDialog() #endif // wxUSE_LOG_DIALOG -#if wxUSE_FILE +#if wxUSE_FILE && wxUSE_FILEDLG // pass an uninitialized file object, the function will ask the user for the // filename and try to open it, returns TRUE on success (file was opened), @@ -1052,3 +1074,34 @@ static int OpenLogFile(wxFile& file, wxString *pFilename) #endif // wxUSE_FILE +#endif // !(wxUSE_LOGGUI || wxUSE_LOGWINDOW) + +#if wxUSE_TEXTCTRL + +// ---------------------------------------------------------------------------- +// wxLogTextCtrl implementation +// ---------------------------------------------------------------------------- + +wxLogTextCtrl::wxLogTextCtrl(wxTextCtrl *pTextCtrl) +{ + m_pTextCtrl = pTextCtrl; +} + +void wxLogTextCtrl::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) +{ + wxString msg; + TimeStamp(&msg); + +#if defined(__WXMAC__) && !defined(__DARWIN__) + // VZ: this is a bug in wxMac, it *must* accept '\n' as new line, the + // translation must be done in wxTextCtrl, not here! (FIXME) + msg << szString << wxT('\r'); +#else + msg << szString << wxT('\n'); +#endif + + m_pTextCtrl->AppendText(msg); +} + +#endif // wxUSE_TEXTCTRL +