// This file is part of BOINC. // http://boinc.berkeley.edu // Copyright (C) 2008 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License // as published by the Free Software Foundation, // either version 3 of the License, or (at your option) any later version. // // BOINC is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with BOINC. If not, see . // #if defined(__GNUG__) && !defined(__APPLE__) #pragma implementation "NoticeListCtrl.h" #endif #include "stdwx.h" #include "Events.h" #include "BOINCGUIApp.h" #include "MainDocument.h" #include "NoticeListCtrl.h" ////@begin XPM images ////@end XPM images #ifdef __WXMAC__ CNoticeListCtrlAccessible::CNoticeListCtrlAccessible(wxWindow* win) { mp_win = win; SetupMacAccessibilitySupport(); } CNoticeListCtrlAccessible::~CNoticeListCtrlAccessible() { RemoveMacAccessibilitySupport(); } #endif #if wxUSE_ACCESSIBILITY || defined(__WXMAC__) // Gets the name of the specified object. wxAccStatus CNoticeListCtrlAccessible::GetName(int childId, wxString* name) { static wxString strBuffer; if (childId == wxACC_SELF) { *name = _("Notice List"); } else { CMainDocument* pDoc = wxDynamicCast(wxGetApp().GetDocument(), CMainDocument); strBuffer = wxEmptyString; if (pDoc) { strBuffer = wxString(process_client_message(pDoc->notice(childId-1)->title), wxConvUTF8); *name = strBuffer.c_str(); } } return wxACC_OK; } // Can return either a child object, or an integer // representing the child element, starting from 1. wxAccStatus CNoticeListCtrlAccessible::HitTest(const wxPoint& pt, int* childId, wxAccessible** /*childObject*/) { CNoticeListCtrl* pCtrl = wxDynamicCast(GetWindow(), CNoticeListCtrl); if (pCtrl) { *childId = pCtrl->HitTest(pt); return wxACC_OK; } // Let the framework handle the other cases. return wxACC_NOT_IMPLEMENTED; } // Returns the rectangle for this object (id = 0) or a child element (id > 0). wxAccStatus CNoticeListCtrlAccessible::GetLocation(wxRect& rect, int elementId) { CNoticeListCtrl* pCtrl = wxDynamicCast(GetWindow(), CNoticeListCtrl); if (pCtrl && (0 == elementId)) { // List control rect.SetPosition(pCtrl->GetScreenPosition()); rect.SetWidth(pCtrl->GetSize().GetWidth()); rect.SetHeight(pCtrl->GetSize().GetHeight()); return wxACC_OK; } else if (pCtrl && (0 != elementId)) { // List item wxSize cCtrlSize = pCtrl->GetClientSize(); int iItemWidth = cCtrlSize.GetWidth(); int iItemHeight = pCtrl->GetTotalClientHeight() / (int)pCtrl->GetItemCount(); // Set the initial control postition to the absolute coords of the upper // left hand position of the control rect.SetPosition(pCtrl->GetScreenPosition()); rect.width = iItemWidth - 1; rect.height = iItemHeight - 1; if (1 == elementId) { // First child } else { // Other children rect.SetTop(rect.GetTop() + ((elementId - 1) * iItemHeight) + 1); rect.height -= 1; } return wxACC_OK; } // Let the framework handle the other cases. return wxACC_FALSE; } // Gets the number of children. wxAccStatus CNoticeListCtrlAccessible::GetChildCount(int* childCount) { CNoticeListCtrl* pCtrl = wxDynamicCast(GetWindow(), CNoticeListCtrl); if (pCtrl) { *childCount = (int)pCtrl->GetItemCount(); return wxACC_OK; } // Let the framework handle the other cases. return wxACC_NOT_IMPLEMENTED; } // Performs the default action. childId is 0 (the action for this object) // or > 0 (the action for a child). // Return wxACC_NOT_SUPPORTED if there is no default action for this // window (e.g. an edit control). wxAccStatus CNoticeListCtrlAccessible::DoDefaultAction(int childId) { CNoticeListCtrl* pCtrl = wxDynamicCast(GetWindow(), CNoticeListCtrl); CMainDocument* pDoc = wxDynamicCast(wxGetApp().GetDocument(), CMainDocument); if (pCtrl && (childId != wxACC_SELF)) { // Zero-based array index int iRealChildId = childId - 1; pCtrl->SetSelection(iRealChildId); // Fire Event NoticeListCtrlEvent evt( wxEVT_NOTICELIST_ITEM_CHANGE, pDoc->notice(iRealChildId)->seqno, wxString(pDoc->notice(iRealChildId)->link, wxConvUTF8) ); #ifdef __WXMAC__ evt.SetEventObject(pCtrl); #else evt.SetEventObject(this); #endif pCtrl->GetParent()->AddPendingEvent( evt ); return wxACC_OK; } // Let the framework handle the other cases. return wxACC_NOT_IMPLEMENTED; } // Returns the description for this object or a child. wxAccStatus CNoticeListCtrlAccessible::GetDescription(int childId, wxString* description) { CMainDocument* pDoc = wxGetApp().GetDocument(); static wxString strBuffer; if (pDoc && (childId != wxACC_SELF)) { strBuffer = wxEmptyString; if (pDoc) { strBuffer = wxString(process_client_message(pDoc->notice(childId-1)->description.c_str()), wxConvUTF8); *description = strBuffer.c_str(); return wxACC_OK; } } // Let the framework handle the other cases. return wxACC_NOT_IMPLEMENTED; } #ifndef __WXMAC__ // Navigates from fromId to toId/toObject. wxAccStatus CNoticeListCtrlAccessible::Navigate( wxNavDir navDir, int fromId, int* toId, wxAccessible** toObject ) { CNoticeListCtrl* pCtrl = wxDynamicCast(GetWindow(), CNoticeListCtrl); *toObject = NULL; if (0 != fromId) { switch (navDir) { case wxNAVDIR_PREVIOUS: case wxNAVDIR_UP: if (1 == fromId) { return wxACC_FALSE; } else { *toId = fromId - 1; return wxACC_OK; } break; case wxNAVDIR_NEXT: case wxNAVDIR_DOWN: if ((int)pCtrl->GetItemCount() == fromId) { return wxACC_FALSE; } else { *toId = fromId + 1; return wxACC_OK; } return wxACC_FALSE; break; case wxNAVDIR_LEFT: return wxACC_FALSE; break; case wxNAVDIR_RIGHT: return wxACC_FALSE; break; case wxNAVDIR_FIRSTCHILD: if (1 == fromId) { return wxACC_FALSE; } else { *toId = 1; return wxACC_OK; } break; case wxNAVDIR_LASTCHILD: if ((int)pCtrl->GetItemCount() == fromId) { return wxACC_FALSE; } else { *toId = (int)pCtrl->GetItemCount(); return wxACC_OK; } break; } } // Let the framework handle the other cases. return wxACC_NOT_IMPLEMENTED; } // Gets the default action for this object (0) or > 0 (the action for a child). // Return wxACC_OK even if there is no action. actionName is the action, or the empty // string if there is no action. // The retrieved string describes the action that is performed on an object, // not what the object does as a result. For example, a toolbar button that prints // a document has a default action of "Press" rather than "Prints the current document." wxAccStatus CNoticeListCtrlAccessible::GetDefaultAction(int childId, wxString* actionName) { CNoticeListCtrl* pCtrl = wxDynamicCast(GetWindow(), CNoticeListCtrl); if (pCtrl && (childId != wxACC_SELF)) { *actionName = _("Click"); return wxACC_OK; } // Let the framework handle the other cases. return wxACC_NOT_IMPLEMENTED; } // Returns a role constant. wxAccStatus CNoticeListCtrlAccessible::GetRole(int childId, wxAccRole* role) { if (childId == wxACC_SELF) { *role = wxROLE_SYSTEM_LIST; } else { *role = wxROLE_SYSTEM_LISTITEM; } return wxACC_OK; } // Returns a role constant. wxAccStatus CNoticeListCtrlAccessible::GetState(int childId, long* state) { if (childId == wxACC_SELF) { *state = wxACC_STATE_SYSTEM_DEFAULT; } else { CNoticeListCtrl* pCtrl = wxDynamicCast(GetWindow(), CNoticeListCtrl); if (pCtrl && (pCtrl->IsSelected(childId - 1))) { *state = wxACC_STATE_SYSTEM_SELECTABLE | wxACC_STATE_SYSTEM_FOCUSABLE | wxACC_STATE_SYSTEM_SELECTED | wxACC_STATE_SYSTEM_FOCUSED; } else if (pCtrl && (pCtrl->IsVisible(childId - 1))) { *state = wxACC_STATE_SYSTEM_SELECTABLE | wxACC_STATE_SYSTEM_FOCUSABLE; } else { *state = wxACC_STATE_SYSTEM_SELECTABLE | wxACC_STATE_SYSTEM_FOCUSABLE | wxACC_STATE_SYSTEM_OFFSCREEN | wxACC_STATE_SYSTEM_INVISIBLE; } } return wxACC_OK; } // Selects the object or child. wxAccStatus CNoticeListCtrlAccessible::Select(int , wxAccSelectionFlags ) { // Let the framework handle the other cases. return wxACC_NOT_IMPLEMENTED; } // Gets a variant representing the selected children // of this object. // Acceptable values: // - a null variant (IsNull() returns true) // - a list variant (GetType() == wxT("list")) // - an integer representing the selected child element, // or 0 if this object is selected (GetType() == wxT("long")) // - a "void*" pointer to a wxAccessible child object wxAccStatus CNoticeListCtrlAccessible::GetSelections(wxVariant* ) { // Let the framework handle the other cases. return wxACC_NOT_IMPLEMENTED; } #endif // ifndef __WXMAC__ #endif // wxUSE_ACCESSIBILITY || defined(__WXMAC__) /*! * CNoticeListCtrl event definitions */ DEFINE_EVENT_TYPE( wxEVT_NOTICELIST_ITEM_CHANGE ) DEFINE_EVENT_TYPE( wxEVT_NOTICELIST_ITEM_DISPLAY ) /*! * CNoticeListCtrl type definition */ IMPLEMENT_DYNAMIC_CLASS( CNoticeListCtrl, wxHtmlListBox ) IMPLEMENT_DYNAMIC_CLASS( NoticeListCtrlEvent, wxNotifyEvent ) /*! * CNoticeListCtrl event table definition */ BEGIN_EVENT_TABLE( CNoticeListCtrl, wxHtmlListBox ) ////@begin CNoticeListCtrl event table entries EVT_LISTBOX(ID_LIST_NOTIFICATIONSVIEW, CNoticeListCtrl::OnSelected) EVT_LISTBOX_DCLICK(ID_LIST_NOTIFICATIONSVIEW, CNoticeListCtrl::OnDClicked) EVT_HTML_CELL_CLICKED(ID_LIST_NOTIFICATIONSVIEW, CNoticeListCtrl::OnClicked) EVT_HTML_LINK_CLICKED(ID_LIST_NOTIFICATIONSVIEW, CNoticeListCtrl::OnLinkClicked) ////@end CNoticeListCtrl event table entries END_EVENT_TABLE() /*! * CNoticeListCtrl constructors */ CNoticeListCtrl::CNoticeListCtrl( ) { } CNoticeListCtrl::CNoticeListCtrl( wxWindow* parent ) { Create( parent ); } CNoticeListCtrl::~CNoticeListCtrl( ) { #ifdef __WXMAC__ if (m_accessible) { delete m_accessible; } #endif } /*! * CNoticeListCtrl creator */ bool CNoticeListCtrl::Create( wxWindow* parent ) { ////@begin CNoticeListCtrl member initialisation ////@end CNoticeListCtrl member initialisation ////@begin CNoticeListCtrl creation wxHtmlListBox::Create( parent, ID_LIST_NOTIFICATIONSVIEW, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER | wxTAB_TRAVERSAL ); #if wxUSE_ACCESSIBILITY SetAccessible(new CNoticeListCtrlAccessible(this)); #endif #ifdef __WXMAC__ m_accessible = new CNoticeListCtrlAccessible(this); #endif ////@end CNoticeListCtrl creation return TRUE; } void CNoticeListCtrl::OnSelected( wxCommandEvent& event ) { // Fire Event NoticeListCtrlEvent evt( wxEVT_NOTICELIST_ITEM_CHANGE, event.GetInt(), wxEmptyString ); evt.SetEventObject(this); GetParent()->AddPendingEvent( evt ); } void CNoticeListCtrl::OnClicked( wxHtmlCellEvent& event ) { event.Skip(); } void CNoticeListCtrl::OnDClicked( wxCommandEvent& event ) { event.Skip(); } void CNoticeListCtrl::OnLinkClicked( wxHtmlLinkEvent& event ) { // Fire Event NoticeListCtrlEvent evt( wxEVT_NOTICELIST_ITEM_DISPLAY, event.GetInt(), event.GetLinkInfo().GetHref() ); evt.SetEventObject(this); GetParent()->AddPendingEvent( evt ); } wxString CNoticeListCtrl::OnGetItem(size_t i) const { CMainDocument* pDoc = wxGetApp().GetDocument(); wxString strTitle = wxEmptyString; wxString strDescription = wxEmptyString; wxString strProjectName = wxEmptyString; wxString strURL = wxEmptyString; wxString strArrivalTime = wxEmptyString; wxString strBuffer = wxEmptyString; wxString strTemp = wxEmptyString; wxDateTime dtBuffer; wxASSERT(pDoc); wxASSERT(wxDynamicCast(pDoc, CMainDocument)); NOTICE* np = pDoc->notice((unsigned int)i); strProjectName = wxString(np->project_name, wxConvUTF8); strURL = wxString(np->link, wxConvUTF8); strTitle = wxString(process_client_message(np->title), wxConvUTF8); strDescription = wxString(process_client_message(np->description.c_str()), wxConvUTF8); dtBuffer.Set((time_t)np->arrival_time); strArrivalTime = dtBuffer.Format(); if (!strTitle.IsEmpty()) { strTemp.Printf( wxT("%s
"), strTitle.c_str() ); strBuffer += strTemp; } strBuffer += strDescription; strBuffer += wxT("
"); if (!strProjectName.IsEmpty()) { strTemp.Printf( wxT("%s %s
"), _("From"), strProjectName.c_str() ); strBuffer += strTemp; } strBuffer += strArrivalTime; if (!strURL.IsEmpty()) { strTemp.Printf( wxT(" · %s "), strURL.c_str(), _("more...") ); strBuffer += strTemp; } strBuffer += wxT("

\n"); return strBuffer; } /*! * Update the UI. */ bool CNoticeListCtrl::UpdateUI() { CMainDocument* pDoc = wxGetApp().GetDocument(); wxASSERT(pDoc); wxASSERT(wxDynamicCast(pDoc, CMainDocument)); if (pDoc->GetNoticeCount() < 0) return true; if ( (GetItemCount() != pDoc->GetNoticeCount()) || pDoc->notices.complete ) { SetItemCount(pDoc->GetNoticeCount()); } return true; } /*! * Return the total height of all the client items. */ wxCoord CNoticeListCtrl::GetTotalClientHeight() { return EstimateTotalHeight(); }