X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/cd1ff792d26f15ecabb92bad5473b43490b475be..9b49405777342458dc1666001865eef7309b6c30:/src/generic/logg.cpp diff --git a/src/generic/logg.cpp b/src/generic/logg.cpp index 368cfe4d8b..175d9c9208 100644 --- a/src/generic/logg.cpp +++ b/src/generic/logg.cpp @@ -44,11 +44,14 @@ #if wxUSE_LOGGUI || wxUSE_LOGWINDOW #include "wx/file.h" +#include "wx/clipbrd.h" +#include "wx/dataobj.h" #include "wx/textfile.h" #include "wx/statline.h" #include "wx/artprov.h" #include "wx/collpane.h" #include "wx/arrstr.h" +#include "wx/msgout.h" #if wxUSE_THREADS #include "wx/thread.h" @@ -79,6 +82,8 @@ // the suffix we add to the button to show that the dialog can be expanded #define EXPAND_SUFFIX _T(" >>") +#define CAN_SAVE_FILES (wxUSE_FILE && wxUSE_FILEDLG) + // ---------------------------------------------------------------------------- // private classes // ---------------------------------------------------------------------------- @@ -117,10 +122,12 @@ public: // event handlers void OnOk(wxCommandEvent& event); -#if wxUSE_FILE +#if wxUSE_CLIPBOARD + void OnCopy(wxCommandEvent& event); +#endif // wxUSE_CLIPBOARD +#if CAN_SAVE_FILES void OnSave(wxCommandEvent& event); -#endif // wxUSE_FILE - void OnListSelect(wxListEvent& event); +#endif // CAN_SAVE_FILES void OnListItemActivated(wxListEvent& event); private: @@ -142,6 +149,12 @@ private: return text; } +#if CAN_SAVE_FILES || wxUSE_CLIPBOARD + // return the contents of the dialog as a multiline string + wxString GetLogMessages() const; +#endif // CAN_SAVE_FILES || wxUSE_CLIPBOARD + + // the data for the listctrl wxArrayString m_messages; wxArrayInt m_severity; @@ -150,14 +163,6 @@ private: // 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; @@ -166,15 +171,17 @@ private: static size_t ms_maxLength; DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxLogDialog) + wxDECLARE_NO_COPY_CLASS(wxLogDialog); }; BEGIN_EVENT_TABLE(wxLogDialog, wxDialog) EVT_BUTTON(wxID_OK, wxLogDialog::OnOk) -#if wxUSE_FILE +#if wxUSE_CLIPBOARD + EVT_BUTTON(wxID_COPY, wxLogDialog::OnCopy) +#endif // wxUSE_CLIPBOARD +#if CAN_SAVE_FILES EVT_BUTTON(wxID_SAVE, wxLogDialog::OnSave) -#endif // wxUSE_FILE - EVT_LIST_ITEM_SELECTED(wxID_ANY, wxLogDialog::OnListSelect) +#endif // CAN_SAVE_FILES EVT_LIST_ITEM_ACTIVATED(wxID_ANY, wxLogDialog::OnListItemActivated) END_EVENT_TABLE() @@ -184,7 +191,7 @@ END_EVENT_TABLE() // private functions // ---------------------------------------------------------------------------- -#if wxUSE_FILE && wxUSE_FILEDLG +#if CAN_SAVE_FILES // 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), @@ -192,7 +199,7 @@ END_EVENT_TABLE() // dialog was cancelled static int OpenLogFile(wxFile& file, wxString *filename = NULL, wxWindow *parent = NULL); -#endif // wxUSE_FILE +#endif // CAN_SAVE_FILES // ---------------------------------------------------------------------------- // global variables @@ -227,7 +234,7 @@ void wxVLogStatus(wxFrame *pFrame, const wxString& format, va_list argptr) #else wxLog::OnLog(wxLOG_Status, msg, time(NULL)); #endif - gs_pFrame = (wxFrame *) NULL; + gs_pFrame = NULL; } } @@ -273,6 +280,75 @@ 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; + const size_t nMsgCount = messages.size(); + message.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 ) @@ -281,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 - - if ( repeatCount > 0 ) - { - m_aMessages[nMsgCount - 1] - << " (" << m_aMessages[nMsgCount - 2] << ")"; - } + wxArrayString messages; + wxArrayInt severities; + wxArrayLong times; - wxLogDialog dlg(NULL, - m_aMessages, m_aSeverity, m_aTimes, - title, style); + messages.swap(m_aMessages); + severities.swap(m_aSeverity); + times.swap(m_aTimes); - // 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 @@ -399,32 +435,6 @@ void wxLogGui::DoLog(wxLogLevel level, const wxString& szString, time_t t) #endif // wxUSE_STATUSBAR break; - case wxLOG_Trace: - case wxLOG_Debug: - #ifdef __WXDEBUG__ - { - wxString str; - TimeStamp(&str); - str += szString; - - #if defined(__WXMSW__) && !defined(__WXMICROWIN__) - // don't prepend debug/trace here: it goes to the - // debug window anyhow - str += wxT("\r\n"); - OutputDebugString(str.wx_str()); - #else - // send them to stderr - wxFprintf(stderr, wxT("[%s] %s\n"), - level == wxLOG_Trace ? wxT("Trace") - : wxT("Debug"), - str.c_str()); - fflush(stderr); - #endif - } - #endif // __WXDEBUG__ - - break; - case wxLOG_FatalError: // show this one immediately wxMessageBox(szString, _("Fatal error"), wxICON_HAND); @@ -456,6 +466,11 @@ void wxLogGui::DoLog(wxLogLevel level, const wxString& szString, time_t t) m_aTimes.Add((long)t); m_bHasMessages = true; break; + + default: + // let the base class deal with debug/trace messages as well as any + // custom levels + wxLog::DoLog(level, szString, t); } } @@ -479,9 +494,9 @@ public: // menu callbacks void OnClose(wxCommandEvent& event); void OnCloseWindow(wxCloseEvent& event); -#if wxUSE_FILE - void OnSave (wxCommandEvent& event); -#endif // wxUSE_FILE +#if CAN_SAVE_FILES + void OnSave(wxCommandEvent& event); +#endif // CAN_SAVE_FILES void OnClear(wxCommandEvent& event); // this function is safe to call from any thread (notice that it should be @@ -524,15 +539,15 @@ private: DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxLogFrame) + wxDECLARE_NO_COPY_CLASS(wxLogFrame); }; BEGIN_EVENT_TABLE(wxLogFrame, wxFrame) // wxLogWindow menu events EVT_MENU(Menu_Close, wxLogFrame::OnClose) -#if wxUSE_FILE +#if CAN_SAVE_FILES EVT_MENU(Menu_Save, wxLogFrame::OnSave) -#endif // wxUSE_FILE +#endif // CAN_SAVE_FILES EVT_MENU(Menu_Clear, wxLogFrame::OnClear) EVT_CLOSE(wxLogFrame::OnCloseWindow) @@ -558,9 +573,9 @@ wxLogFrame::wxLogFrame(wxWindow *pParent, wxLogWindow *log, const wxString& szTi // create menu wxMenuBar *pMenuBar = new wxMenuBar; wxMenu *pMenu = new wxMenu; -#if wxUSE_FILE +#if CAN_SAVE_FILES pMenu->Append(Menu_Save, _("&Save..."), _("Save log contents to file")); -#endif // wxUSE_FILE +#endif // CAN_SAVE_FILES pMenu->Append(Menu_Clear, _("C&lear"), _("Clear the log contents")); pMenu->AppendSeparator(); pMenu->Append(Menu_Close, _("&Close"), _("Close this window")); @@ -596,10 +611,9 @@ void wxLogFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) DoClose(); } -#if wxUSE_FILE +#if CAN_SAVE_FILES void wxLogFrame::OnSave(wxCommandEvent& WXUNUSED(event)) { -#if wxUSE_FILEDLG wxString filename; wxFile file; int rc = OpenLogFile(file, &filename, this); @@ -628,9 +642,8 @@ void wxLogFrame::OnSave(wxCommandEvent& WXUNUSED(event)) else { wxLogStatus((wxFrame*)this, _("Log saved to the file '%s'."), filename.c_str()); } -#endif } -#endif // wxUSE_FILE +#endif // CAN_SAVE_FILES void wxLogFrame::OnClear(wxCommandEvent& WXUNUSED(event)) { @@ -759,7 +772,7 @@ bool wxLogWindow::OnFrameClose(wxFrame * WXUNUSED(frame)) void wxLogWindow::OnFrameDelete(wxFrame * WXUNUSED(frame)) { - m_pLogFrame = (wxLogFrame *)NULL; + m_pLogFrame = NULL; } wxLogWindow::~wxLogWindow() @@ -776,12 +789,6 @@ wxLogWindow::~wxLogWindow() #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; @@ -825,19 +832,7 @@ wxLogDialog::wxLogDialog(wxWindow *parent, m_times.Add(times[n]); } - m_listctrl = (wxListCtrl *)NULL; - -#ifndef __SMARTPHONE__ - -#if wxUSE_STATLINE - m_statline = (wxStaticLine *)NULL; -#endif // wxUSE_STATLINE - -#if wxUSE_FILE - m_btnSave = (wxButton *)NULL; -#endif // wxUSE_FILE - -#endif // __SMARTPHONE__ + m_listctrl = NULL; bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); @@ -855,7 +850,7 @@ wxLogDialog::wxLogDialog(wxWindow *parent, wxID_ANY, wxArtProvider::GetMessageBoxIcon(style) ); - sizerAll->Add(icon, 0, wxALIGN_CENTRE_VERTICAL); + sizerAll->Add(icon, wxSizerFlags().Centre()); } // create the text sizer with a minimal size so that we are sure it won't be too small @@ -863,31 +858,43 @@ wxLogDialog::wxLogDialog(wxWindow *parent, wxSizer *szText = CreateTextSizer(message); szText->SetMinSize(wxMin(300, wxGetDisplaySize().x / 3), -1); - sizerAll->Add(szText, 1, - wxALIGN_CENTRE_VERTICAL | wxLEFT | wxRIGHT, MARGIN); + sizerAll->Add(szText, wxSizerFlags(1).Centre().Border(wxLEFT | wxRIGHT)); wxButton *btnOk = new wxButton(this, wxID_OK); - sizerAll->Add(btnOk, 0, isPda ? wxCENTRE : wxCENTRE|wxBOTTOM, MARGIN/2); + sizerAll->Add(btnOk, wxSizerFlags().Centre()); - sizerTop->Add(sizerAll, 0, wxALL | wxEXPAND, MARGIN); + sizerTop->Add(sizerAll, wxSizerFlags().Expand().Border()); // add the details pane - #ifndef __SMARTPHONE__ - wxCollapsiblePane *collpane = new wxCollapsiblePane(this, wxID_ANY, ms_details); - sizerTop->Add(collpane, 1, wxGROW|wxALL, MARGIN); + wxCollapsiblePane * const + collpane = new wxCollapsiblePane(this, wxID_ANY, ms_details); + sizerTop->Add(collpane, wxSizerFlags(1).Expand().Border()); wxWindow *win = collpane->GetPane(); - wxSizer *paneSz = new wxBoxSizer(wxVERTICAL); + wxSizer * const paneSz = new wxBoxSizer(wxVERTICAL); CreateDetailsControls(win); - paneSz->Add(m_listctrl, 1, wxEXPAND | wxTOP, MARGIN); + paneSz->Add(m_listctrl, wxSizerFlags(1).Expand().Border(wxTOP)); -#if wxUSE_FILE && !defined(__SMARTPHONE__) - paneSz->Add(m_btnSave, 0, wxALIGN_RIGHT | wxTOP, MARGIN); -#endif // wxUSE_FILE +#if wxUSE_CLIPBOARD || CAN_SAVE_FILES + wxBoxSizer * const btnSizer = new wxBoxSizer(wxHORIZONTAL); + + wxSizerFlags flagsBtn; + flagsBtn.Border(wxLEFT); + +#if wxUSE_CLIPBOARD + btnSizer->Add(new wxButton(win, wxID_COPY), flagsBtn); +#endif // wxUSE_CLIPBOARD + +#if CAN_SAVE_FILES + btnSizer->Add(new wxButton(win, wxID_SAVE), flagsBtn); +#endif // CAN_SAVE_FILES + + paneSz->Add(btnSizer, wxSizerFlags().Right().Border(wxTOP)); +#endif // wxUSE_CLIPBOARD || CAN_SAVE_FILES win->SetSizer(paneSz); paneSz->SetSizeHints(win); @@ -910,14 +917,6 @@ wxLogDialog::wxLogDialog(wxWindow *parent, void wxLogDialog::CreateDetailsControls(wxWindow *parent) { -#ifndef __SMARTPHONE__ - // create the save button and separator line if possible -#if wxUSE_FILE - m_btnSave = new wxButton(parent, wxID_SAVE); -#endif // wxUSE_FILE - -#endif // __SMARTPHONE__ - // create the list ctrl now m_listctrl = new wxListCtrl(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, @@ -1032,14 +1031,6 @@ void wxLogDialog::CreateDetailsControls(wxWindow *parent) m_listctrl->SetSize(wxDefaultCoord, wxMin(height, heightMax)); } -void wxLogDialog::OnListSelect(wxListEvent& event) -{ - // we can't just disable the control because this looks ugly under Windows - // (wrong bg colour, no scrolling...), but we still want to disable - // selecting items - it makes no sense here - m_listctrl->SetItemState(event.GetIndex(), 0, wxLIST_STATE_SELECTED); -} - void wxLogDialog::OnListItemActivated(wxListEvent& event) { // show the activated item in a message box @@ -1062,49 +1053,65 @@ void wxLogDialog::OnOk(wxCommandEvent& WXUNUSED(event)) EndModal(wxID_OK); } -#if wxUSE_FILE +#if CAN_SAVE_FILES || wxUSE_CLIPBOARD -void wxLogDialog::OnSave(wxCommandEvent& WXUNUSED(event)) +wxString wxLogDialog::GetLogMessages() const { -#if wxUSE_FILEDLG - wxFile file; - int rc = OpenLogFile(file, NULL, this); - if ( rc == -1 ) - { - // cancelled - return; - } - - bool ok = rc != 0; - wxString fmt = wxLog::GetTimestamp(); - if ( !fmt ) + if ( fmt.empty() ) { - // default format - fmt = _T("%c"); + // use the default format + fmt = "%c"; } - size_t count = m_messages.GetCount(); - for ( size_t n = 0; ok && (n < count); n++ ) + const size_t count = m_messages.GetCount(); + + wxString text; + text.reserve(count*m_messages[0].length()); + for ( size_t n = 0; n < count; n++ ) { - wxString line; - line << TimeStamp(fmt, (time_t)m_times[n]) - << _T(": ") + text << TimeStamp(fmt, (time_t)m_times[n]) + << ": " << m_messages[n] << wxTextFile::GetEOL(); + } + + return text; +} + +#endif // CAN_SAVE_FILES || wxUSE_CLIPBOARD - ok = file.Write(line); +#if wxUSE_CLIPBOARD + +void wxLogDialog::OnCopy(wxCommandEvent& WXUNUSED(event)) +{ + wxClipboardLocker clip; + if ( !clip || + !wxTheClipboard->AddData(new wxTextDataObject(GetLogMessages())) ) + { + wxLogError(_("Failed to copy dialog contents to the clipboard.")); } +} - if ( ok ) - ok = file.Close(); +#endif // wxUSE_CLIPBOARD + +#if CAN_SAVE_FILES + +void wxLogDialog::OnSave(wxCommandEvent& WXUNUSED(event)) +{ + wxFile file; + int rc = OpenLogFile(file, NULL, this); + if ( rc == -1 ) + { + // cancelled + return; + } - if ( !ok ) + if ( !rc || !file.Write(GetLogMessages()) || !file.Close() ) wxLogError(_("Can't save log contents to file.")); -#endif // wxUSE_FILEDLG } -#endif // wxUSE_FILE +#endif // CAN_SAVE_FILES wxLogDialog::~wxLogDialog() { @@ -1116,7 +1123,7 @@ wxLogDialog::~wxLogDialog() #endif // wxUSE_LOG_DIALOG -#if wxUSE_FILE && wxUSE_FILEDLG +#if CAN_SAVE_FILES // 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), @@ -1134,7 +1141,7 @@ static int OpenLogFile(wxFile& file, wxString *pFilename, wxWindow *parent) // open file // --------- - bool bOk = false; + bool bOk; if ( wxFile::Exists(filename) ) { bool bAppend = false; wxString strMsg; @@ -1174,7 +1181,7 @@ static int OpenLogFile(wxFile& file, wxString *pFilename, wxWindow *parent) return bOk; } -#endif // wxUSE_FILE +#endif // CAN_SAVE_FILES #endif // !(wxUSE_LOGGUI || wxUSE_LOGWINDOW)