X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/8ff411360322275bb2e2ad7860482c6d7687a921..05e0b047d879cdbfade7f2ab346c0acdf3e29f96:/src/generic/logg.cpp?ds=sidebyside diff --git a/src/generic/logg.cpp b/src/generic/logg.cpp index 779879cbeb..368cfe4d8b 100644 --- a/src/generic/logg.cpp +++ b/src/generic/logg.cpp @@ -7,7 +7,7 @@ // Created: 20.09.99 (extracted from src/common/log.cpp) // RCS-ID: $Id$ // Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows license +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // ============================================================================ @@ -18,17 +18,11 @@ // headers // ---------------------------------------------------------------------------- -// no #pragma implementation "log.h" because it's already in src/common/log.cpp - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if !wxUSE_GUI - #error "This file can't be compiled without GUI!" + #pragma hdrstop #endif #ifndef WX_PRECOMP @@ -43,8 +37,8 @@ #include "wx/textctrl.h" #include "wx/sizer.h" #include "wx/statbmp.h" - #include "wx/button.h" #include "wx/settings.h" + #include "wx/wxcrtvararg.h" #endif // WX_PRECOMP #if wxUSE_LOGGUI || wxUSE_LOGWINDOW @@ -53,20 +47,35 @@ #include "wx/textfile.h" #include "wx/statline.h" #include "wx/artprov.h" +#include "wx/collpane.h" +#include "wx/arrstr.h" + +#if wxUSE_THREADS + #include "wx/thread.h" +#endif // wxUSE_THREADS #ifdef __WXMSW__ - // for OutputDebugString() - #include "wx/msw/private.h" + // for OutputDebugString() + #include "wx/msw/private.h" #endif // Windows + +#ifdef __WXPM__ + #include +#endif + #if wxUSE_LOG_DIALOG #include "wx/listctrl.h" #include "wx/imaglist.h" #include "wx/image.h" -#else // !wxUSE_LOG_DIALOG - #include "wx/msgdlg.h" #endif // wxUSE_LOG_DIALOG/!wxUSE_LOG_DIALOG +#if defined(__MWERKS__) && wxUSE_UNICODE + #include +#endif + +#include "wx/datetime.h" + // the suffix we add to the button to show that the dialog can be expanded #define EXPAND_SUFFIX _T(" >>") @@ -78,15 +87,20 @@ // this function is a wrapper around strftime(3) // allows to exclude the usage of wxDateTime -static wxString TimeStamp(const wxChar *format, time_t t) +static wxString TimeStamp(const wxString& format, time_t t) { +#if wxUSE_DATETIME wxChar buf[4096]; - if ( !wxStrftime(buf, WXSIZEOF(buf), format, localtime(&t)) ) + struct tm tm; + if ( !wxStrftime(buf, WXSIZEOF(buf), format, wxLocaltime_r(&t, &tm)) ) { // buffer is too small? wxFAIL_MSG(_T("strftime() failed")); } return wxString(buf); +#else // !wxUSE_DATETIME + return wxEmptyString; +#endif // wxUSE_DATETIME/!wxUSE_DATETIME } @@ -103,48 +117,65 @@ public: // event handlers void OnOk(wxCommandEvent& event); - void OnDetails(wxCommandEvent& event); #if wxUSE_FILE void OnSave(wxCommandEvent& event); #endif // wxUSE_FILE void OnListSelect(wxListEvent& event); + void OnListItemActivated(wxListEvent& event); private: // create controls needed for the details display - void CreateDetailsControls(); + void CreateDetailsControls(wxWindow *); + + // if necessary truncates the given string and adds an ellipsis + wxString EllipsizeString(const wxString &text) + { + if (ms_maxLength > 0 && + text.length() > ms_maxLength) + { + wxString ret(text); + ret.Truncate(ms_maxLength); + ret << "..."; + return ret; + } + + return text; + } // the data for the listctrl wxArrayString m_messages; wxArrayInt m_severity; wxArrayLong m_times; - // the "toggle" button and its state - wxButton *m_btnDetails; - bool m_showingDetails; - // the controls which are not shown initially (but only when details // button is pressed) wxListCtrl *m_listctrl; +#ifndef __SMARTPHONE__ #if wxUSE_STATLINE wxStaticLine *m_statline; #endif // wxUSE_STATLINE #if wxUSE_FILE wxButton *m_btnSave; #endif // wxUSE_FILE +#endif // __SMARTPHONE__ // the translated "Details" string static wxString ms_details; + // the maximum length of the log message + static size_t ms_maxLength; + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxLogDialog) }; BEGIN_EVENT_TABLE(wxLogDialog, wxDialog) - EVT_BUTTON(wxID_CANCEL, wxLogDialog::OnOk) - EVT_BUTTON(wxID_MORE, wxLogDialog::OnDetails) + EVT_BUTTON(wxID_OK, wxLogDialog::OnOk) #if wxUSE_FILE EVT_BUTTON(wxID_SAVE, wxLogDialog::OnSave) #endif // wxUSE_FILE - EVT_LIST_ITEM_SELECTED(-1, wxLogDialog::OnListSelect) + EVT_LIST_ITEM_SELECTED(wxID_ANY, wxLogDialog::OnListSelect) + EVT_LIST_ITEM_ACTIVATED(wxID_ANY, wxLogDialog::OnListItemActivated) END_EVENT_TABLE() #endif // wxUSE_LOG_DIALOG @@ -156,10 +187,10 @@ END_EVENT_TABLE() #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), -// FALSE if file couldn't be opened/created and -1 if the file selection +// filename and try to open it, returns true on success (file was opened), +// false if file couldn't be opened/created and -1 if the file selection // dialog was cancelled -static int OpenLogFile(wxFile& file, wxString *filename = NULL); +static int OpenLogFile(wxFile& file, wxString *filename = NULL, wxWindow *parent = NULL); #endif // wxUSE_FILE @@ -181,33 +212,51 @@ static wxFrame *gs_pFrame = NULL; // FIXME MT-unsafe // accepts an additional argument which tells to which frame the output should // be directed -void wxVLogStatus(wxFrame *pFrame, const wxChar *szFormat, va_list argptr) +void wxVLogStatus(wxFrame *pFrame, const wxString& format, va_list argptr) { wxString msg; wxLog *pLog = wxLog::GetActiveTarget(); if ( pLog != NULL ) { - msg.PrintfV(szFormat, argptr); + msg.PrintfV(format, argptr); wxASSERT( gs_pFrame == NULL ); // should be reset! gs_pFrame = pFrame; +#ifdef __WXWINCE__ + wxLog::OnLog(wxLOG_Status, msg, 0); +#else wxLog::OnLog(wxLOG_Status, msg, time(NULL)); +#endif gs_pFrame = (wxFrame *) NULL; } } -void wxLogStatus(wxFrame *pFrame, const wxChar *szFormat, ...) +#if !wxUSE_UTF8_LOCALE_ONLY +void wxDoLogStatusWchar(wxFrame *pFrame, const wxChar *format, ...) { va_list argptr; - va_start(argptr, szFormat); - wxVLogStatus(pFrame, szFormat, argptr); + va_start(argptr, format); + wxVLogStatus(pFrame, format, argptr); va_end(argptr); } +#endif // !wxUSE_UTF8_LOCALE_ONLY + +#if wxUSE_UNICODE_UTF8 +void wxDoLogStatusUtf8(wxFrame *pFrame, const char *format, ...) +{ + va_list argptr; + va_start(argptr, format); + wxVLogStatus(pFrame, format, argptr); + va_end(argptr); +} +#endif // wxUSE_UNICODE_UTF8 // ---------------------------------------------------------------------------- // wxLogGui implementation (FIXME MT-unsafe) // ---------------------------------------------------------------------------- +#if wxUSE_LOGGUI + wxLogGui::wxLogGui() { Clear(); @@ -217,7 +266,7 @@ void wxLogGui::Clear() { m_bErrors = m_bWarnings = - m_bHasMessages = FALSE; + m_bHasMessages = false; m_aMessages.Empty(); m_aSeverity.Empty(); @@ -230,11 +279,11 @@ void wxLogGui::Flush() return; // do it right now to block any new calls to Flush() while we're here - m_bHasMessages = FALSE; + m_bHasMessages = false; + + const unsigned repeatCount = LogLastRepeatIfNeeded(); - wxString appName = wxTheApp->GetAppName(); - if ( !!appName ) - appName[0u] = wxToupper(appName[0u]); + wxString appName = wxTheApp->GetAppDisplayName(); long style; wxString titleFormat; @@ -254,7 +303,7 @@ void wxLogGui::Flush() wxString title; title.Printf(titleFormat, appName.c_str()); - size_t nMsgCount = m_aMessages.Count(); + 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! @@ -269,6 +318,12 @@ void wxLogGui::Flush() { #if wxUSE_LOG_DIALOG + if ( repeatCount > 0 ) + { + m_aMessages[nMsgCount - 1] + << " (" << m_aMessages[nMsgCount - 2] << ")"; + } + wxLogDialog dlg(NULL, m_aMessages, m_aSeverity, m_aTimes, title, style); @@ -299,7 +354,7 @@ void wxLogGui::Flush() // this catches both cases of 1 message with wxUSE_LOG_DIALOG and any // situation without it - if ( !!str ) + if ( !str.empty() ) { wxMessageBox(str, title, wxOK | style); @@ -312,7 +367,7 @@ void wxLogGui::Flush() } // log all kinds of messages -void wxLogGui::DoLog(wxLogLevel level, const wxChar *szString, time_t t) +void wxLogGui::DoLog(wxLogLevel level, const wxString& szString, time_t t) { switch ( level ) { case wxLOG_Info: @@ -322,7 +377,7 @@ void wxLogGui::DoLog(wxLogLevel level, const wxChar *szString, time_t t) m_aMessages.Add(szString); m_aSeverity.Add(wxLOG_Message); m_aTimes.Add((long)t); - m_bHasMessages = TRUE; + m_bHasMessages = true; } break; @@ -356,7 +411,7 @@ void wxLogGui::DoLog(wxLogLevel level, const wxChar *szString, time_t t) // don't prepend debug/trace here: it goes to the // debug window anyhow str += wxT("\r\n"); - OutputDebugString(str); + OutputDebugString(str.wx_str()); #else // send them to stderr wxFprintf(stderr, wxT("[%s] %s\n"), @@ -386,35 +441,39 @@ void wxLogGui::DoLog(wxLogLevel level, const wxChar *szString, time_t t) m_aSeverity.Empty(); m_aTimes.Empty(); #endif // wxUSE_LOG_DIALOG - m_bErrors = TRUE; + m_bErrors = true; } // fall through case wxLOG_Warning: if ( !m_bErrors ) { // for the warning we don't discard the info messages - m_bWarnings = TRUE; + m_bWarnings = true; } m_aMessages.Add(szString); m_aSeverity.Add((int)level); m_aTimes.Add((long)t); - m_bHasMessages = TRUE; + m_bHasMessages = true; break; } } +#endif // wxUSE_LOGGUI + // ---------------------------------------------------------------------------- // wxLogWindow and wxLogFrame implementation // ---------------------------------------------------------------------------- +#if wxUSE_LOGWINDOW + // log frame class // --------------- class wxLogFrame : public wxFrame { public: // ctor & dtor - wxLogFrame(wxFrame *pParent, wxLogWindow *log, const wxChar *szTitle); + wxLogFrame(wxWindow *pParent, wxLogWindow *log, const wxString& szTitle); virtual ~wxLogFrame(); // menu callbacks @@ -425,10 +484,14 @@ public: #endif // wxUSE_FILE void OnClear(wxCommandEvent& event); - void OnIdle(wxIdleEvent&); + // this function is safe to call from any thread (notice that it should be + // also called from the main thread to ensure that the messages logged from + // it appear in correct order with the messages from the other threads) + void AddLogMessage(const wxString& message); - // accessors - wxTextCtrl *TextCtrl() const { return m_pTextCtrl; } + // actually append the messages logged from secondary threads to the text + // control during idle time in the main thread + virtual void OnInternalIdle(); private: // use standard ids for our commands! @@ -442,10 +505,26 @@ private: // common part of OnClose() and OnCloseWindow() void DoClose(); + // do show the message in the text control + void DoShowLogMessage(const wxString& message) + { + m_pTextCtrl->AppendText(message); + } + wxTextCtrl *m_pTextCtrl; wxLogWindow *m_log; + // queue of messages logged from other threads which need to be displayed + wxArrayString m_pendingMessages; + +#if wxUSE_THREADS + // critical section to protect access to m_pendingMessages + wxCriticalSection m_critSection; +#endif // wxUSE_THREADS + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxLogFrame) }; BEGIN_EVENT_TABLE(wxLogFrame, wxFrame) @@ -459,12 +538,12 @@ BEGIN_EVENT_TABLE(wxLogFrame, wxFrame) EVT_CLOSE(wxLogFrame::OnCloseWindow) END_EVENT_TABLE() -wxLogFrame::wxLogFrame(wxFrame *pParent, wxLogWindow *log, const wxChar *szTitle) - : wxFrame(pParent, -1, szTitle) +wxLogFrame::wxLogFrame(wxWindow *pParent, wxLogWindow *log, const wxString& szTitle) + : wxFrame(pParent, wxID_ANY, szTitle) { m_log = log; - m_pTextCtrl = new wxTextCtrl(this, -1, wxEmptyString, wxDefaultPosition, + m_pTextCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxHSCROLL | @@ -503,7 +582,7 @@ void wxLogFrame::DoClose() { // instead of closing just hide the window to be able to Show() it // later - Show(FALSE); + Show(false); } } @@ -523,7 +602,7 @@ void wxLogFrame::OnSave(wxCommandEvent& WXUNUSED(event)) #if wxUSE_FILEDLG wxString filename; wxFile file; - int rc = OpenLogFile(file, &filename); + int rc = OpenLogFile(file, &filename, this); if ( rc == -1 ) { // cancelled @@ -547,7 +626,7 @@ void wxLogFrame::OnSave(wxCommandEvent& WXUNUSED(event)) wxLogError(_("Can't save log contents to file.")); } else { - wxLogStatus(this, _("Log saved to the file '%s'."), filename.c_str()); + wxLogStatus((wxFrame*)this, _("Log saved to the file '%s'."), filename.c_str()); } #endif } @@ -558,6 +637,43 @@ void wxLogFrame::OnClear(wxCommandEvent& WXUNUSED(event)) m_pTextCtrl->Clear(); } +void wxLogFrame::OnInternalIdle() +{ + { + wxCRIT_SECT_LOCKER(locker, m_critSection); + + const size_t count = m_pendingMessages.size(); + for ( size_t n = 0; n < count; n++ ) + { + DoShowLogMessage(m_pendingMessages[n]); + } + + m_pendingMessages.clear(); + } // release m_critSection + + wxFrame::OnInternalIdle(); +} + +void wxLogFrame::AddLogMessage(const wxString& message) +{ + wxCRIT_SECT_LOCKER(locker, m_critSection); + +#if wxUSE_THREADS + if ( !wxThread::IsMain() || !m_pendingMessages.empty() ) + { + // message needs to be queued for later showing + m_pendingMessages.Add(message); + + wxWakeUpIdle(); + } + else // we are the main thread and no messages are queued, so we can + // log the message directly +#endif // wxUSE_THREADS + { + DoShowLogMessage(message); + } +} + wxLogFrame::~wxLogFrame() { m_log->OnFrameDelete(this); @@ -566,8 +682,8 @@ wxLogFrame::~wxLogFrame() // wxLogWindow // ----------- -wxLogWindow::wxLogWindow(wxFrame *pParent, - const wxChar *szTitle, +wxLogWindow::wxLogWindow(wxWindow *pParent, + const wxString& szTitle, bool bShow, bool bDoPass) { @@ -576,7 +692,7 @@ wxLogWindow::wxLogWindow(wxFrame *pParent, m_pLogFrame = new wxLogFrame(pParent, this, szTitle); if ( bShow ) - m_pLogFrame->Show(TRUE); + m_pLogFrame->Show(); } void wxLogWindow::Show(bool bShow) @@ -584,7 +700,7 @@ void wxLogWindow::Show(bool bShow) m_pLogFrame->Show(bShow); } -void wxLogWindow::DoLog(wxLogLevel level, const wxChar *szString, time_t t) +void wxLogWindow::DoLog(wxLogLevel level, const wxString& szString, time_t t) { // first let the previous logger show it wxLogPassThrough::DoLog(level, szString, t); @@ -594,11 +710,11 @@ void wxLogWindow::DoLog(wxLogLevel level, const wxChar *szString, time_t t) case wxLOG_Status: // by default, these messages are ignored by wxLog, so process // them ourselves - if ( !wxIsEmpty(szString) ) + if ( !szString.empty() ) { wxString str; str << _("Status: ") << szString; - DoLogString(str, t); + LogString(str, t); } break; @@ -614,28 +730,16 @@ void wxLogWindow::DoLog(wxLogLevel level, const wxChar *szString, time_t t) wxLog::DoLog(level, szString, t); } } - - m_bHasMessages = TRUE; } -void wxLogWindow::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) +void wxLogWindow::DoLogString(const wxString& szString, time_t WXUNUSED(t)) { - // put the text into our window - wxTextCtrl *pText = m_pLogFrame->TextCtrl(); - - // remove selection (WriteText is in fact ReplaceSelection) -#ifdef __WXMSW__ - long nLen = pText->GetLastPosition(); - pText->SetSelection(nLen, nLen); -#endif // Windows - wxString msg; + TimeStamp(&msg); msg << szString << wxT('\n'); - pText->AppendText(msg); - - // TODO ensure that the line can be seen + m_pLogFrame->AddLogMessage(msg); } wxFrame *wxLogWindow::GetFrame() const @@ -650,7 +754,7 @@ void wxLogWindow::OnFrameCreate(wxFrame * WXUNUSED(frame)) bool wxLogWindow::OnFrameClose(wxFrame * WXUNUSED(frame)) { // allow to close - return TRUE; + return true; } void wxLogWindow::OnFrameDelete(wxFrame * WXUNUSED(frame)) @@ -664,15 +768,22 @@ wxLogWindow::~wxLogWindow() delete m_pLogFrame; } +#endif // wxUSE_LOGWINDOW + // ---------------------------------------------------------------------------- // wxLogDialog // ---------------------------------------------------------------------------- #if wxUSE_LOG_DIALOG +#ifndef __SMARTPHONE__ static const size_t MARGIN = 10; +#else +static const size_t MARGIN = 0; +#endif wxString wxLogDialog::ms_details; +size_t wxLogDialog::ms_maxLength = 0; wxLogDialog::wxLogDialog(wxWindow *parent, const wxArrayString& messages, @@ -680,16 +791,26 @@ wxLogDialog::wxLogDialog(wxWindow *parent, const wxArrayLong& times, const wxString& caption, long style) - : wxDialog(parent, -1, caption, + : wxDialog(parent, wxID_ANY, caption, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) { - if ( ms_details.IsEmpty() ) + // init the static variables: + + if ( ms_details.empty() ) { // ensure that we won't loop here if wxGetTranslation() // happens to pop up a Log message while translating this :-) ms_details = wxTRANSLATE("&Details"); ms_details = wxGetTranslation(ms_details); +#ifdef __SMARTPHONE__ + ms_details = wxStripMenuCodes(ms_details); +#endif + } + + if ( ms_maxLength == 0 ) + { + ms_maxLength = (2 * wxGetDisplaySize().x/3) / GetCharWidth(); } size_t count = messages.GetCount(); @@ -699,21 +820,15 @@ wxLogDialog::wxLogDialog(wxWindow *parent, for ( size_t n = 0; n < count; n++ ) { - wxString msg = messages[n]; - do - { - m_messages.Add(msg.BeforeFirst(_T('\n'))); - msg = msg.AfterFirst(_T('\n')); - - m_severity.Add(severity[n]); - m_times.Add(times[n]); - } - while ( !!msg ); + m_messages.Add(messages[n]); + m_severity.Add(severity[n]); + m_times.Add(times[n]); } - m_showingDetails = FALSE; // not initially m_listctrl = (wxListCtrl *)NULL; +#ifndef __SMARTPHONE__ + #if wxUSE_STATLINE m_statline = (wxStaticLine *)NULL; #endif // wxUSE_STATLINE @@ -722,83 +837,99 @@ wxLogDialog::wxLogDialog(wxWindow *parent, m_btnSave = (wxButton *)NULL; #endif // wxUSE_FILE +#endif // __SMARTPHONE__ + + bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); + // create the controls which are always shown and layout them: we use // sizers even though our window is not resizeable to calculate the size of // the dialog properly wxBoxSizer *sizerTop = new wxBoxSizer(wxVERTICAL); - wxBoxSizer *sizerButtons = new wxBoxSizer(wxVERTICAL); - wxBoxSizer *sizerAll = new wxBoxSizer(wxHORIZONTAL); - - // this "Ok" button has wxID_CANCEL id - not very logical, but this allows - // 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); - m_btnDetails = new wxButton(this, wxID_MORE, ms_details + EXPAND_SUFFIX); - sizerButtons->Add(m_btnDetails, 0, wxCENTRE | wxTOP, MARGIN/2 - 1); - -#ifndef __WIN16__ - wxBitmap bitmap; - switch ( style & wxICON_MASK ) + wxBoxSizer *sizerAll = new wxBoxSizer(isPda ? wxVERTICAL : wxHORIZONTAL); + + if (!isPda) { - case wxICON_ERROR: - bitmap = wxArtProvider::GetIcon(wxART_ERROR, wxART_MESSAGE_BOX); break; - case wxICON_INFORMATION: - bitmap = wxArtProvider::GetIcon(wxART_INFORMATION, wxART_MESSAGE_BOX); break; - case wxICON_WARNING: - bitmap = wxArtProvider::GetIcon(wxART_WARNING, wxART_MESSAGE_BOX); break; - default: - wxFAIL_MSG(_T("incorrect log style")); + wxStaticBitmap *icon = new wxStaticBitmap + ( + this, + wxID_ANY, + wxArtProvider::GetMessageBoxIcon(style) + ); + sizerAll->Add(icon, 0, wxALIGN_CENTRE_VERTICAL); } - sizerAll->Add(new wxStaticBitmap(this, -1, bitmap), 0); -#endif // !Win16 - const wxString& message = messages.Last(); - sizerAll->Add(CreateTextSizer(message), 1, + // create the text sizer with a minimal size so that we are sure it won't be too small + wxString message = EllipsizeString(messages.Last()); + wxSizer *szText = CreateTextSizer(message); + szText->SetMinSize(wxMin(300, wxGetDisplaySize().x / 3), -1); + + sizerAll->Add(szText, 1, wxALIGN_CENTRE_VERTICAL | wxLEFT | wxRIGHT, MARGIN); - sizerAll->Add(sizerButtons, 0, wxALIGN_RIGHT | wxLEFT, MARGIN); + + wxButton *btnOk = new wxButton(this, wxID_OK); + sizerAll->Add(btnOk, 0, isPda ? wxCENTRE : wxCENTRE|wxBOTTOM, MARGIN/2); sizerTop->Add(sizerAll, 0, wxALL | wxEXPAND, MARGIN); - SetAutoLayout(TRUE); - SetSizer(sizerTop); - sizerTop->SetSizeHints(this); - sizerTop->Fit(this); + // add the details pane - btnOk->SetFocus(); +#ifndef __SMARTPHONE__ + wxCollapsiblePane *collpane = new wxCollapsiblePane(this, wxID_ANY, ms_details); + sizerTop->Add(collpane, 1, wxGROW|wxALL, MARGIN); - // this can't happen any more as we don't use this dialog in this case -#if 0 - if ( count == 1 ) - { - // no details... it's easier to disable a button than to change the - // dialog layout depending on whether we have details or not - m_btnDetails->Disable(); - } -#endif // 0 + wxWindow *win = collpane->GetPane(); + wxSizer *paneSz = new wxBoxSizer(wxVERTICAL); + + CreateDetailsControls(win); + + paneSz->Add(m_listctrl, 1, wxEXPAND | wxTOP, MARGIN); + +#if wxUSE_FILE && !defined(__SMARTPHONE__) + paneSz->Add(m_btnSave, 0, wxALIGN_RIGHT | wxTOP, MARGIN); +#endif // wxUSE_FILE + + win->SetSizer(paneSz); + paneSz->SetSizeHints(win); +#else // __SMARTPHONE__ + SetLeftMenu(wxID_OK); + SetRightMenu(wxID_MORE, ms_details + EXPAND_SUFFIX); +#endif // __SMARTPHONE__/!__SMARTPHONE__ + + SetSizerAndFit(sizerTop); Centre(); + + if (isPda) + { + // Move up the screen so that when we expand the dialog, + // there's enough space. + Move(wxPoint(GetPosition().x, GetPosition().y / 2)); + } } -void wxLogDialog::CreateDetailsControls() +void wxLogDialog::CreateDetailsControls(wxWindow *parent) { +#ifndef __SMARTPHONE__ // create the save button and separator line if possible #if wxUSE_FILE - m_btnSave = new wxButton(this, wxID_SAVE, _("&Save...")); + m_btnSave = new wxButton(parent, wxID_SAVE); #endif // wxUSE_FILE -#if wxUSE_STATLINE - m_statline = new wxStaticLine(this, -1); -#endif // wxUSE_STATLINE +#endif // __SMARTPHONE__ // create the list ctrl now - m_listctrl = new wxListCtrl(this, -1, + m_listctrl = new wxListCtrl(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER | wxLC_REPORT | wxLC_NO_HEADER | wxLC_SINGLE_SEL); +#ifdef __WXWINCE__ + // This makes a big aesthetic difference on WinCE but I + // don't want to risk problems on other platforms + m_listctrl->Hide(); +#endif // no need to translate these strings as they're not shown to the // user anyhow (we use wxLC_NO_HEADER style) @@ -817,9 +948,8 @@ void wxLogDialog::CreateDetailsControls() wxART_INFORMATION }; - bool loadedIcons = TRUE; + bool loadedIcons = true; -#ifndef __WIN16__ for ( size_t icon = 0; icon < WXSIZEOF(icons); icon++ ) { wxBitmap bmp = wxArtProvider::GetBitmap(icons[icon], wxART_MESSAGE_BOX, @@ -829,7 +959,7 @@ void wxLogDialog::CreateDetailsControls() // Degrade gracefully. if ( !bmp.Ok() ) { - loadedIcons = FALSE; + loadedIcons = false; break; } @@ -838,7 +968,6 @@ void wxLogDialog::CreateDetailsControls() } m_listctrl->SetImageList(imageList, wxIMAGE_LIST_SMALL); -#endif // !Win16 // and fill it wxString fmt = wxLog::GetTimestamp(); @@ -853,7 +982,6 @@ void wxLogDialog::CreateDetailsControls() { int image; -#ifndef __WIN16__ if ( loadedIcons ) { switch ( m_severity[n] ) @@ -871,12 +999,15 @@ void wxLogDialog::CreateDetailsControls() } } else // failed to load images -#endif // !Win16 { image = -1; } - m_listctrl->InsertItem(n, m_messages[n], image); + wxString msg = m_messages[n]; + msg.Replace(wxT("\n"), wxT(" ")); + msg = EllipsizeString(msg); + + m_listctrl->InsertItem(n, msg, image); m_listctrl->SetItem(n, 1, TimeStamp(fmt, (time_t)m_times[n])); } @@ -898,7 +1029,7 @@ void wxLogDialog::CreateDetailsControls() heightMax *= 9; heightMax /= 10; - m_listctrl->SetSize(-1, wxMin(height, heightMax)); + m_listctrl->SetSize(wxDefaultCoord, wxMin(height, heightMax)); } void wxLogDialog::OnListSelect(wxListEvent& event) @@ -909,6 +1040,23 @@ void wxLogDialog::OnListSelect(wxListEvent& event) m_listctrl->SetItemState(event.GetIndex(), 0, wxLIST_STATE_SELECTED); } +void wxLogDialog::OnListItemActivated(wxListEvent& event) +{ + // show the activated item in a message box + // This allow the user to correctly display the logs which are longer + // than the listctrl and thus gets truncated or those which contains + // newlines. + + // NB: don't do: + // wxString str = m_listctrl->GetItemText(event.GetIndex()); + // as there's a 260 chars limit on the items inside a wxListCtrl in wxMSW. + wxString str = m_messages[event.GetIndex()]; + + // wxMessageBox will nicely handle the '\n' in the string (if any) + // and supports long strings + wxMessageBox(str, wxT("Log message"), wxOK, this); +} + void wxLogDialog::OnOk(wxCommandEvent& WXUNUSED(event)) { EndModal(wxID_OK); @@ -920,7 +1068,7 @@ void wxLogDialog::OnSave(wxCommandEvent& WXUNUSED(event)) { #if wxUSE_FILEDLG wxFile file; - int rc = OpenLogFile(file); + int rc = OpenLogFile(file, NULL, this); if ( rc == -1 ) { // cancelled @@ -958,67 +1106,6 @@ void wxLogDialog::OnSave(wxCommandEvent& WXUNUSED(event)) #endif // wxUSE_FILE -void wxLogDialog::OnDetails(wxCommandEvent& WXUNUSED(event)) -{ - wxSizer *sizer = GetSizer(); - - if ( m_showingDetails ) - { - m_btnDetails->SetLabel(ms_details + EXPAND_SUFFIX); - - sizer->Remove(m_listctrl); - -#if wxUSE_STATLINE - sizer->Remove(m_statline); -#endif // wxUSE_STATLINE - -#if wxUSE_FILE - sizer->Remove(m_btnSave); -#endif // wxUSE_FILE - } - else // show details now - { - m_btnDetails->SetLabel(wxString(_T("<< ")) + ms_details); - - if ( !m_listctrl ) - { - CreateDetailsControls(); - } - -#if wxUSE_STATLINE - sizer->Add(m_statline, 0, wxEXPAND | (wxALL & ~wxTOP), MARGIN); -#endif // wxUSE_STATLINE - - 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 - } - - m_showingDetails = !m_showingDetails; - - // in any case, our size changed - update - sizer->SetSizeHints(this); - sizer->Fit(this); - -#ifdef __WXGTK__ - // VS: this is neccessary in order to force frame redraw under - // WindowMaker or fvwm2 (and probably other broken WMs). - // Otherwise, detailed list wouldn't be displayed. - Show(TRUE); -#endif // wxGTK -} - wxLogDialog::~wxLogDialog() { if ( m_listctrl ) @@ -1032,14 +1119,14 @@ wxLogDialog::~wxLogDialog() #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), -// FALSE if file couldn't be opened/created and -1 if the file selection +// filename and try to open it, returns true on success (file was opened), +// false if file couldn't be opened/created and -1 if the file selection // dialog was cancelled -static int OpenLogFile(wxFile& file, wxString *pFilename) +static int OpenLogFile(wxFile& file, wxString *pFilename, wxWindow *parent) { // get the file name // ----------------- - wxString filename = wxSaveFileSelector(wxT("log"), wxT("txt"), wxT("log.txt")); + wxString filename = wxSaveFileSelector(wxT("log"), wxT("txt"), wxT("log.txt"), parent); if ( !filename ) { // cancelled return -1; @@ -1047,20 +1134,20 @@ static int OpenLogFile(wxFile& file, wxString *pFilename) // open file // --------- - bool bOk = FALSE; + bool bOk = false; if ( wxFile::Exists(filename) ) { - bool bAppend = FALSE; + bool bAppend = false; wxString strMsg; strMsg.Printf(_("Append log to file '%s' (choosing [No] will overwrite it)?"), filename.c_str()); switch ( wxMessageBox(strMsg, _("Question"), wxICON_QUESTION | wxYES_NO | wxCANCEL) ) { case wxYES: - bAppend = TRUE; + bAppend = true; break; case wxNO: - bAppend = FALSE; + bAppend = false; break; case wxCANCEL: @@ -1074,7 +1161,7 @@ static int OpenLogFile(wxFile& file, wxString *pFilename) bOk = file.Open(filename, wxFile::write_append); } else { - bOk = file.Create(filename, TRUE /* overwrite */); + bOk = file.Create(filename, true /* overwrite */); } } else { @@ -1091,7 +1178,7 @@ static int OpenLogFile(wxFile& file, wxString *pFilename) #endif // !(wxUSE_LOGGUI || wxUSE_LOGWINDOW) -#if wxUSE_TEXTCTRL +#if wxUSE_LOG && wxUSE_TEXTCTRL // ---------------------------------------------------------------------------- // wxLogTextCtrl implementation @@ -1102,21 +1189,13 @@ wxLogTextCtrl::wxLogTextCtrl(wxTextCtrl *pTextCtrl) m_pTextCtrl = pTextCtrl; } -void wxLogTextCtrl::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) +void wxLogTextCtrl::DoLogString(const wxString& szString, time_t WXUNUSED(t)) { wxString msg; TimeStamp(&msg); -#if defined(__WXMAC__) - // 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 - +#endif // wxUSE_LOG && wxUSE_TEXTCTRL