// 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 "ProjectListCtrl.h" #endif #include "stdwx.h" #include "diagnostics.h" #include "util.h" #include "mfile.h" #include "miofile.h" #include "parse.h" #include "error_numbers.h" #include "wizardex.h" #include "error_numbers.h" #include "BOINCGUIApp.h" #include "SkinManager.h" #include "MainDocument.h" #include "BOINCBaseWizard.h" #include "WizardAttach.h" #include "ProjectListCtrl.h" ////@begin XPM images #include "res/externalweblink.xpm" #include "res/nvidiaicon.xpm" #include "res/atiicon.xpm" #include "res/multicore.xpm" ////@end XPM images #if wxUSE_ACCESSIBILITY || defined(__WXMAC__) #ifdef __WXMAC__ CProjectListCtrlAccessible::CProjectListCtrlAccessible(wxWindow* win) { mp_win = win; SetupMacAccessibilitySupport(); } CProjectListCtrlAccessible::~CProjectListCtrlAccessible() { RemoveMacAccessibilitySupport(); } #endif // Gets the name of the specified object. wxAccStatus CProjectListCtrlAccessible::GetName(int childId, wxString* name) { if (childId == wxACC_SELF) { *name = _("Project List"); } else { CProjectListCtrl* pCtrl = wxDynamicCast(GetWindow(), CProjectListCtrl); if (pCtrl) { *name = pCtrl->GetItem(childId - 1)->GetTitle().c_str(); } } return wxACC_OK; } // Can return either a child object, or an integer // representing the child element, starting from 1. wxAccStatus CProjectListCtrlAccessible::HitTest(const wxPoint& pt, int* childId, wxAccessible** /*childObject*/) { CProjectListCtrl* pCtrl = wxDynamicCast(GetWindow(), CProjectListCtrl); 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 CProjectListCtrlAccessible::GetLocation(wxRect& rect, int elementId) { CProjectListCtrl* pCtrl = wxDynamicCast(GetWindow(), CProjectListCtrl); 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(); // Set the initial control postition to the absolute coords of the upper // left hand position of the control rect.SetPosition(pCtrl->GetScreenPosition()); rect.width = cCtrlSize.GetWidth() - 1; rect.height = pCtrl->GetItemHeight(elementId - 1) - 1; // Items can have different heights int firstVisibleItem = (int)pCtrl->GetFirstVisibleLine(); int yOffset = 0; for (int i=firstVisibleItem; i<(elementId - 1); ++i) { yOffset += pCtrl->GetItemHeight((size_t)i); } rect.SetTop(rect.GetTop() + yOffset); rect.height -= 1; return wxACC_OK; } // Let the framework handle the other cases. return wxACC_FALSE; } // Gets the number of children. wxAccStatus CProjectListCtrlAccessible::GetChildCount(int* childCount) { CProjectListCtrl* pCtrl = wxDynamicCast(GetWindow(), CProjectListCtrl); 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 CProjectListCtrlAccessible::DoDefaultAction(int childId) { CProjectListCtrl* pCtrl = wxDynamicCast(GetWindow(), CProjectListCtrl); if (pCtrl && (childId != wxACC_SELF)) { // Zero-based array index int iRealChildId = childId - 1; pCtrl->SetSelection(iRealChildId); // Fire Event ProjectListCtrlEvent evt( wxEVT_PROJECTLIST_ITEM_CHANGE, pCtrl->GetItem(iRealChildId)->GetTitle(), pCtrl->GetItem(iRealChildId)->GetURL(), true ); #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 CProjectListCtrlAccessible::GetDescription(int childId, wxString* description) { CProjectListCtrl* pCtrl = wxDynamicCast(GetWindow(), CProjectListCtrl); if (pCtrl && (childId != wxACC_SELF)) { *description = pCtrl->GetItem(childId - 1)->GetDescription().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 CProjectListCtrlAccessible::Navigate( wxNavDir navDir, int fromId, int* toId, wxAccessible** toObject ) { CProjectListCtrl* pCtrl = wxDynamicCast(GetWindow(), CProjectListCtrl); *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 CProjectListCtrlAccessible::GetDefaultAction(int childId, wxString* actionName) { CProjectListCtrl* pCtrl = wxDynamicCast(GetWindow(), CProjectListCtrl); 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 CProjectListCtrlAccessible::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 CProjectListCtrlAccessible::GetState(int childId, long* state) { if (childId == wxACC_SELF) { *state = wxACC_STATE_SYSTEM_DEFAULT; } else { CProjectListCtrl* pCtrl = wxDynamicCast(GetWindow(), CProjectListCtrl); 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 CProjectListCtrlAccessible::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 CProjectListCtrlAccessible::GetSelections(wxVariant* ) { // Let the framework handle the other cases. return wxACC_NOT_IMPLEMENTED; } #endif // ifndef __WXMAC__ #endif // wxUSE_ACCESSIBILITY || defined(__WXMAC__) /*! * CProjectListItem type definition */ IMPLEMENT_DYNAMIC_CLASS( CProjectListItem, wxObject ) /*! * CProjectListCtrl event definitions */ DEFINE_EVENT_TYPE( wxEVT_PROJECTLIST_ITEM_CHANGE ) DEFINE_EVENT_TYPE( wxEVT_PROJECTLIST_ITEM_DISPLAY ) /*! * CProjectListCtrl type definition */ IMPLEMENT_DYNAMIC_CLASS( CProjectListCtrl, wxHtmlListBox ) IMPLEMENT_DYNAMIC_CLASS( ProjectListCtrlEvent, wxNotifyEvent ) /*! * CProjectListCtrl event table definition */ BEGIN_EVENT_TABLE( CProjectListCtrl, wxHtmlListBox ) ////@begin CProjectListCtrl event table entries EVT_LISTBOX(ID_PROJECTLISTCTRL, CProjectListCtrl::OnSelected) EVT_HTML_CELL_CLICKED( ID_PROJECTLISTCTRL, CProjectListCtrl::OnClicked ) EVT_LISTBOX_DCLICK(ID_PROJECTLISTCTRL, CProjectListCtrl::OnDClicked) EVT_HTML_LINK_CLICKED( ID_PROJECTLISTCTRL, CProjectListCtrl::OnLinkClicked ) EVT_HTML_CELL_HOVER( ID_PROJECTLISTCTRL, CProjectListCtrl::OnHover ) ////@end CProjectListCtrl event table entries END_EVENT_TABLE() /*! * CProjectListCtrl constructors */ CProjectListCtrl::CProjectListCtrl( ) { } CProjectListCtrl::CProjectListCtrl( wxWindow* parent ) { Create( parent ); } #ifdef __WXMAC__ CProjectListCtrl::~CProjectListCtrl( ) { if (m_accessible) { delete m_accessible; } } #endif /*! * CProjectList creator */ bool CProjectListCtrl::Create( wxWindow* parent ) { ////@begin CProjectListCtrl member initialisation ////@end CProjectListCtrl member initialisation ////@begin CProjectListCtrl creation wxHtmlListBox::Create( parent, ID_PROJECTLISTCTRL, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER | wxTAB_TRAVERSAL ); #if wxUSE_ACCESSIBILITY SetAccessible(new CProjectListCtrlAccessible(this)); #endif #ifdef __WXMAC__ m_accessible = new CProjectListCtrlAccessible(this); #endif wxMemoryFSHandler::AddFile(wxT("webexternallink.xpm"), wxBitmap(externalweblink_xpm), wxBITMAP_TYPE_XPM); wxMemoryFSHandler::AddFile(wxT("nvidiaicon.xpm"), wxBitmap(nvidiaicon_xpm), wxBITMAP_TYPE_XPM); wxMemoryFSHandler::AddFile(wxT("atiicon.xpm"), wxBitmap(atiicon_xpm), wxBITMAP_TYPE_XPM); wxMemoryFSHandler::AddFile(wxT("multicore.xpm"), wxBitmap(multicore_xpm), wxBITMAP_TYPE_XPM); ////@end CProjectListCtrl creation return TRUE; } void CProjectListCtrl::OnSelected( wxCommandEvent& event ) { // Fire Event ProjectListCtrlEvent evt( wxEVT_PROJECTLIST_ITEM_CHANGE, m_Items[event.GetInt()]->GetTitle(), m_Items[event.GetInt()]->GetURL(), m_Items[event.GetInt()]->IsPlatformSupported() ); evt.SetEventObject(this); GetParent()->AddPendingEvent( evt ); } void CProjectListCtrl::OnClicked( wxHtmlCellEvent& event ) { event.Skip(); } void CProjectListCtrl::OnDClicked( wxCommandEvent& event ) { event.Skip(); } void CProjectListCtrl::OnLinkClicked( wxHtmlLinkEvent& event ) { // Fire Event ProjectListCtrlEvent evt( wxEVT_PROJECTLIST_ITEM_DISPLAY, wxEmptyString, event.GetLinkInfo().GetHref(), true ); evt.SetEventObject(this); GetParent()->AddPendingEvent( evt ); } void CProjectListCtrl::OnHover( wxHtmlCellEvent& event ) { long i = 0; wxHtmlCell* pCell = event.GetCell(); wxHtmlCell* pRootCell = pCell->GetRootCell(); wxString strMulticoreIcon = wxT("multicore"); wxString strNvidiaIcon = wxT("nvidiaicon"); wxString strATIIcon = wxT("atiicon"); wxString strWebsiteIcon = wxT("website"); wxString strTooltip = wxEmptyString; wxHtmlCell* pAnchor = pCell->GetParent()->GetFirstChild(); if (pAnchor->Find(wxHTML_COND_ISANCHOR, &strMulticoreIcon)) { strTooltip = _("Multicore CPU Supported"); } else if (pAnchor->Find(wxHTML_COND_ISANCHOR, &strNvidiaIcon)) { strTooltip = _("Nvidia GPU Supported"); } else if (pAnchor->Find(wxHTML_COND_ISANCHOR, &strATIIcon)) { strTooltip = _("ATI GPU Supported"); } else if (pAnchor->Find(wxHTML_COND_ISANCHOR, &strWebsiteIcon)) { strTooltip = _("Project Website"); } else { // Convert current HTML cell into an array index pRootCell->GetId().ToLong(&i); strTooltip = m_Items[i]->GetDescription(); } // Set Tooltip to the item currently being hovered over SetToolTip(strTooltip); } wxString CProjectListCtrl::OnGetItem(size_t i) const { wxString strTopRow = wxEmptyString; wxString strBuffer = wxEmptyString; // // Top Row // strTopRow += wxT(""); strTopRow += wxT(""); strBuffer.Printf( wxT(""), m_Items[i]->GetTitle().c_str() ); strTopRow += strBuffer; if (m_Items[i]->IsMulticoreSupported()) { strTopRow += wxT(""); } if (m_Items[i]->IsNvidiaGPUSupported()) { strTopRow += wxT(""); } if (m_Items[i]->IsATIGPUSupported()) { strTopRow += wxT(""); } strBuffer.Printf( wxT(""), m_Items[i]->GetURL().c_str() ); strTopRow += strBuffer; strTopRow += wxT(""); strTopRow += wxT("
%s
"); return strTopRow; } /*! * Append a new entry to the project list. */ bool CProjectListCtrl::Append( wxString strURL, wxString strTitle, wxString strImage, wxString strDescription, bool bNvidiaGPUSupported, bool bATIGPUSupported, bool bMulticoreSupported, bool bSupported ) { CProjectListItem* pItem = new CProjectListItem(); pItem->SetURL( strURL ); pItem->SetTitle( strTitle ); pItem->SetImage( strImage ); pItem->SetDescription( strDescription ); pItem->SetNvidiaGPUSupported( bNvidiaGPUSupported ); pItem->SetATIGPUSupported( bATIGPUSupported ); pItem->SetMulticoreSupported( bMulticoreSupported ); pItem->SetPlatformSupported( bSupported ); m_Items.push_back(pItem); SetItemCount(m_Items.size()); return true; } /*! * Return the project list entry at a given index. */ CProjectListItem* CProjectListCtrl::GetItem( int iIndex ) { return m_Items[iIndex]; }