#include "FileZilla.h" #include "StatusView.h" #include #ifdef _DEBUG #define new DEBUG_NEW #endif #define MAX_LINECOUNT 1000 BEGIN_EVENT_TABLE(CStatusView, wxWindow) EVT_SIZE(CStatusView::OnSize) EVT_MENU(XRCID("ID_CLEARALL"), CStatusView::OnClear) EVT_MENU(XRCID("ID_COPYTOCLIPBOARD"), CStatusView::OnCopy) END_EVENT_TABLE() class CFastTextCtrl : public wxTextCtrl { public: CFastTextCtrl(wxWindow* parent) : wxTextCtrl(parent, -1, _T(""), wxDefaultPosition, wxDefaultSize, wxNO_BORDER | wxVSCROLL | wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH | wxTE_RICH2 | wxTE_NOHIDESEL | wxTAB_TRAVERSAL) { } #ifdef __WXMSW__ // wxTextCtrl::Remove is somewhat slow, this is a faster version virtual void Remove(long from, long to) { DoSetSelection(from, to, false); m_updatesCount = -2; // suppress any update event ::SendMessage((HWND)GetHandle(), EM_REPLACESEL, 0, (LPARAM)_T("")); } #endif DECLARE_EVENT_TABLE(); void OnText(wxCommandEvent& event) { // Do nothing here. // Having this event handler prevents the event from propagating up the // window hierarchy which saves a few CPU cycles. } #ifdef __WXMSW__ void OnNavigationKey(wxNavigationKeyEvent& event) { wxWindow* parent = GetParent(); event.SetEventObject(parent); parent->ProcessEvent(event); } #else void OnKeyDown(wxKeyEvent& event) { if (event.GetKeyCode() != WXK_TAB) { event.Skip(); return; } wxWindow* parent = GetParent(); wxNavigationKeyEvent navEvent; navEvent.SetEventObject(parent); navEvent.SetDirection(!event.ShiftDown()); navEvent.SetFromTab(true); navEvent.ResumePropagation(1); parent->ProcessEvent(navEvent); } #endif }; BEGIN_EVENT_TABLE(CFastTextCtrl, wxTextCtrl) EVT_TEXT(wxID_ANY, CFastTextCtrl::OnText) #ifdef __WXMSW__ EVT_NAVIGATION_KEY(CFastTextCtrl::OnNavigationKey) #else EVT_KEY_DOWN(CFastTextCtrl::OnKeyDown) #endif END_EVENT_TABLE() CStatusView::CStatusView(wxWindow* parent, wxWindowID id) : wxWindow(parent, id, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER) { m_pTextCtrl = 0; m_pTextCtrl = new CFastTextCtrl(this); m_pTextCtrl->SetFont(GetFont()); m_pTextCtrl->Connect(wxID_ANY, wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(CStatusView::OnContextMenu), 0, this); m_nLineCount = 0; InitDefAttr(); } CStatusView::~CStatusView() { } void CStatusView::OnSize(wxSizeEvent &event) { if (m_pTextCtrl) { m_pTextCtrl->SetSize(GetClientSize()); } } void CStatusView::AddToLog(CLogmsgNotification *pNotification) { AddToLog(pNotification->msgType, pNotification->msg); } void CStatusView::AddToLog(enum MessageType messagetype, wxString message) { #ifndef __WXGTK__ wxWindowUpdateLocker *pLock = 0; #endif //__WXGTK__ wxString prefix; if (m_nLineCount) prefix = _T("\n"); if (m_nLineCount == MAX_LINECOUNT) { #ifndef __WXGTK__ pLock = new wxWindowUpdateLocker(m_pTextCtrl); #endif //__WXGTK__ m_pTextCtrl->Remove(0, m_lineLengths.front() + 1); m_lineLengths.pop_front(); } else m_nLineCount++; m_pTextCtrl->SetDefaultStyle(m_attributeCache[messagetype].attr); prefix += m_attributeCache[messagetype].prefix; int lineLength = m_attributeCache[messagetype].len + message.Length(); if (m_rtl) { // Unicode control characters that control reading direction const wxChar LTR_MARK = 0x200e; //const wxChar RTL_MARK = 0x200f; const wxChar LTR_EMBED = 0x202A; //const wxChar RTL_EMBED = 0x202B; //const wxChar POP = 0x202c; //const wxChar LTR_OVERRIDE = 0x202D; //const wxChar RTL_OVERRIDE = 0x202E; if (messagetype == Command || messagetype == Response || messagetype >= Debug_Warning) { // Commands, responses and debug message contain English text, // set LTR reading order for them. prefix += LTR_MARK; prefix += LTR_EMBED; lineLength += 2; } } m_lineLengths.push_back(lineLength); m_pTextCtrl->AppendText(prefix + message); #ifndef __WXGTK__ delete pLock; #endif //__WXGTK__ } void CStatusView::InitDefAttr() { // Measure withs of all types wxClientDC dc(this); int maxWidth = 0; wxCoord width = 0; wxCoord height = 0; dc.GetTextExtent(_("Error:"), &width, &height); maxWidth = width; dc.GetTextExtent(_("Command:"), &width, &height); if (width > maxWidth) maxWidth = width; dc.GetTextExtent(_("Response:"), &width, &height); if (width > maxWidth) maxWidth = width; dc.GetTextExtent(_("Trace:"), &width, &height); if (width > maxWidth) maxWidth = width; dc.GetTextExtent(_("Listing:"), &width, &height); if (width > maxWidth) maxWidth = width; dc.GetTextExtent(_("Status:"), &width, &height); if (width > maxWidth) maxWidth = width; dc.SetMapMode(wxMM_LOMETRIC); maxWidth = dc.DeviceToLogicalX(maxWidth) + 20; wxArrayInt array; array.Add(maxWidth); wxTextAttr defAttr; defAttr.SetTabs(array); defAttr.SetLeftIndent(0, maxWidth); for (int i = 0; i < MessageTypeCount; i++) { m_attributeCache[i].attr = defAttr; switch (i) { case Error: m_attributeCache[i].prefix = _("Error:"); m_attributeCache[i].attr.SetTextColour(wxColour(255, 0, 0)); break; case Command: m_attributeCache[i].prefix = _("Command:"); m_attributeCache[i].attr.SetTextColour(wxColour(0, 0, 128)); break; case Response: m_attributeCache[i].prefix = _("Response:"); m_attributeCache[i].attr.SetTextColour(wxColour(0, 128, 0)); break; case Debug_Warning: case Debug_Info: case Debug_Verbose: case Debug_Debug: m_attributeCache[i].prefix = _("Trace:"); m_attributeCache[i].attr.SetTextColour(wxColour(128, 0, 128)); break; case RawList: m_attributeCache[i].prefix = _("Listing:"); m_attributeCache[i].attr.SetTextColour(wxColour(0, 128, 128)); break; default: m_attributeCache[i].prefix = _("Status:"); m_attributeCache[i].attr.SetTextColour(wxColour(0, 0, 0)); break; } m_attributeCache[i].prefix += _T("\t"); m_attributeCache[i].len = m_attributeCache[i].prefix.Length(); } m_rtl = wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft; } void CStatusView::OnContextMenu(wxContextMenuEvent& event) { wxMenu* pMenu = wxXmlResource::Get()->LoadMenu(_T("ID_MENU_LOG")); if (!pMenu) return; PopupMenu(pMenu); delete pMenu; } void CStatusView::OnClear(wxCommandEvent& event) { if (m_pTextCtrl) m_pTextCtrl->Clear(); m_nLineCount = 0; m_lineLengths.clear(); } void CStatusView::OnCopy(wxCommandEvent& event) { if (!m_pTextCtrl) return; long from, to; m_pTextCtrl->GetSelection(&from, &to); if (from != to) m_pTextCtrl->Copy(); else { m_pTextCtrl->Freeze(); m_pTextCtrl->SetSelection(-1, -1); m_pTextCtrl->Copy(); m_pTextCtrl->SetSelection(from, to); m_pTextCtrl->Thaw(); } } void CStatusView::SetFocus() { m_pTextCtrl->SetFocus(); }