boinc/clientgui/BOINCBaseView.cpp

1199 lines
42 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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 <http://www.gnu.org/licenses/>.
#if defined(__GNUG__) && !defined(__APPLE__)
#pragma implementation "BOINCBaseView.h"
#endif
#include "stdwx.h"
#include "BOINCGUIApp.h"
#include "MainDocument.h"
#include "BOINCBaseView.h"
#include "BOINCTaskCtrl.h"
#include "BOINCListCtrl.h"
#include "Events.h"
#include "res/boinc.xpm"
#include "res/sortascending.xpm"
#include "res/sortdescending.xpm"
IMPLEMENT_DYNAMIC_CLASS(CBOINCBaseView, wxPanel)
CBOINCBaseView::CBOINCBaseView() {}
CBOINCBaseView::CBOINCBaseView(wxNotebook* pNotebook) :
wxPanel(pNotebook, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL)
{
m_bProcessingTaskRenderEvent = false;
m_bProcessingListRenderEvent = false;
m_bForceUpdateSelection = true;
m_bIgnoreUIEvents = false;
m_bNeedSort = false;
m_iPreviousSelectionCount = 0;
m_lPreviousFirstSelection = -1;
//
// Setup View
//
m_pTaskPane = NULL;
m_pListPane = NULL;
m_iProgressColumn = -1;
m_iSortColumnID = -1;
m_SortArrows = NULL;
m_aStdColNameOrder = NULL;
m_iDefaultShownColumns = NULL;
m_iNumDefaultShownColumns = 0;
SetName(GetViewName());
SetAutoLayout(TRUE);
}
CBOINCBaseView::CBOINCBaseView(wxNotebook* pNotebook, wxWindowID iTaskWindowID, int iTaskWindowFlags, wxWindowID iListWindowID, int iListWindowFlags) :
wxPanel(pNotebook, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL)
{
m_bProcessingTaskRenderEvent = false;
m_bProcessingListRenderEvent = false;
m_bForceUpdateSelection = true;
m_bIgnoreUIEvents = false;
m_iPreviousSelectionCount = 0;
m_lPreviousFirstSelection = -1;
//
// Setup View
//
m_pTaskPane = NULL;
m_pListPane = NULL;
SetName(GetViewName());
SetAutoLayout(TRUE);
wxFlexGridSizer* itemFlexGridSizer = new wxFlexGridSizer(2, 0, 0);
wxASSERT(itemFlexGridSizer);
itemFlexGridSizer->AddGrowableRow(0);
itemFlexGridSizer->AddGrowableCol(1);
m_pTaskPane = new CBOINCTaskCtrl(this, iTaskWindowID, iTaskWindowFlags);
wxASSERT(m_pTaskPane);
m_pListPane = new CBOINCListCtrl(this, iListWindowID, iListWindowFlags);
wxASSERT(m_pListPane);
itemFlexGridSizer->Add(m_pTaskPane, 1, wxGROW|wxALL, 1);
itemFlexGridSizer->Add(m_pListPane, 1, wxGROW|wxALL, 1);
SetSizer(itemFlexGridSizer);
UpdateSelection();
#if USE_NATIVE_LISTCONTROL
m_pListPane->PushEventHandler(new MyEvtHandler(m_pListPane));
#else
m_pListPane->SaveEventHandler((m_pListPane->GetMainWin())->GetEventHandler());
(m_pListPane->GetMainWin())->PushEventHandler(new MyEvtHandler(m_pListPane));
#endif
m_iProgressColumn = -1;
m_iSortColumnID = -1;
m_bReverseSort = false;
m_SortArrows = new wxImageList(16, 16, true);
m_SortArrows->Add( wxIcon( sortascending_xpm ) );
m_SortArrows->Add( wxIcon( sortdescending_xpm ) );
m_pListPane->SetImageList(m_SortArrows, wxIMAGE_LIST_SMALL);
m_aStdColNameOrder = NULL;
m_iDefaultShownColumns = NULL;
m_iNumDefaultShownColumns = 0;
}
CBOINCBaseView::~CBOINCBaseView() {
if (m_pListPane) {
#if USE_NATIVE_LISTCONTROL
m_pListPane->PopEventHandler(true);
#else
(m_pListPane->GetMainWin())->PopEventHandler(true);
#endif
}
if (m_SortArrows) {
delete m_SortArrows;
}
m_arrSelectedKeys1.Clear();
m_arrSelectedKeys2.Clear();
m_iSortedIndexes.Clear();
if (m_aStdColNameOrder) {
delete m_aStdColNameOrder;
}
}
// The name of the view.
// If it has not been defined by the view "Undefined" is returned.
//
wxString& CBOINCBaseView::GetViewName() {
static wxString strViewName(wxT("Undefined"));
return strViewName;
}
// The user friendly name of the view.
// If it has not been defined by the view "Undefined" is returned.
//
wxString& CBOINCBaseView::GetViewDisplayName() {
static wxString strViewName(wxT("Undefined"));
return strViewName;
}
// The user friendly icon of the view.
// If it has not been defined by the view the BOINC icon is returned.
//
const char** CBOINCBaseView::GetViewIcon() {
wxASSERT(boinc_xpm);
return boinc_xpm;
}
// The rate at which the view is refreshed.
// If it has not been defined by the view 1 second is retrned.
//
int CBOINCBaseView::GetViewRefreshRate() {
return 1;
}
// Get bit mask of current view(s).
//
int CBOINCBaseView::GetViewCurrentViewPage() {
return 0;
}
wxString CBOINCBaseView::GetKeyValue1(int) {
return wxEmptyString;
}
wxString CBOINCBaseView::GetKeyValue2(int) {
return wxEmptyString;
}
int CBOINCBaseView::FindRowIndexByKeyValues(wxString&, wxString&) {
return -1;
}
bool CBOINCBaseView::FireOnSaveState(wxConfigBase* pConfig) {
return OnSaveState(pConfig);
}
bool CBOINCBaseView::FireOnRestoreState(wxConfigBase* pConfig) {
return OnRestoreState(pConfig);
}
int CBOINCBaseView::GetListRowCount() {
wxASSERT(m_pListPane);
return m_pListPane->GetItemCount();
}
void CBOINCBaseView::FireOnListRender(wxTimerEvent& event) {
OnListRender(event);
}
void CBOINCBaseView::FireOnListSelected(wxListEvent& event) {
OnListSelected(event);
}
void CBOINCBaseView::FireOnListDeselected(wxListEvent& event) {
OnListDeselected(event);
}
wxString CBOINCBaseView::FireOnListGetItemText(long item, long column) const {
return OnListGetItemText(item, column);
}
int CBOINCBaseView::FireOnListGetItemImage(long item) const {
return OnListGetItemImage(item);
}
void CBOINCBaseView::OnListRender(wxTimerEvent& event) {
if (!m_bProcessingListRenderEvent) {
m_bProcessingListRenderEvent = true;
wxASSERT(m_pListPane);
// Remember the key values of currently selected items
SaveSelections();
int iDocCount = GetDocCount();
int iCacheCount = GetCacheCount();
if (iDocCount != iCacheCount) {
if (0 >= iDocCount) {
EmptyCache();
m_pListPane->DeleteAllItems();
} else {
int iIndex = 0;
int iReturnValue = -1;
if (iDocCount > iCacheCount) {
for (iIndex = 0; iIndex < (iDocCount - iCacheCount); iIndex++) {
iReturnValue = AddCacheElement();
wxASSERT(!iReturnValue);
}
wxASSERT(GetDocCount() == GetCacheCount());
m_pListPane->SetItemCount(iDocCount);
m_bNeedSort = true;
} else {
// The virtual ListCtrl keeps a separate its list of selected rows;
// make sure it does not reference any rows beyond the new last row.
// We can ClearSelections() because we called SaveSelections() above.
ClearSelections();
m_pListPane->SetItemCount(iDocCount);
for (iIndex = (iCacheCount - 1); iIndex >= iDocCount; --iIndex) {
iReturnValue = RemoveCacheElement();
wxASSERT(!iReturnValue);
}
wxASSERT(GetDocCount() == GetCacheCount());
//fprintf(stderr, "CBOINCBaseView::OnListRender(): m_pListPane->RefreshItems(0, %d)\n", iDocCount - 1);
m_pListPane->RefreshItems(0, iDocCount - 1);
#ifdef __WXGTK__
// Work around an apparent bug in wxWidgets 3.0
// which drew blank lines at the top and failed
// to draw the bottom items. This could happen
// if the list was scrolled near the bottom and
// the user selected "Show active tasks."
m_pListPane->EnsureVisible(iDocCount - 1);
#endif
m_bNeedSort = true;
}
}
}
if (iDocCount > 0) {
SynchronizeCache();
if (iDocCount > 1) {
if (_EnsureLastItemVisible() && (iDocCount != iCacheCount)) {
m_pListPane->EnsureVisible(iDocCount - 1);
}
}
}
// Find the previously selected items by their key values and reselect them
RestoreSelections();
UpdateSelection();
m_bProcessingListRenderEvent = false;
}
event.Skip();
}
bool CBOINCBaseView::OnSaveState(wxConfigBase* pConfig) {
bool bReturnValue = true;
wxASSERT(pConfig);
wxASSERT(m_pTaskPane);
wxASSERT(m_pListPane);
if (!m_pTaskPane->OnSaveState(pConfig)) {
bReturnValue = false;
}
if (!m_pListPane->OnSaveState(pConfig)) {
bReturnValue = false;
}
return bReturnValue;
}
bool CBOINCBaseView::OnRestoreState(wxConfigBase* pConfig) {
wxASSERT(pConfig);
wxASSERT(m_pTaskPane);
wxASSERT(m_pListPane);
if (!m_pTaskPane->OnRestoreState(pConfig)) {
return false;
}
if (!m_pListPane->OnRestoreState(pConfig)) {
return false;
}
return true;
}
// We don't use this because multiple selection virtual
// wxListCtrl does not generate selection events for
// shift-click; see OnCheckSelectionChanged() below.
void CBOINCBaseView::OnListSelected(wxListEvent& event) {
wxLogTrace(wxT("Function Start/End"), wxT("CBOINCBaseView::OnListSelected - Function Begin"));
if (!m_bIgnoreUIEvents) {
m_bForceUpdateSelection = true;
UpdateSelection();
event.Skip();
}
wxLogTrace(wxT("Function Start/End"), wxT("CBOINCBaseView::OnListSelected - Function End"));
}
// We don't use this because multiple selection virtual
// wxListCtrl does generates deselection events only for
// control-click; see OnCheckSelectionChanged() below.
void CBOINCBaseView::OnListDeselected(wxListEvent& event) {
wxLogTrace(wxT("Function Start/End"), wxT("CBOINCBaseView::OnListDeselected - Function Begin"));
if (!m_bIgnoreUIEvents) {
m_bForceUpdateSelection = true;
UpdateSelection();
event.Skip();
}
wxLogTrace(wxT("Function Start/End"), wxT("CBOINCBaseView::OnListDeselected - Function End"));
}
void CBOINCBaseView::OnCheckSelectionChanged(CCheckSelectionChangedEvent& ) {
CheckSelectionChanged();
}
void CBOINCBaseView::OnCacheHint(wxListEvent& ) {
CheckSelectionChanged();
}
// Work around features in multiple selection virtual wxListCtrl:
// * It does not send deselection events (except ctrl-click).
// * It does not send selection events if you add to selection
// using Shift_Click.
//
// We currently handle all selections and deselections here.
// On the Mac, this is called due to an event posted by CBOINCListCtrl::OnMouseDown().
// On Windows, it is called due to a EVT_LIST_CACHE_HINT from wxListCtrl.
void CBOINCBaseView::CheckSelectionChanged() {
int newSelectionCount = m_pListPane->GetSelectedItemCount();
long currentSelection = m_pListPane->GetFirstSelected();
if ((newSelectionCount != m_iPreviousSelectionCount) ||
(currentSelection != m_lPreviousFirstSelection)
) {
if (!m_bIgnoreUIEvents) {
m_bForceUpdateSelection = true;
UpdateSelection();
}
}
m_iPreviousSelectionCount = newSelectionCount;
m_lPreviousFirstSelection = currentSelection;
}
wxString CBOINCBaseView::OnListGetItemText(long WXUNUSED(item), long WXUNUSED(column)) const {
return wxString(wxT("Undefined"));
}
int CBOINCBaseView::OnListGetItemImage(long WXUNUSED(item)) const {
return -1;
}
int CBOINCBaseView::GetDocCount() {
return 0;
}
wxString CBOINCBaseView::OnDocGetItemImage(long WXUNUSED(item)) const {
return wxString(wxT("Undefined"));
}
wxString CBOINCBaseView::OnDocGetItemAttr(long WXUNUSED(item)) const {
return wxString(wxT("Undefined"));
}
int CBOINCBaseView::AddCacheElement() {
return -1;
}
int CBOINCBaseView::EmptyCache() {
return -1;
}
int CBOINCBaseView::GetCacheCount() {
return -1;
}
int CBOINCBaseView::RemoveCacheElement() {
return -1;
}
int CBOINCBaseView::SynchronizeCache() {
int iRowIndex = 0;
int iRowTotal = 0;
int iColumnIndex = 0;
int iColumnTotal = 0;
bool bNeedRefreshData = false;
iRowTotal = GetDocCount();
iColumnTotal = m_pListPane->GetColumnCount();
for (iRowIndex = 0; iRowIndex < iRowTotal; iRowIndex++) {
bNeedRefreshData = false;
for (iColumnIndex = 0; iColumnIndex < iColumnTotal; iColumnIndex++) {
if (SynchronizeCacheItem(iRowIndex, iColumnIndex)) {
#ifdef __WXMAC__
bNeedRefreshData = true;
#else
// To reduce flicker, refresh only changed columns
m_pListPane->RefreshCell(iRowIndex, iColumnIndex);
#endif
if (iColumnIndex >= 0) {
if (m_iColumnIndexToColumnID[iColumnIndex] == m_iSortColumnID) {
m_bNeedSort = true;
}
}
}
}
// Mac is double-buffered to avoid flicker, so this is more efficient
if (bNeedRefreshData) {
m_pListPane->RefreshItem(iRowIndex);
}
}
if (m_bNeedSort) {
sortData(); // Will mark moved items as needing refresh
m_bNeedSort = false;
}
return 0;
}
bool CBOINCBaseView::SynchronizeCacheItem(wxInt32 WXUNUSED(iRowIndex), wxInt32 WXUNUSED(iColumnIndex)) {
return false;
}
void CBOINCBaseView::OnColClick(wxListEvent& event) {
wxListItem item;
int newSortColIndex = event.GetColumn();
int oldSortColIndex = -1;
if (newSortColIndex < 0) return; // Clicked past last column
if (m_iSortColumnID >= 0) {
oldSortColIndex = m_iColumnIDToColumnIndex[m_iSortColumnID];
}
item.SetMask(wxLIST_MASK_IMAGE);
if (newSortColIndex == oldSortColIndex) {
m_bReverseSort = !m_bReverseSort;
SetSortColumn(newSortColIndex);
} else {
// Remove sort arrow from old sort column
if (oldSortColIndex >= 0) {
item.SetImage(-1);
m_pListPane->SetColumn(oldSortColIndex, item);
}
m_iSortColumnID = m_iColumnIndexToColumnID[newSortColIndex];
m_bReverseSort = false;
SetSortColumn(newSortColIndex);
}
// Write the change to the registry
// Do this here because SetListColumnOrder() can call SetSortColumn()
// even when neither m_iSortColumnID nor m_bReverseSort changes
wxConfigBase* pConfig = wxConfigBase::Get(false);
pConfig->SetPath(wxT("/") + GetViewName());
m_pListPane->OnSaveState(pConfig);
}
void CBOINCBaseView::SetSortColumn(int newSortColIndex) {
wxListItem item;
int i, j, m;
wxArrayInt selections;
item.SetImage(m_bReverseSort ? 0 : 1);
m_pListPane->SetColumn(newSortColIndex, item);
Freeze(); // To reduce flicker
// Remember which cache elements are selected and deselect them
m_bIgnoreUIEvents = true;
i = -1;
while (1) {
i = m_pListPane->GetNextSelected(i);
if (i < 0) break;
selections.Add(m_iSortedIndexes[i]);
m_pListPane->SelectRow(i, false);
}
sortData();
// Reselect previously selected cache elements in the sorted list
m = (int)selections.GetCount();
for (i=0; i<m; i++) {
if (selections[i] >= 0) {
j = m_iSortedIndexes.Index(selections[i]);
m_pListPane->SelectRow(j, true);
}
}
m_bIgnoreUIEvents = false;
Thaw();
}
void CBOINCBaseView::InitSort() {
wxListItem item;
if (m_iSortColumnID < 0) return;
int newSortColIndex = m_iColumnIDToColumnIndex[m_iSortColumnID];
if (newSortColIndex < 0) return;
item.SetMask(wxLIST_MASK_IMAGE);
item.SetImage(m_bReverseSort ? 0 : 1);
m_pListPane->SetColumn(newSortColIndex, item);
Freeze(); // To reduce flicker
sortData();
Thaw();
}
void CBOINCBaseView::sortData() {
if (m_iSortColumnID < 0) return;
if (m_iColumnIDToColumnIndex[m_iSortColumnID] < 0) return;
wxArrayInt oldSortedIndexes(m_iSortedIndexes);
int i, n = (int)m_iSortedIndexes.GetCount();
std::stable_sort(m_iSortedIndexes.begin(), m_iSortedIndexes.end(), m_funcSortCompare);
// Refresh rows which have moved
for (i=0; i<n; i++) {
if (m_iSortedIndexes[i] != oldSortedIndexes[i]) {
m_pListPane->RefreshItem(i);
}
}
}
void CBOINCBaseView::EmptyTasks() {
unsigned int i;
unsigned int j;
for (i=0; i<m_TaskGroups.size(); i++) {
for (j=0; j<m_TaskGroups[i]->m_Tasks.size(); j++) {
delete m_TaskGroups[i]->m_Tasks[j];
}
m_TaskGroups[i]->m_Tasks.clear();
delete m_TaskGroups[i];
}
m_TaskGroups.clear();
}
void CBOINCBaseView::ClearSavedSelections() {
m_arrSelectedKeys1.Clear();
m_arrSelectedKeys2.Clear();
}
// Save the key values of the currently selected rows for later restore
void CBOINCBaseView::SaveSelections() {
if (!_IsSelectionManagementNeeded()) {
return;
}
m_arrSelectedKeys1.Clear();
m_arrSelectedKeys2.Clear();
m_bIgnoreUIEvents = true;
int i = -1;
while (1) {
i = m_pListPane->GetNextSelected(i);
if (i < 0) break;
m_arrSelectedKeys1.Add(GetKeyValue1(i));
m_arrSelectedKeys2.Add(GetKeyValue2(i));
}
m_bIgnoreUIEvents = false;
}
// Select all rows with formerly selected data based on key values
//
// Each RPC may add (insert) or delete items from the list, so
// the selected row numbers may now point to different data.
// We called SaveSelections() before updating the underlying
// data; this routine finds the data corresponding to each
// previous selection and makes any adjustments to ensure that
// the rows containing the originally selected data are selected.
void CBOINCBaseView::RestoreSelections() {
if (!_IsSelectionManagementNeeded()) {
return;
}
// To minimize flicker, this method selects or deselects only
// those rows which actually need their selection status changed.
// First, get a list of which rows should be selected
int i, j, m = 0, newCount = 0, oldCount = (int)m_arrSelectedKeys1.size();
bool found;
wxArrayInt arrSelRows;
for(i=0; i< oldCount; ++i) {
int index = FindRowIndexByKeyValues(m_arrSelectedKeys1[i], m_arrSelectedKeys2[i]);
if(index >= 0) {
arrSelRows.Add(index);
}
}
newCount = (int)arrSelRows.GetCount();
// Step through the currently selected row numbers and for each one determine
// whether it should remain selected.
m_bIgnoreUIEvents = true;
i = -1;
while (1) {
found = false;
i = m_pListPane->GetNextSelected(i);
if (i < 0) break;
m = (int)arrSelRows.GetCount();
for (j=0; j<m; ++j) {
if (arrSelRows[j] == i) {
arrSelRows.RemoveAt(j); // We have handled this one so remove from list
found = true; // Already selected, so no change needed
break;
}
}
if (!found) {
m_pListPane->SelectRow(i, false); // This row should no longer be selected
}
}
// Now select those rows which were not previously selected but should now be
m = (int)arrSelRows.GetCount();
for (j=0; j<m; ++j) {
m_pListPane->SelectRow(arrSelRows[j], true);
}
m_bIgnoreUIEvents = false;
if (oldCount != newCount) {
m_bForceUpdateSelection = true; // OnListRender() will call UpdateSelection()
}
}
void CBOINCBaseView::ClearSelections() {
if (!m_pListPane) return;
m_bIgnoreUIEvents = true;
int i = -1;
while (1) {
i = m_pListPane->GetNextSelected(i);
if (i < 0) break;
m_pListPane->SelectRow(i, false);
}
m_bIgnoreUIEvents = false;
}
void CBOINCBaseView::PreUpdateSelection(){
}
void CBOINCBaseView::UpdateSelection(){
}
void CBOINCBaseView::PostUpdateSelection(){
wxASSERT(m_pTaskPane);
if (m_pTaskPane->UpdateControls()) {
// Under wxWidgets 2.9.4, Layout() causes ListCtrl
// to repaint, so call only when actually needed.
Layout();
}
}
void CBOINCBaseView::UpdateWebsiteSelection(long lControlGroup, PROJECT* project){
unsigned int i;
CTaskItemGroup* pGroup = NULL;
CTaskItem* pItem = NULL;
wxASSERT(m_pTaskPane);
wxASSERT(m_pListPane);
if (m_bForceUpdateSelection) {
// Update the websites list
//
if (m_TaskGroups.size() > 1) {
// Delete task group, objects, and controls.
pGroup = m_TaskGroups[lControlGroup];
m_pTaskPane->DeleteTaskGroupAndTasks(pGroup);
for (i=0; i<pGroup->m_Tasks.size(); i++) {
delete pGroup->m_Tasks[i];
}
pGroup->m_Tasks.clear();
delete pGroup;
pGroup = NULL;
m_TaskGroups.erase( m_TaskGroups.begin() + 1 );
}
// If something is selected create the tasks and controls
//
if (m_pListPane->GetSelectedItemCount()) {
if (project) {
// Create the web sites task group
pGroup = new CTaskItemGroup( _("Project web pages") );
m_TaskGroups.push_back( pGroup );
// Default project url
pItem = new CTaskItem(
wxString("Home page", wxConvUTF8),
wxString(project->project_name.c_str(), wxConvUTF8) + wxT(" web site"),
wxString(project->master_url, wxConvUTF8),
ID_TASK_PROJECT_WEB_PROJDEF_MIN
);
pGroup->m_Tasks.push_back(pItem);
// Project defined urls
for (i=0;(i<project->gui_urls.size())&&(i<=ID_TASK_PROJECT_WEB_PROJDEF_MAX);i++) {
pItem = new CTaskItem(
wxGetTranslation(wxString(project->gui_urls[i].name.c_str(), wxConvUTF8)),
wxGetTranslation(wxString(project->gui_urls[i].description.c_str(), wxConvUTF8)),
wxString(project->gui_urls[i].url.c_str(), wxConvUTF8),
ID_TASK_PROJECT_WEB_PROJDEF_MIN + 1 + i
);
pGroup->m_Tasks.push_back(pItem);
}
}
}
m_pTaskPane->FitInside();
m_bForceUpdateSelection = false;
}
}
// Make sure task pane background is properly erased
void CBOINCBaseView::RefreshTaskPane() {
if (m_pTaskPane) {
m_pTaskPane->Refresh(true);
}
}
#ifdef __WXMAC__
// Fix Keyboard navigation on Mac
//
// NOTE: to select an item in wxListCtrl when none
// has yet been selected, press tab and then space.
#define SHIFT_MASK (1<<17)
void CBOINCBaseView::OnKeyPressed(wxKeyEvent &event) {
wxWindow next;
CTaskItemGroup* pGroup = NULL;
CTaskItem* pItem = NULL;
int i, j;
bool focusOK = false;
if (m_pTaskPane) {
int keyCode = event.GetKeyCode();
wxUint32 keyFlags = event.GetRawKeyFlags();
if (keyCode == WXK_TAB) {
wxWindow* focused = wxWindow::FindFocus();
if (!m_pTaskPane->IsDescendant(focused)) {
if (keyFlags & SHIFT_MASK) {
for (i=m_TaskGroups.size()-1; i>=0; --i) {
pGroup = m_TaskGroups[i];
for (j=pGroup->m_Tasks.size()-1; j>=0; --j) {
pItem = pGroup->m_Tasks[j];
if (pItem->m_pButton) {
if (pItem->m_pButton->CanAcceptFocus()) {
focusOK = true;
break;
}
}
}
if (focusOK) break;
}
} else {
for (i=0; i<m_TaskGroups.size(); ++i) {
pGroup = m_TaskGroups[i];
for (j=0; j<pGroup->m_Tasks.size(); ++j) {
pItem = pGroup->m_Tasks[j];
if (pItem->m_pButton) {
if (pItem->m_pButton->CanAcceptFocus()) {
focusOK = true;
break;
}
}
}
if (focusOK) break;
}
}
if (focusOK) {
pItem->m_pButton->SetFocus();
return;
}
}
wxNavigationKeyEvent evt;
evt.SetDirection((keyFlags & SHIFT_MASK) == 0);
evt.SetFromTab(true);
m_pTaskPane->GetEventHandler()->AddPendingEvent(evt);
return;
}
}
event.Skip();
}
#endif
bool CBOINCBaseView::_IsSelectionManagementNeeded() {
return IsSelectionManagementNeeded();
}
bool CBOINCBaseView::IsSelectionManagementNeeded() {
return false;
}
bool CBOINCBaseView::_EnsureLastItemVisible() {
return EnsureLastItemVisible();
}
bool CBOINCBaseView::EnsureLastItemVisible() {
return false;
}
double CBOINCBaseView::GetProgressValue(long) {
return 0.0;
}
wxString CBOINCBaseView::GetProgressText( long ) {
return wxEmptyString;
}
void CBOINCBaseView::AppendColumn(int){
}
void CBOINCBaseView::append_to_status(wxString& existing, const wxChar* additional) {
if (existing.size() == 0) {
existing = additional;
} else {
existing = existing + wxT(", ") + additional;
}
}
// HTML Entity Conversion:
// http://www.webreference.com/html/reference/character/
// Completed: The ISO Latin 1 Character Set
//
wxString CBOINCBaseView::HtmlEntityEncode(wxString strRaw) {
wxString strEncodedHtml(strRaw);
#ifdef __WXMSW__
strEncodedHtml.Replace(wxT("&"), wxT("&amp;"), true);
strEncodedHtml.Replace(wxT("\""), wxT("&quot;"), true);
strEncodedHtml.Replace(wxT("<"), wxT("&lt;"), true);
strEncodedHtml.Replace(wxT(">"), wxT("&gt;"), true);
strEncodedHtml.Replace(wxT(""), wxT("&sbquo;"), true);
strEncodedHtml.Replace(wxT("ƒ"), wxT("&fnof;"), true);
strEncodedHtml.Replace(wxT(""), wxT("&bdquo;"), true);
strEncodedHtml.Replace(wxT(""), wxT("&hellip;"), true);
strEncodedHtml.Replace(wxT(""), wxT("&dagger;"), true);
strEncodedHtml.Replace(wxT(""), wxT("&Dagger;"), true);
strEncodedHtml.Replace(wxT("Š"), wxT("&Scaron;"), true);
strEncodedHtml.Replace(wxT("Œ"), wxT("&OElig;"), true);
strEncodedHtml.Replace(wxT(""), wxT("&lsquo;"), true);
strEncodedHtml.Replace(wxT(""), wxT("&rsquo;"), true);
strEncodedHtml.Replace(wxT(""), wxT("&ldquo;"), true);
strEncodedHtml.Replace(wxT(""), wxT("&rdquo;"), true);
strEncodedHtml.Replace(wxT(""), wxT("&bull;"), true);
strEncodedHtml.Replace(wxT(""), wxT("&ndash;"), true);
strEncodedHtml.Replace(wxT(""), wxT("&mdash;"), true);
strEncodedHtml.Replace(wxT("˜˜~"), wxT("&tilde;"), true);
strEncodedHtml.Replace(wxT(""), wxT("&trade;"), true);
strEncodedHtml.Replace(wxT("š"), wxT("&scaron;"), true);
strEncodedHtml.Replace(wxT("œ"), wxT("&oelig;"), true);
strEncodedHtml.Replace(wxT("Ÿ"), wxT("&Yuml;"), true);
strEncodedHtml.Replace(wxT("¡"), wxT("&iexcl;"), true);
strEncodedHtml.Replace(wxT("¢"), wxT("&cent;"), true);
strEncodedHtml.Replace(wxT("£"), wxT("&pound;"), true);
strEncodedHtml.Replace(wxT("¤"), wxT("&curren;"), true);
strEncodedHtml.Replace(wxT("¥"), wxT("&yen;"), true);
strEncodedHtml.Replace(wxT("¦"), wxT("&brvbar;"), true);
strEncodedHtml.Replace(wxT("§"), wxT("&sect;"), true);
strEncodedHtml.Replace(wxT("¨"), wxT("&uml;"), true);
strEncodedHtml.Replace(wxT("©"), wxT("&copy;"), true);
strEncodedHtml.Replace(wxT("ª"), wxT("&ordf;"), true);
strEncodedHtml.Replace(wxT("«"), wxT("&laquo;"), true);
strEncodedHtml.Replace(wxT("¬"), wxT("&not;"), true);
strEncodedHtml.Replace(wxT("®"), wxT("&reg;"), true);
strEncodedHtml.Replace(wxT("¯"), wxT("&macr;"), true);
strEncodedHtml.Replace(wxT("°"), wxT("&deg;"), true);
strEncodedHtml.Replace(wxT("±"), wxT("&plusmn;"), true);
strEncodedHtml.Replace(wxT("²"), wxT("&sup2;"), true);
strEncodedHtml.Replace(wxT("³"), wxT("&sup3;"), true);
strEncodedHtml.Replace(wxT("´"), wxT("&acute;"), true);
strEncodedHtml.Replace(wxT("µ"), wxT("&micro;"), true);
strEncodedHtml.Replace(wxT(""), wxT("&para;"), true);
strEncodedHtml.Replace(wxT("·"), wxT("&middot;"), true);
strEncodedHtml.Replace(wxT("¸"), wxT("&cedil;"), true);
strEncodedHtml.Replace(wxT("¹"), wxT("&sup1;"), true);
strEncodedHtml.Replace(wxT("º"), wxT("&ordm;"), true);
strEncodedHtml.Replace(wxT("»"), wxT("&raquo;"), true);
strEncodedHtml.Replace(wxT("¼"), wxT("&frac14;"), true);
strEncodedHtml.Replace(wxT("½"), wxT("&frac12;"), true);
strEncodedHtml.Replace(wxT("¾"), wxT("&frac34;"), true);
strEncodedHtml.Replace(wxT("¿"), wxT("&iquest;"), true);
strEncodedHtml.Replace(wxT("À"), wxT("&Agrave;"), true);
strEncodedHtml.Replace(wxT("Á"), wxT("&Aacute;"), true);
strEncodedHtml.Replace(wxT("Â"), wxT("&Acirc;"), true);
strEncodedHtml.Replace(wxT("Ã"), wxT("&Atilde;"), true);
strEncodedHtml.Replace(wxT("Ä"), wxT("&Auml;"), true);
strEncodedHtml.Replace(wxT("Å"), wxT("&Aring;"), true);
strEncodedHtml.Replace(wxT("Æ"), wxT("&AElig;"), true);
strEncodedHtml.Replace(wxT("Ç"), wxT("&Ccedil;"), true);
strEncodedHtml.Replace(wxT("È"), wxT("&Egrave;"), true);
strEncodedHtml.Replace(wxT("É"), wxT("&Eacute;"), true);
strEncodedHtml.Replace(wxT("Ê"), wxT("&Ecirc;"), true);
strEncodedHtml.Replace(wxT("Ë"), wxT("&Euml;"), true);
strEncodedHtml.Replace(wxT("Ì"), wxT("&Igrave;"), true);
strEncodedHtml.Replace(wxT("Í"), wxT("&Iacute;"), true);
strEncodedHtml.Replace(wxT("Î"), wxT("&Icirc;"), true);
strEncodedHtml.Replace(wxT("Ï"), wxT("&Iuml;"), true);
strEncodedHtml.Replace(wxT("Ð"), wxT("&ETH;"), true);
strEncodedHtml.Replace(wxT("Ñ"), wxT("&Ntilde;"), true);
strEncodedHtml.Replace(wxT("Ò"), wxT("&Ograve;"), true);
strEncodedHtml.Replace(wxT("Ó"), wxT("&Oacute;"), true);
strEncodedHtml.Replace(wxT("Ô"), wxT("&Ocirc;"), true);
strEncodedHtml.Replace(wxT("Õ"), wxT("&Otilde;"), true);
strEncodedHtml.Replace(wxT("Ö"), wxT("&Ouml;"), true);
strEncodedHtml.Replace(wxT("×"), wxT("&times;"), true);
strEncodedHtml.Replace(wxT("Ø"), wxT("&Oslash;"), true);
strEncodedHtml.Replace(wxT("Ù"), wxT("&Ugrave;"), true);
strEncodedHtml.Replace(wxT("Ú"), wxT("&Uacute;"), true);
strEncodedHtml.Replace(wxT("Û"), wxT("&Ucirc;"), true);
strEncodedHtml.Replace(wxT("Ü"), wxT("&Uuml;"), true);
strEncodedHtml.Replace(wxT("Ý"), wxT("&Yacute;"), true);
strEncodedHtml.Replace(wxT("Þ"), wxT("&THORN;"), true);
strEncodedHtml.Replace(wxT("ß"), wxT("&szlig;"), true);
strEncodedHtml.Replace(wxT("à"), wxT("&agrave;"), true);
strEncodedHtml.Replace(wxT("á"), wxT("&aacute;"), true);
strEncodedHtml.Replace(wxT("â"), wxT("&acirc;"), true);
strEncodedHtml.Replace(wxT("ã"), wxT("&atilde;"), true);
strEncodedHtml.Replace(wxT("ä"), wxT("&auml;"), true);
strEncodedHtml.Replace(wxT("å"), wxT("&aring;"), true);
strEncodedHtml.Replace(wxT("æ"), wxT("&aelig;"), true);
strEncodedHtml.Replace(wxT("ç"), wxT("&ccedil;"), true);
strEncodedHtml.Replace(wxT("è"), wxT("&egrave;"), true);
strEncodedHtml.Replace(wxT("é"), wxT("&eacute;"), true);
strEncodedHtml.Replace(wxT("ê"), wxT("&ecirc;"), true);
strEncodedHtml.Replace(wxT("ë"), wxT("&euml;"), true);
strEncodedHtml.Replace(wxT("ì"), wxT("&igrave;"), true);
strEncodedHtml.Replace(wxT("í"), wxT("&iacute;"), true);
strEncodedHtml.Replace(wxT("î"), wxT("&icirc;"), true);
strEncodedHtml.Replace(wxT("ï"), wxT("&iuml;"), true);
strEncodedHtml.Replace(wxT("ð"), wxT("&eth;"), true);
strEncodedHtml.Replace(wxT("ñ"), wxT("&ntilde;"), true);
strEncodedHtml.Replace(wxT("ò"), wxT("&ograve;"), true);
strEncodedHtml.Replace(wxT("ó"), wxT("&oacute;"), true);
strEncodedHtml.Replace(wxT("ô"), wxT("&ocirc;"), true);
strEncodedHtml.Replace(wxT("õ"), wxT("&otilde;"), true);
strEncodedHtml.Replace(wxT("ö"), wxT("&ouml;"), true);
strEncodedHtml.Replace(wxT("÷"), wxT("&divide;"), true);
strEncodedHtml.Replace(wxT("ø"), wxT("&oslash;"), true);
strEncodedHtml.Replace(wxT("ù"), wxT("&ugrave;"), true);
strEncodedHtml.Replace(wxT("ú"), wxT("&uacute;"), true);
strEncodedHtml.Replace(wxT("û"), wxT("&ucirc;"), true);
strEncodedHtml.Replace(wxT("ü"), wxT("&uuml;"), true);
strEncodedHtml.Replace(wxT("ý"), wxT("&yacute;"), true);
strEncodedHtml.Replace(wxT("þ"), wxT("&thorn;"), true);
strEncodedHtml.Replace(wxT("ÿ"), wxT("&yuml;"), true);
#endif
return strEncodedHtml;
}
wxString CBOINCBaseView::HtmlEntityDecode(wxString strRaw) {
wxString strDecodedHtml(strRaw);
if (0 <= strDecodedHtml.Find(wxT("&"))) {
#ifdef __WXMSW__
strDecodedHtml.Replace(wxT("&amp;"), wxT("&"), true);
strDecodedHtml.Replace(wxT("&quot;"), wxT("\""), true);
strDecodedHtml.Replace(wxT("&lt;"), wxT("<"), true);
strDecodedHtml.Replace(wxT("&gt;"), wxT(">"), true);
strDecodedHtml.Replace(wxT("&sbquo;"), wxT(""), true);
strDecodedHtml.Replace(wxT("&fnof;"), wxT("ƒ"), true);
strDecodedHtml.Replace(wxT("&bdquo;"), wxT(""), true);
strDecodedHtml.Replace(wxT("&hellip;"), wxT(""), true);
strDecodedHtml.Replace(wxT("&dagger;"), wxT(""), true);
strDecodedHtml.Replace(wxT("&Dagger;"), wxT(""), true);
strDecodedHtml.Replace(wxT("&Scaron;"), wxT("Š"), true);
strDecodedHtml.Replace(wxT("&OElig;"), wxT("Œ"), true);
strDecodedHtml.Replace(wxT("&lsquo;"), wxT(""), true);
strDecodedHtml.Replace(wxT("&rsquo;"), wxT(""), true);
strDecodedHtml.Replace(wxT("&ldquo;"), wxT(""), true);
strDecodedHtml.Replace(wxT("&rdquo;"), wxT(""), true);
strDecodedHtml.Replace(wxT("&bull;"), wxT(""), true);
strDecodedHtml.Replace(wxT("&ndash;"), wxT(""), true);
strDecodedHtml.Replace(wxT("&mdash;"), wxT(""), true);
strDecodedHtml.Replace(wxT("&tilde;"), wxT("˜˜~"), true);
strDecodedHtml.Replace(wxT("&trade;"), wxT(""), true);
strDecodedHtml.Replace(wxT("&scaron;"), wxT("š"), true);
strDecodedHtml.Replace(wxT("&oelig;"), wxT("œ"), true);
strDecodedHtml.Replace(wxT("&Yuml;"), wxT("Ÿ"), true);
strDecodedHtml.Replace(wxT("&iexcl;"), wxT("¡"), true);
strDecodedHtml.Replace(wxT("&cent;"), wxT("¢"), true);
strDecodedHtml.Replace(wxT("&pound;"), wxT("£"), true);
strDecodedHtml.Replace(wxT("&curren;"), wxT("¤"), true);
strDecodedHtml.Replace(wxT("&yen;"), wxT("¥"), true);
strDecodedHtml.Replace(wxT("&brvbar;"), wxT("¦"), true);
strDecodedHtml.Replace(wxT("&sect;"), wxT("§"), true);
strDecodedHtml.Replace(wxT("&uml;"), wxT("¨"), true);
strDecodedHtml.Replace(wxT("&copy;"), wxT("©"), true);
strDecodedHtml.Replace(wxT("&ordf;"), wxT("ª"), true);
strDecodedHtml.Replace(wxT("&laquo;"), wxT("«"), true);
strDecodedHtml.Replace(wxT("&not;"), wxT("¬"), true);
strDecodedHtml.Replace(wxT("&reg;"), wxT("®"), true);
strDecodedHtml.Replace(wxT("&macr;"), wxT("¯"), true);
strDecodedHtml.Replace(wxT("&deg;"), wxT("°"), true);
strDecodedHtml.Replace(wxT("&plusmn;"), wxT("±"), true);
strDecodedHtml.Replace(wxT("&sup2;"), wxT("²"), true);
strDecodedHtml.Replace(wxT("&sup3;"), wxT("³"), true);
strDecodedHtml.Replace(wxT("&acute;"), wxT("´"), true);
strDecodedHtml.Replace(wxT("&micro;"), wxT("µ"), true);
strDecodedHtml.Replace(wxT("&para;"), wxT(""), true);
strDecodedHtml.Replace(wxT("&middot;"), wxT("·"), true);
strDecodedHtml.Replace(wxT("&cedil;"), wxT("¸"), true);
strDecodedHtml.Replace(wxT("&sup1;"), wxT("¹"), true);
strDecodedHtml.Replace(wxT("&ordm;"), wxT("º"), true);
strDecodedHtml.Replace(wxT("&raquo;"), wxT("»"), true);
strDecodedHtml.Replace(wxT("&frac14;"), wxT("¼"), true);
strDecodedHtml.Replace(wxT("&frac12;"), wxT("½"), true);
strDecodedHtml.Replace(wxT("&frac34;"), wxT("¾"), true);
strDecodedHtml.Replace(wxT("&iquest;"), wxT("¿"), true);
strDecodedHtml.Replace(wxT("&Agrave;"), wxT("À"), true);
strDecodedHtml.Replace(wxT("&Aacute;"), wxT("Á"), true);
strDecodedHtml.Replace(wxT("&Acirc;"), wxT("Â"), true);
strDecodedHtml.Replace(wxT("&Atilde;"), wxT("Ã"), true);
strDecodedHtml.Replace(wxT("&Auml;"), wxT("Ä"), true);
strDecodedHtml.Replace(wxT("&Aring;"), wxT("Å"), true);
strDecodedHtml.Replace(wxT("&AElig;"), wxT("Æ"), true);
strDecodedHtml.Replace(wxT("&Ccedil;"), wxT("Ç"), true);
strDecodedHtml.Replace(wxT("&Egrave;"), wxT("È"), true);
strDecodedHtml.Replace(wxT("&Eacute;"), wxT("É"), true);
strDecodedHtml.Replace(wxT("&Ecirc;"), wxT("Ê"), true);
strDecodedHtml.Replace(wxT("&Euml;"), wxT("Ë"), true);
strDecodedHtml.Replace(wxT("&Igrave;"), wxT("Ì"), true);
strDecodedHtml.Replace(wxT("&Iacute;"), wxT("Í"), true);
strDecodedHtml.Replace(wxT("&Icirc;"), wxT("Î"), true);
strDecodedHtml.Replace(wxT("&Iuml;"), wxT("Ï"), true);
strDecodedHtml.Replace(wxT("&ETH;"), wxT("Ð"), true);
strDecodedHtml.Replace(wxT("&Ntilde;"), wxT("Ñ"), true);
strDecodedHtml.Replace(wxT("&Ograve;"), wxT("Ò"), true);
strDecodedHtml.Replace(wxT("&Oacute;"), wxT("Ó"), true);
strDecodedHtml.Replace(wxT("&Ocirc;"), wxT("Ô"), true);
strDecodedHtml.Replace(wxT("&Otilde;"), wxT("Õ"), true);
strDecodedHtml.Replace(wxT("&Ouml;"), wxT("Ö"), true);
strDecodedHtml.Replace(wxT("&times;"), wxT("×"), true);
strDecodedHtml.Replace(wxT("&Oslash;"), wxT("Ø"), true);
strDecodedHtml.Replace(wxT("&Ugrave;"), wxT("Ù"), true);
strDecodedHtml.Replace(wxT("&Uacute;"), wxT("Ú"), true);
strDecodedHtml.Replace(wxT("&Ucirc;"), wxT("Û"), true);
strDecodedHtml.Replace(wxT("&Uuml;"), wxT("Ü"), true);
strDecodedHtml.Replace(wxT("&Yacute;"), wxT("Ý"), true);
strDecodedHtml.Replace(wxT("&THORN;"), wxT("Þ"), true);
strDecodedHtml.Replace(wxT("&szlig;"), wxT("ß"), true);
strDecodedHtml.Replace(wxT("&agrave;"), wxT("à"), true);
strDecodedHtml.Replace(wxT("&aacute;"), wxT("á"), true);
strDecodedHtml.Replace(wxT("&acirc;"), wxT("â"), true);
strDecodedHtml.Replace(wxT("&atilde;"), wxT("ã"), true);
strDecodedHtml.Replace(wxT("&auml;"), wxT("ä"), true);
strDecodedHtml.Replace(wxT("&aring;"), wxT("å"), true);
strDecodedHtml.Replace(wxT("&aelig;"), wxT("æ"), true);
strDecodedHtml.Replace(wxT("&ccedil;"), wxT("ç"), true);
strDecodedHtml.Replace(wxT("&egrave;"), wxT("è"), true);
strDecodedHtml.Replace(wxT("&eacute;"), wxT("é"), true);
strDecodedHtml.Replace(wxT("&ecirc;"), wxT("ê"), true);
strDecodedHtml.Replace(wxT("&euml;"), wxT("ë"), true);
strDecodedHtml.Replace(wxT("&igrave;"), wxT("ì"), true);
strDecodedHtml.Replace(wxT("&iacute;"), wxT("í"), true);
strDecodedHtml.Replace(wxT("&icirc;"), wxT("î"), true);
strDecodedHtml.Replace(wxT("&iuml;"), wxT("ï"), true);
strDecodedHtml.Replace(wxT("&eth;"), wxT("ð"), true);
strDecodedHtml.Replace(wxT("&ntilde;"), wxT("ñ"), true);
strDecodedHtml.Replace(wxT("&ograve;"), wxT("ò"), true);
strDecodedHtml.Replace(wxT("&oacute;"), wxT("ó"), true);
strDecodedHtml.Replace(wxT("&ocirc;"), wxT("ô"), true);
strDecodedHtml.Replace(wxT("&otilde;"), wxT("õ"), true);
strDecodedHtml.Replace(wxT("&ouml;"), wxT("ö"), true);
strDecodedHtml.Replace(wxT("&divide;"), wxT("÷"), true);
strDecodedHtml.Replace(wxT("&oslash;"), wxT("ø"), true);
strDecodedHtml.Replace(wxT("&ugrave;"), wxT("ù"), true);
strDecodedHtml.Replace(wxT("&uacute;"), wxT("ú"), true);
strDecodedHtml.Replace(wxT("&ucirc;"), wxT("û"), true);
strDecodedHtml.Replace(wxT("&uuml;"), wxT("ü"), true);
strDecodedHtml.Replace(wxT("&yacute;"), wxT("ý"), true);
strDecodedHtml.Replace(wxT("&thorn;"), wxT("þ"), true);
strDecodedHtml.Replace(wxT("&yuml;"), wxT("ÿ"), true);
#endif
}
return strDecodedHtml;
}