1 // This file is part of BOINC.
2 // http://boinc.berkeley.edu
3 // Copyright (C) 2015 University of California
4 //
5 // BOINC is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU Lesser General Public License
7 // as published by the Free Software Foundation,
8 // either version 3 of the License, or (at your option) any later version.
9 //
10 // BOINC is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 // See the GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with BOINC. If not, see <http://www.gnu.org/licenses/>.
17
18 #if defined(__GNUG__) && !defined(__APPLE__)
19 #pragma implementation "BOINCBaseView.h"
20 #endif
21
22 #include "stdwx.h"
23 #include "BOINCGUIApp.h"
24 #include "MainDocument.h"
25 #include "BOINCBaseView.h"
26 #include "BOINCTaskCtrl.h"
27 #include "BOINCListCtrl.h"
28 #include "Events.h"
29
30 #include "res/boinc.xpm"
31 #include "res/sortascending.xpm"
32 #include "res/sortdescending.xpm"
33
34
IMPLEMENT_DYNAMIC_CLASS(CBOINCBaseView,wxPanel)35 IMPLEMENT_DYNAMIC_CLASS(CBOINCBaseView, wxPanel)
36
37 CBOINCBaseView::CBOINCBaseView() {}
38
CBOINCBaseView(wxNotebook * pNotebook)39 CBOINCBaseView::CBOINCBaseView(wxNotebook* pNotebook) :
40 wxPanel(pNotebook, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL)
41 {
42 m_bProcessingTaskRenderEvent = false;
43 m_bProcessingListRenderEvent = false;
44
45 m_bForceUpdateSelection = true;
46 m_bIgnoreUIEvents = false;
47 m_bNeedSort = false;
48
49 m_iPreviousSelectionCount = 0;
50 m_lPreviousFirstSelection = -1;
51
52 //
53 // Setup View
54 //
55 m_pTaskPane = NULL;
56 m_pListPane = NULL;
57 m_iProgressColumn = -1;
58 m_iSortColumnID = -1;
59 m_SortArrows = NULL;
60
61 m_aStdColNameOrder = NULL;
62 m_iDefaultShownColumns = NULL;
63 m_iNumDefaultShownColumns = 0;
64
65 SetName(GetViewName());
66 SetAutoLayout(TRUE);
67 }
68
69
CBOINCBaseView(wxNotebook * pNotebook,wxWindowID iTaskWindowID,int iTaskWindowFlags,wxWindowID iListWindowID,int iListWindowFlags)70 CBOINCBaseView::CBOINCBaseView(wxNotebook* pNotebook, wxWindowID iTaskWindowID, int iTaskWindowFlags, wxWindowID iListWindowID, int iListWindowFlags) :
71 wxPanel(pNotebook, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL)
72 {
73 m_bProcessingTaskRenderEvent = false;
74 m_bProcessingListRenderEvent = false;
75
76 m_bForceUpdateSelection = true;
77 m_bIgnoreUIEvents = false;
78
79 m_iPreviousSelectionCount = 0;
80 m_lPreviousFirstSelection = -1;
81
82 //
83 // Setup View
84 //
85 m_pTaskPane = NULL;
86 m_pListPane = NULL;
87
88 SetName(GetViewName());
89 SetAutoLayout(TRUE);
90
91 wxFlexGridSizer* itemFlexGridSizer = new wxFlexGridSizer(2, 0, 0);
92 wxASSERT(itemFlexGridSizer);
93
94 itemFlexGridSizer->AddGrowableRow(0);
95 itemFlexGridSizer->AddGrowableCol(1);
96
97 m_pTaskPane = new CBOINCTaskCtrl(this, iTaskWindowID, iTaskWindowFlags);
98 wxASSERT(m_pTaskPane);
99
100 m_pListPane = new CBOINCListCtrl(this, iListWindowID, iListWindowFlags);
101 wxASSERT(m_pListPane);
102
103 itemFlexGridSizer->Add(m_pTaskPane, 1, wxGROW|wxALL, 1);
104 itemFlexGridSizer->Add(m_pListPane, 1, wxGROW|wxALL, 1);
105
106 SetSizer(itemFlexGridSizer);
107
108 UpdateSelection();
109
110 m_iProgressColumn = -1;
111 m_iSortColumnID = -1;
112 m_bReverseSort = false;
113
114 m_SortArrows = new wxImageList(16, 16, true);
115 m_SortArrows->Add( wxIcon( sortascending_xpm ) );
116 m_SortArrows->Add( wxIcon( sortdescending_xpm ) );
117 m_pListPane->SetImageList(m_SortArrows, wxIMAGE_LIST_SMALL);
118
119 m_aStdColNameOrder = NULL;
120 m_iDefaultShownColumns = NULL;
121 m_iNumDefaultShownColumns = 0;
122 }
123
124
~CBOINCBaseView()125 CBOINCBaseView::~CBOINCBaseView() {
126 if (m_SortArrows) {
127 delete m_SortArrows;
128 }
129 m_arrSelectedKeys1.Clear();
130 m_arrSelectedKeys2.Clear();
131 m_iSortedIndexes.Clear();
132 if (m_aStdColNameOrder) {
133 delete m_aStdColNameOrder;
134 }
135 }
136
137
138 // The name of the view.
139 // If it has not been defined by the view "Undefined" is returned.
140 //
GetViewName()141 wxString& CBOINCBaseView::GetViewName() {
142 static wxString strViewName(wxT("Undefined"));
143 return strViewName;
144 }
145
146
147 // The user friendly name of the view.
148 // If it has not been defined by the view "Undefined" is returned.
149 //
GetViewDisplayName()150 wxString& CBOINCBaseView::GetViewDisplayName() {
151 static wxString strViewName(wxT("Undefined"));
152 return strViewName;
153 }
154
155
156 // The user friendly icon of the view.
157 // If it has not been defined by the view the BOINC icon is returned.
158 //
GetViewIcon()159 const char** CBOINCBaseView::GetViewIcon() {
160 wxASSERT(boinc_xpm);
161 return boinc_xpm;
162 }
163
164
165 // The rate at which the view is refreshed.
166 // If it has not been defined by the view 1 second is retrned.
167 //
GetViewRefreshRate()168 int CBOINCBaseView::GetViewRefreshRate() {
169 return 1;
170 }
171
172
173 // Get bit mask of current view(s).
174 //
GetViewCurrentViewPage()175 int CBOINCBaseView::GetViewCurrentViewPage() {
176 return 0;
177 }
178
179
GetKeyValue1(int)180 wxString CBOINCBaseView::GetKeyValue1(int) {
181 return wxEmptyString;
182 }
183
184
GetKeyValue2(int)185 wxString CBOINCBaseView::GetKeyValue2(int) {
186 return wxEmptyString;
187 }
188
189
FindRowIndexByKeyValues(wxString &,wxString &)190 int CBOINCBaseView::FindRowIndexByKeyValues(wxString&, wxString&) {
191 return -1;
192 }
193
194
FireOnSaveState(wxConfigBase * pConfig)195 bool CBOINCBaseView::FireOnSaveState(wxConfigBase* pConfig) {
196 return OnSaveState(pConfig);
197 }
198
199
FireOnRestoreState(wxConfigBase * pConfig)200 bool CBOINCBaseView::FireOnRestoreState(wxConfigBase* pConfig) {
201 return OnRestoreState(pConfig);
202 }
203
204
GetListRowCount()205 int CBOINCBaseView::GetListRowCount() {
206 wxASSERT(m_pListPane);
207 return m_pListPane->GetItemCount();
208 }
209
210
FireOnListRender(wxTimerEvent & event)211 void CBOINCBaseView::FireOnListRender(wxTimerEvent& event) {
212 OnListRender(event);
213 }
214
215
FireOnListSelected(wxListEvent & event)216 void CBOINCBaseView::FireOnListSelected(wxListEvent& event) {
217 OnListSelected(event);
218 }
219
220
FireOnListDeselected(wxListEvent & event)221 void CBOINCBaseView::FireOnListDeselected(wxListEvent& event) {
222 OnListDeselected(event);
223 }
224
225
FireOnListGetItemText(long item,long column) const226 wxString CBOINCBaseView::FireOnListGetItemText(long item, long column) const {
227 return OnListGetItemText(item, column);
228 }
229
230
FireOnListGetItemImage(long item) const231 int CBOINCBaseView::FireOnListGetItemImage(long item) const {
232 return OnListGetItemImage(item);
233 }
234
235
OnListRender(wxTimerEvent & event)236 void CBOINCBaseView::OnListRender(wxTimerEvent& event) {
237 if (!m_bProcessingListRenderEvent) {
238 m_bProcessingListRenderEvent = true;
239
240 wxASSERT(m_pListPane);
241
242 // Remember the key values of currently selected items
243 SaveSelections();
244
245 int iDocCount = GetDocCount();
246 int iCacheCount = GetCacheCount();
247 if (iDocCount != iCacheCount) {
248 if (0 >= iDocCount) {
249 EmptyCache();
250 m_pListPane->DeleteAllItems();
251 } else {
252 int iIndex = 0;
253 int iReturnValue = -1;
254 if (iDocCount > iCacheCount) {
255 for (iIndex = 0; iIndex < (iDocCount - iCacheCount); iIndex++) {
256 iReturnValue = AddCacheElement();
257 wxASSERT(!iReturnValue);
258 }
259 wxASSERT(GetDocCount() == GetCacheCount());
260 m_pListPane->SetItemCount(iDocCount);
261 m_bNeedSort = true;
262 } else {
263 // The virtual ListCtrl keeps a separate its list of selected rows;
264 // make sure it does not reference any rows beyond the new last row.
265 // We can ClearSelections() because we called SaveSelections() above.
266 ClearSelections();
267 m_pListPane->SetItemCount(iDocCount);
268 for (iIndex = (iCacheCount - 1); iIndex >= iDocCount; --iIndex) {
269 iReturnValue = RemoveCacheElement();
270 wxASSERT(!iReturnValue);
271 }
272 wxASSERT(GetDocCount() == GetCacheCount());
273 //fprintf(stderr, "CBOINCBaseView::OnListRender(): m_pListPane->RefreshItems(0, %d)\n", iDocCount - 1);
274 m_pListPane->RefreshItems(0, iDocCount - 1);
275 #ifdef __WXGTK__
276 // Work around an apparent bug in wxWidgets 3.0
277 // which drew blank lines at the top and failed
278 // to draw the bottom items. This could happen
279 // if the list was scrolled near the bottom and
280 // the user selected "Show active tasks."
281 m_pListPane->EnsureVisible(iDocCount - 1);
282 #endif
283 m_bNeedSort = true;
284 }
285 }
286 }
287
288 if (iDocCount > 0) {
289 SynchronizeCache();
290 if (iDocCount > 1) {
291 if (_EnsureLastItemVisible() && (iDocCount != iCacheCount)) {
292 m_pListPane->EnsureVisible(iDocCount - 1);
293 }
294 }
295 }
296
297 // Find the previously selected items by their key values and reselect them
298 RestoreSelections();
299
300 UpdateSelection();
301
302 m_bProcessingListRenderEvent = false;
303 }
304
305 event.Skip();
306 }
307
308
OnSaveState(wxConfigBase * pConfig)309 bool CBOINCBaseView::OnSaveState(wxConfigBase* pConfig) {
310 bool bReturnValue = true;
311
312 wxASSERT(pConfig);
313 wxASSERT(m_pTaskPane);
314 wxASSERT(m_pListPane);
315
316 if (!m_pTaskPane->OnSaveState(pConfig)) {
317 bReturnValue = false;
318 }
319
320 if (!m_pListPane->OnSaveState(pConfig)) {
321 bReturnValue = false;
322 }
323 return bReturnValue;
324 }
325
326
OnRestoreState(wxConfigBase * pConfig)327 bool CBOINCBaseView::OnRestoreState(wxConfigBase* pConfig) {
328 wxASSERT(pConfig);
329 wxASSERT(m_pTaskPane);
330 wxASSERT(m_pListPane);
331
332 if (!m_pTaskPane->OnRestoreState(pConfig)) {
333 return false;
334 }
335
336 if (!m_pListPane->OnRestoreState(pConfig)) {
337 return false;
338 }
339 return true;
340 }
341
342
343 // We don't use this because multiple selection virtual
344 // wxListCtrl does not generate selection events for
345 // shift-click; see OnCheckSelectionChanged() below.
OnListSelected(wxListEvent & event)346 void CBOINCBaseView::OnListSelected(wxListEvent& event) {
347 wxLogTrace(wxT("Function Start/End"), wxT("CBOINCBaseView::OnListSelected - Function Begin"));
348
349 if (!m_bIgnoreUIEvents) {
350 m_bForceUpdateSelection = true;
351 UpdateSelection();
352 event.Skip();
353 }
354
355 wxLogTrace(wxT("Function Start/End"), wxT("CBOINCBaseView::OnListSelected - Function End"));
356 }
357
358
359 // We don't use this because multiple selection virtual
360 // wxListCtrl does generates deselection events only for
361 // control-click; see OnCheckSelectionChanged() below.
OnListDeselected(wxListEvent & event)362 void CBOINCBaseView::OnListDeselected(wxListEvent& event) {
363 wxLogTrace(wxT("Function Start/End"), wxT("CBOINCBaseView::OnListDeselected - Function Begin"));
364
365 if (!m_bIgnoreUIEvents) {
366 m_bForceUpdateSelection = true;
367 UpdateSelection();
368 event.Skip();
369 }
370
371 wxLogTrace(wxT("Function Start/End"), wxT("CBOINCBaseView::OnListDeselected - Function End"));
372 }
373
374
OnCheckSelectionChanged(CCheckSelectionChangedEvent &)375 void CBOINCBaseView::OnCheckSelectionChanged(CCheckSelectionChangedEvent& ) {
376 CheckSelectionChanged();
377 }
378
379
OnCacheHint(wxListEvent &)380 void CBOINCBaseView::OnCacheHint(wxListEvent& ) {
381 CheckSelectionChanged();
382 }
383
384
385 // Work around features in multiple selection virtual wxListCtrl:
386 // * It does not send deselection events (except ctrl-click).
387 // * It does not send selection events if you add to selection
388 // using Shift_Click.
389 //
390 // We currently handle all selections and deselections here.
391 // On the Mac, this is called due to an event posted by CBOINCListCtrl::OnMouseDown().
392 // On Windows, it is called due to a EVT_LIST_CACHE_HINT from wxListCtrl.
CheckSelectionChanged()393 void CBOINCBaseView::CheckSelectionChanged() {
394 int newSelectionCount = m_pListPane->GetSelectedItemCount();
395 long currentSelection = m_pListPane->GetFirstSelected();
396
397 if ((newSelectionCount != m_iPreviousSelectionCount) ||
398 (currentSelection != m_lPreviousFirstSelection)
399 ) {
400 if (!m_bIgnoreUIEvents) {
401 m_bForceUpdateSelection = true;
402 UpdateSelection();
403 }
404 }
405
406 m_iPreviousSelectionCount = newSelectionCount;
407 m_lPreviousFirstSelection = currentSelection;
408 }
409
410
OnListGetItemText(long WXUNUSED (item),long WXUNUSED (column)) const411 wxString CBOINCBaseView::OnListGetItemText(long WXUNUSED(item), long WXUNUSED(column)) const {
412 return wxString(wxT("Undefined"));
413 }
414
415
OnListGetItemImage(long WXUNUSED (item)) const416 int CBOINCBaseView::OnListGetItemImage(long WXUNUSED(item)) const {
417 return -1;
418 }
419
420
GetDocCount()421 int CBOINCBaseView::GetDocCount() {
422 return 0;
423 }
424
425
OnDocGetItemImage(long WXUNUSED (item)) const426 wxString CBOINCBaseView::OnDocGetItemImage(long WXUNUSED(item)) const {
427 return wxString(wxT("Undefined"));
428 }
429
430
OnDocGetItemAttr(long WXUNUSED (item)) const431 wxString CBOINCBaseView::OnDocGetItemAttr(long WXUNUSED(item)) const {
432 return wxString(wxT("Undefined"));
433 }
434
435
AddCacheElement()436 int CBOINCBaseView::AddCacheElement() {
437 return -1;
438 }
439
440
EmptyCache()441 int CBOINCBaseView::EmptyCache() {
442 return -1;
443 }
444
445
GetCacheCount()446 int CBOINCBaseView::GetCacheCount() {
447 return -1;
448 }
449
450
RemoveCacheElement()451 int CBOINCBaseView::RemoveCacheElement() {
452 return -1;
453 }
454
455
SynchronizeCache()456 int CBOINCBaseView::SynchronizeCache() {
457 int iRowIndex = 0;
458 int iRowTotal = 0;
459 int iColumnIndex = 0;
460 int iColumnTotal = 0;
461 bool bNeedRefreshData = false;
462
463 iRowTotal = GetDocCount();
464 iColumnTotal = m_pListPane->GetColumnCount();
465
466 for (iRowIndex = 0; iRowIndex < iRowTotal; iRowIndex++) {
467 bNeedRefreshData = false;
468
469 for (iColumnIndex = 0; iColumnIndex < iColumnTotal; iColumnIndex++) {
470 if (SynchronizeCacheItem(iRowIndex, iColumnIndex)) {
471 #ifdef __WXMAC__
472 bNeedRefreshData = true;
473 #else
474 // To reduce flicker, refresh only changed columns
475 m_pListPane->RefreshCell(iRowIndex, iColumnIndex);
476 #endif
477 if (iColumnIndex >= 0) {
478 if (m_iColumnIndexToColumnID[iColumnIndex] == m_iSortColumnID) {
479 m_bNeedSort = true;
480 }
481 }
482 }
483 }
484
485 // Mac is double-buffered to avoid flicker, so this is more efficient
486 if (bNeedRefreshData) {
487 m_pListPane->RefreshItem(iRowIndex);
488 }
489 }
490
491 if (m_bNeedSort) {
492 sortData(); // Will mark moved items as needing refresh
493 m_bNeedSort = false;
494 }
495
496 return 0;
497 }
498
499
SynchronizeCacheItem(wxInt32 WXUNUSED (iRowIndex),wxInt32 WXUNUSED (iColumnIndex))500 bool CBOINCBaseView::SynchronizeCacheItem(wxInt32 WXUNUSED(iRowIndex), wxInt32 WXUNUSED(iColumnIndex)) {
501 return false;
502 }
503
504
OnColClick(wxListEvent & event)505 void CBOINCBaseView::OnColClick(wxListEvent& event) {
506 wxListItem item;
507 int newSortColIndex = event.GetColumn();
508 int oldSortColIndex = -1;
509
510 if (newSortColIndex < 0) return; // Clicked past last column
511
512 if (m_iSortColumnID >= 0) {
513 oldSortColIndex = m_iColumnIDToColumnIndex[m_iSortColumnID];
514 }
515
516 item.SetMask(wxLIST_MASK_IMAGE);
517 if (newSortColIndex == oldSortColIndex) {
518 m_bReverseSort = !m_bReverseSort;
519 SetSortColumn(newSortColIndex);
520 } else {
521 // Remove sort arrow from old sort column
522
523 if (oldSortColIndex >= 0) {
524 item.SetImage(-1);
525 m_pListPane->SetColumn(oldSortColIndex, item);
526 }
527 m_iSortColumnID = m_iColumnIndexToColumnID[newSortColIndex];
528 m_bReverseSort = false;
529
530 SetSortColumn(newSortColIndex);
531 }
532
533 // Write the change to the registry
534 // Do this here because SetListColumnOrder() can call SetSortColumn()
535 // even when neither m_iSortColumnID nor m_bReverseSort changes
536 wxConfigBase* pConfig = wxConfigBase::Get(false);
537 pConfig->SetPath(wxT("/") + GetViewName());
538 m_pListPane->OnSaveState(pConfig);
539 }
540
SetSortColumn(int newSortColIndex)541 void CBOINCBaseView::SetSortColumn(int newSortColIndex) {
542 wxListItem item;
543 int i, j, m;
544 wxArrayInt selections;
545
546 item.SetImage(m_bReverseSort ? 0 : 1);
547 m_pListPane->SetColumn(newSortColIndex, item);
548
549 Freeze(); // To reduce flicker
550 // Remember which cache elements are selected and deselect them
551 m_bIgnoreUIEvents = true;
552 i = -1;
553 while (1) {
554 i = m_pListPane->GetNextSelected(i);
555 if (i < 0) break;
556 selections.Add(m_iSortedIndexes[i]);
557 m_pListPane->SelectRow(i, false);
558 }
559
560 sortData();
561
562 // Reselect previously selected cache elements in the sorted list
563 m = (int)selections.GetCount();
564 for (i=0; i<m; i++) {
565 if (selections[i] >= 0) {
566 j = m_iSortedIndexes.Index(selections[i]);
567 m_pListPane->SelectRow(j, true);
568 }
569 }
570 m_bIgnoreUIEvents = false;
571
572 Thaw();
573 }
574
575
InitSort()576 void CBOINCBaseView::InitSort() {
577 wxListItem item;
578
579 if (m_iSortColumnID < 0) return;
580 int newSortColIndex = m_iColumnIDToColumnIndex[m_iSortColumnID];
581 if (newSortColIndex < 0) return;
582
583 item.SetMask(wxLIST_MASK_IMAGE);
584 item.SetImage(m_bReverseSort ? 0 : 1);
585 m_pListPane->SetColumn(newSortColIndex, item);
586 Freeze(); // To reduce flicker
587 sortData();
588 Thaw();
589 }
590
591
sortData()592 void CBOINCBaseView::sortData() {
593 if (m_iSortColumnID < 0) return;
594 if (m_iColumnIDToColumnIndex[m_iSortColumnID] < 0) return;
595
596 wxArrayInt oldSortedIndexes(m_iSortedIndexes);
597 int i, n = (int)m_iSortedIndexes.GetCount();
598
599 std::stable_sort(m_iSortedIndexes.begin(), m_iSortedIndexes.end(), m_funcSortCompare);
600
601 // Refresh rows which have moved
602 for (i=0; i<n; i++) {
603 if (m_iSortedIndexes[i] != oldSortedIndexes[i]) {
604 m_pListPane->RefreshItem(i);
605 }
606 }
607 }
608
609
EmptyTasks()610 void CBOINCBaseView::EmptyTasks() {
611 unsigned int i;
612 unsigned int j;
613 for (i=0; i<m_TaskGroups.size(); i++) {
614 for (j=0; j<m_TaskGroups[i]->m_Tasks.size(); j++) {
615 delete m_TaskGroups[i]->m_Tasks[j];
616 }
617 m_TaskGroups[i]->m_Tasks.clear();
618 delete m_TaskGroups[i];
619 }
620 m_TaskGroups.clear();
621 }
622
623
ClearSavedSelections()624 void CBOINCBaseView::ClearSavedSelections() {
625 m_arrSelectedKeys1.Clear();
626 m_arrSelectedKeys2.Clear();
627 }
628
629
630 // Save the key values of the currently selected rows for later restore
SaveSelections()631 void CBOINCBaseView::SaveSelections() {
632 if (!_IsSelectionManagementNeeded()) {
633 return;
634 }
635
636 m_arrSelectedKeys1.Clear();
637 m_arrSelectedKeys2.Clear();
638 m_bIgnoreUIEvents = true;
639 int i = -1;
640 while (1) {
641 i = m_pListPane->GetNextSelected(i);
642 if (i < 0) break;
643 m_arrSelectedKeys1.Add(GetKeyValue1(i));
644 m_arrSelectedKeys2.Add(GetKeyValue2(i));
645 }
646 m_bIgnoreUIEvents = false;
647 }
648
649 // Select all rows with formerly selected data based on key values
650 //
651 // Each RPC may add (insert) or delete items from the list, so
652 // the selected row numbers may now point to different data.
653 // We called SaveSelections() before updating the underlying
654 // data; this routine finds the data corresponding to each
655 // previous selection and makes any adjustments to ensure that
656 // the rows containing the originally selected data are selected.
RestoreSelections()657 void CBOINCBaseView::RestoreSelections() {
658 if (!_IsSelectionManagementNeeded()) {
659 return;
660 }
661
662 // To minimize flicker, this method selects or deselects only
663 // those rows which actually need their selection status changed.
664 // First, get a list of which rows should be selected
665 int i, j, m = 0, newCount = 0, oldCount = (int)m_arrSelectedKeys1.size();
666 bool found;
667 wxArrayInt arrSelRows;
668 for(i=0; i< oldCount; ++i) {
669 int index = FindRowIndexByKeyValues(m_arrSelectedKeys1[i], m_arrSelectedKeys2[i]);
670 if(index >= 0) {
671 arrSelRows.Add(index);
672 }
673 }
674 newCount = (int)arrSelRows.GetCount();
675
676 // Step through the currently selected row numbers and for each one determine
677 // whether it should remain selected.
678 m_bIgnoreUIEvents = true;
679 i = -1;
680 while (1) {
681 found = false;
682 i = m_pListPane->GetNextSelected(i);
683 if (i < 0) break;
684 m = (int)arrSelRows.GetCount();
685 for (j=0; j<m; ++j) {
686 if (arrSelRows[j] == i) {
687 arrSelRows.RemoveAt(j); // We have handled this one so remove from list
688 found = true; // Already selected, so no change needed
689 break;
690 }
691 }
692 if (!found) {
693 m_pListPane->SelectRow(i, false); // This row should no longer be selected
694 }
695 }
696
697 // Now select those rows which were not previously selected but should now be
698 m = (int)arrSelRows.GetCount();
699 for (j=0; j<m; ++j) {
700 m_pListPane->SelectRow(arrSelRows[j], true);
701 }
702 m_bIgnoreUIEvents = false;
703
704 if (oldCount != newCount) {
705 m_bForceUpdateSelection = true; // OnListRender() will call UpdateSelection()
706 }
707 }
708
709
ClearSelections()710 void CBOINCBaseView::ClearSelections() {
711 if (!m_pListPane) return;
712
713 m_bIgnoreUIEvents = true;
714 int i = -1;
715 while (1) {
716 i = m_pListPane->GetNextSelected(i);
717 if (i < 0) break;
718 m_pListPane->SelectRow(i, false);
719 }
720 m_bIgnoreUIEvents = false;
721 }
722
723
PreUpdateSelection()724 void CBOINCBaseView::PreUpdateSelection(){
725 }
726
727
UpdateSelection()728 void CBOINCBaseView::UpdateSelection(){
729 }
730
731
PostUpdateSelection()732 void CBOINCBaseView::PostUpdateSelection(){
733 wxASSERT(m_pTaskPane);
734 if (m_pTaskPane->UpdateControls()) {
735 // Under wxWidgets 2.9.4, Layout() causes ListCtrl
736 // to repaint, so call only when actually needed.
737 Layout();
738 }
739 }
740
741
UpdateWebsiteSelection(long lControlGroup,PROJECT * project)742 void CBOINCBaseView::UpdateWebsiteSelection(long lControlGroup, PROJECT* project){
743 unsigned int i;
744 CTaskItemGroup* pGroup = NULL;
745 CTaskItem* pItem = NULL;
746
747 wxASSERT(m_pTaskPane);
748 wxASSERT(m_pListPane);
749
750 if (m_bForceUpdateSelection) {
751
752 // Update the websites list
753 //
754 if (m_TaskGroups.size() > 1) {
755
756 // Delete task group, objects, and controls.
757 pGroup = m_TaskGroups[lControlGroup];
758
759 m_pTaskPane->DeleteTaskGroupAndTasks(pGroup);
760 for (i=0; i<pGroup->m_Tasks.size(); i++) {
761 delete pGroup->m_Tasks[i];
762 }
763 pGroup->m_Tasks.clear();
764 delete pGroup;
765
766 pGroup = NULL;
767
768 m_TaskGroups.erase( m_TaskGroups.begin() + 1 );
769 }
770
771 // If something is selected create the tasks and controls
772 //
773 if (m_pListPane->GetSelectedItemCount()) {
774 if (project) {
775 // Create the web sites task group
776 pGroup = new CTaskItemGroup( _("Project web pages") );
777 m_TaskGroups.push_back( pGroup );
778
779 // Default project url
780 pItem = new CTaskItem(
781 wxString("Home page", wxConvUTF8),
782 wxString(project->project_name.c_str(), wxConvUTF8) + wxT(" web site"),
783 wxString(project->master_url, wxConvUTF8),
784 ID_TASK_PROJECT_WEB_PROJDEF_MIN
785 );
786 pGroup->m_Tasks.push_back(pItem);
787
788
789 // Project defined urls
790 for (i=0;(i<project->gui_urls.size())&&(i<=ID_TASK_PROJECT_WEB_PROJDEF_MAX);i++) {
791 pItem = new CTaskItem(
792 wxGetTranslation(wxString(project->gui_urls[i].name.c_str(), wxConvUTF8)),
793 wxGetTranslation(wxString(project->gui_urls[i].description.c_str(), wxConvUTF8)),
794 wxString(project->gui_urls[i].url.c_str(), wxConvUTF8),
795 ID_TASK_PROJECT_WEB_PROJDEF_MIN + 1 + i
796 );
797 pGroup->m_Tasks.push_back(pItem);
798 }
799 }
800 }
801
802 m_pTaskPane->FitInside();
803 m_bForceUpdateSelection = false;
804 }
805 }
806
807
808 // Make sure task pane background is properly erased
RefreshTaskPane()809 void CBOINCBaseView::RefreshTaskPane() {
810 if (m_pTaskPane) {
811 m_pTaskPane->Refresh(true);
812 }
813 }
814
815
816 #ifdef __WXMAC__
817 // Fix Keyboard navigation on Mac
818 //
819 // NOTE: to select an item in wxListCtrl when none
820 // has yet been selected, press tab and then space.
821 #define SHIFT_MASK (1<<17)
822
OnKeyPressed(wxKeyEvent & event)823 void CBOINCBaseView::OnKeyPressed(wxKeyEvent &event) {
824 wxWindow next;
825 CTaskItemGroup* pGroup = NULL;
826 CTaskItem* pItem = NULL;
827 int i, j;
828 bool focusOK = false;
829
830 if (m_pTaskPane) {
831 int keyCode = event.GetKeyCode();
832 wxUint32 keyFlags = event.GetRawKeyFlags();
833
834 if (keyCode == WXK_TAB) {
835 wxWindow* focused = wxWindow::FindFocus();
836 if (!m_pTaskPane->IsDescendant(focused)) {
837 if (keyFlags & SHIFT_MASK) {
838 for (i=m_TaskGroups.size()-1; i>=0; --i) {
839 pGroup = m_TaskGroups[i];
840 for (j=pGroup->m_Tasks.size()-1; j>=0; --j) {
841 pItem = pGroup->m_Tasks[j];
842 if (pItem->m_pButton) {
843 if (pItem->m_pButton->CanAcceptFocus()) {
844 focusOK = true;
845 break;
846 }
847 }
848 }
849 if (focusOK) break;
850 }
851 } else {
852 for (i=0; i<m_TaskGroups.size(); ++i) {
853 pGroup = m_TaskGroups[i];
854 for (j=0; j<pGroup->m_Tasks.size(); ++j) {
855 pItem = pGroup->m_Tasks[j];
856 if (pItem->m_pButton) {
857 if (pItem->m_pButton->CanAcceptFocus()) {
858 focusOK = true;
859 break;
860 }
861 }
862 }
863 if (focusOK) break;
864 }
865 }
866 if (focusOK) {
867 pItem->m_pButton->SetFocus();
868 return;
869 }
870 }
871 wxNavigationKeyEvent evt;
872 evt.SetDirection((keyFlags & SHIFT_MASK) == 0);
873 evt.SetFromTab(true);
874 m_pTaskPane->GetEventHandler()->AddPendingEvent(evt);
875 return;
876 }
877 }
878 event.Skip();
879 }
880 #endif
881
882
_IsSelectionManagementNeeded()883 bool CBOINCBaseView::_IsSelectionManagementNeeded() {
884 return IsSelectionManagementNeeded();
885 }
886
887
IsSelectionManagementNeeded()888 bool CBOINCBaseView::IsSelectionManagementNeeded() {
889 return false;
890 }
891
892
_EnsureLastItemVisible()893 bool CBOINCBaseView::_EnsureLastItemVisible() {
894 return EnsureLastItemVisible();
895 }
896
897
EnsureLastItemVisible()898 bool CBOINCBaseView::EnsureLastItemVisible() {
899 return false;
900 }
901
902
GetProgressValue(long)903 double CBOINCBaseView::GetProgressValue(long) {
904 return 0.0;
905 }
906
907
GetProgressText(long)908 wxString CBOINCBaseView::GetProgressText( long ) {
909 return wxEmptyString;
910 }
911
AppendColumn(int)912 void CBOINCBaseView::AppendColumn(int){
913 }
914
915
append_to_status(wxString & existing,const wxString & additional)916 void CBOINCBaseView::append_to_status(wxString& existing, const wxString& additional) {
917 if (existing.size() == 0) {
918 existing = additional;
919 } else {
920 existing += wxT(", ") + additional;
921 }
922 }
923
924
925 // HTML Entity Conversion:
926 // http://www.webreference.com/html/reference/character/
927 // Completed: The ISO Latin 1 Character Set
928 //
HtmlEntityEncode(wxString strRaw)929 wxString CBOINCBaseView::HtmlEntityEncode(wxString strRaw) {
930 wxString strEncodedHtml(strRaw);
931
932 #ifdef __WXMSW__
933 strEncodedHtml.Replace(wxT("&"), wxT("&"), true);
934 strEncodedHtml.Replace(wxT("\""), wxT("""), true);
935 strEncodedHtml.Replace(wxT("<"), wxT("<"), true);
936 strEncodedHtml.Replace(wxT(">"), wxT(">"), true);
937 strEncodedHtml.Replace(wxT("‚"), wxT("‚"), true);
938 strEncodedHtml.Replace(wxT("ƒ"), wxT("ƒ"), true);
939 strEncodedHtml.Replace(wxT("„"), wxT("„"), true);
940 strEncodedHtml.Replace(wxT("…"), wxT("…"), true);
941 strEncodedHtml.Replace(wxT("†"), wxT("†"), true);
942 strEncodedHtml.Replace(wxT("‡"), wxT("‡"), true);
943 strEncodedHtml.Replace(wxT("Š"), wxT("Š"), true);
944 strEncodedHtml.Replace(wxT("Œ"), wxT("Œ"), true);
945 strEncodedHtml.Replace(wxT("‘"), wxT("‘"), true);
946 strEncodedHtml.Replace(wxT("’"), wxT("’"), true);
947 strEncodedHtml.Replace(wxT("“"), wxT("“"), true);
948 strEncodedHtml.Replace(wxT("”"), wxT("”"), true);
949 strEncodedHtml.Replace(wxT("•"), wxT("•"), true);
950 strEncodedHtml.Replace(wxT("–"), wxT("–"), true);
951 strEncodedHtml.Replace(wxT("—"), wxT("—"), true);
952 strEncodedHtml.Replace(wxT("˜˜~"), wxT("˜"), true);
953 strEncodedHtml.Replace(wxT("™"), wxT("™"), true);
954 strEncodedHtml.Replace(wxT("š"), wxT("š"), true);
955 strEncodedHtml.Replace(wxT("œ"), wxT("œ"), true);
956 strEncodedHtml.Replace(wxT("Ÿ"), wxT("Ÿ"), true);
957 strEncodedHtml.Replace(wxT("¡"), wxT("¡"), true);
958 strEncodedHtml.Replace(wxT("¢"), wxT("¢"), true);
959 strEncodedHtml.Replace(wxT("£"), wxT("£"), true);
960 strEncodedHtml.Replace(wxT("¤"), wxT("¤"), true);
961 strEncodedHtml.Replace(wxT("¥"), wxT("¥"), true);
962 strEncodedHtml.Replace(wxT("¦"), wxT("¦"), true);
963 strEncodedHtml.Replace(wxT("§"), wxT("§"), true);
964 strEncodedHtml.Replace(wxT("¨"), wxT("¨"), true);
965 strEncodedHtml.Replace(wxT("©"), wxT("©"), true);
966 strEncodedHtml.Replace(wxT("ª"), wxT("ª"), true);
967 strEncodedHtml.Replace(wxT("«"), wxT("«"), true);
968 strEncodedHtml.Replace(wxT("¬"), wxT("¬"), true);
969 strEncodedHtml.Replace(wxT("®"), wxT("®"), true);
970 strEncodedHtml.Replace(wxT("¯"), wxT("¯"), true);
971 strEncodedHtml.Replace(wxT("°"), wxT("°"), true);
972 strEncodedHtml.Replace(wxT("±"), wxT("±"), true);
973 strEncodedHtml.Replace(wxT("²"), wxT("²"), true);
974 strEncodedHtml.Replace(wxT("³"), wxT("³"), true);
975 strEncodedHtml.Replace(wxT("´"), wxT("´"), true);
976 strEncodedHtml.Replace(wxT("µ"), wxT("µ"), true);
977 strEncodedHtml.Replace(wxT("¶"), wxT("¶"), true);
978 strEncodedHtml.Replace(wxT("·"), wxT("·"), true);
979 strEncodedHtml.Replace(wxT("¸"), wxT("¸"), true);
980 strEncodedHtml.Replace(wxT("¹"), wxT("¹"), true);
981 strEncodedHtml.Replace(wxT("º"), wxT("º"), true);
982 strEncodedHtml.Replace(wxT("»"), wxT("»"), true);
983 strEncodedHtml.Replace(wxT("¼"), wxT("¼"), true);
984 strEncodedHtml.Replace(wxT("½"), wxT("½"), true);
985 strEncodedHtml.Replace(wxT("¾"), wxT("¾"), true);
986 strEncodedHtml.Replace(wxT("¿"), wxT("¿"), true);
987 strEncodedHtml.Replace(wxT("À"), wxT("À"), true);
988 strEncodedHtml.Replace(wxT("Á"), wxT("Á"), true);
989 strEncodedHtml.Replace(wxT("Â"), wxT("Â"), true);
990 strEncodedHtml.Replace(wxT("Ã"), wxT("Ã"), true);
991 strEncodedHtml.Replace(wxT("Ä"), wxT("Ä"), true);
992 strEncodedHtml.Replace(wxT("Å"), wxT("Å"), true);
993 strEncodedHtml.Replace(wxT("Æ"), wxT("Æ"), true);
994 strEncodedHtml.Replace(wxT("Ç"), wxT("Ç"), true);
995 strEncodedHtml.Replace(wxT("È"), wxT("È"), true);
996 strEncodedHtml.Replace(wxT("É"), wxT("É"), true);
997 strEncodedHtml.Replace(wxT("Ê"), wxT("Ê"), true);
998 strEncodedHtml.Replace(wxT("Ë"), wxT("Ë"), true);
999 strEncodedHtml.Replace(wxT("Ì"), wxT("Ì"), true);
1000 strEncodedHtml.Replace(wxT("Í"), wxT("Í"), true);
1001 strEncodedHtml.Replace(wxT("Î"), wxT("Î"), true);
1002 strEncodedHtml.Replace(wxT("Ï"), wxT("Ï"), true);
1003 strEncodedHtml.Replace(wxT("Ð"), wxT("Ð"), true);
1004 strEncodedHtml.Replace(wxT("Ñ"), wxT("Ñ"), true);
1005 strEncodedHtml.Replace(wxT("Ò"), wxT("Ò"), true);
1006 strEncodedHtml.Replace(wxT("Ó"), wxT("Ó"), true);
1007 strEncodedHtml.Replace(wxT("Ô"), wxT("Ô"), true);
1008 strEncodedHtml.Replace(wxT("Õ"), wxT("Õ"), true);
1009 strEncodedHtml.Replace(wxT("Ö"), wxT("Ö"), true);
1010 strEncodedHtml.Replace(wxT("×"), wxT("×"), true);
1011 strEncodedHtml.Replace(wxT("Ø"), wxT("Ø"), true);
1012 strEncodedHtml.Replace(wxT("Ù"), wxT("Ù"), true);
1013 strEncodedHtml.Replace(wxT("Ú"), wxT("Ú"), true);
1014 strEncodedHtml.Replace(wxT("Û"), wxT("Û"), true);
1015 strEncodedHtml.Replace(wxT("Ü"), wxT("Ü"), true);
1016 strEncodedHtml.Replace(wxT("Ý"), wxT("Ý"), true);
1017 strEncodedHtml.Replace(wxT("Þ"), wxT("Þ"), true);
1018 strEncodedHtml.Replace(wxT("ß"), wxT("ß"), true);
1019 strEncodedHtml.Replace(wxT("à"), wxT("à"), true);
1020 strEncodedHtml.Replace(wxT("á"), wxT("á"), true);
1021 strEncodedHtml.Replace(wxT("â"), wxT("â"), true);
1022 strEncodedHtml.Replace(wxT("ã"), wxT("ã"), true);
1023 strEncodedHtml.Replace(wxT("ä"), wxT("ä"), true);
1024 strEncodedHtml.Replace(wxT("å"), wxT("å"), true);
1025 strEncodedHtml.Replace(wxT("æ"), wxT("æ"), true);
1026 strEncodedHtml.Replace(wxT("ç"), wxT("ç"), true);
1027 strEncodedHtml.Replace(wxT("è"), wxT("è"), true);
1028 strEncodedHtml.Replace(wxT("é"), wxT("é"), true);
1029 strEncodedHtml.Replace(wxT("ê"), wxT("ê"), true);
1030 strEncodedHtml.Replace(wxT("ë"), wxT("ë"), true);
1031 strEncodedHtml.Replace(wxT("ì"), wxT("ì"), true);
1032 strEncodedHtml.Replace(wxT("í"), wxT("í"), true);
1033 strEncodedHtml.Replace(wxT("î"), wxT("î"), true);
1034 strEncodedHtml.Replace(wxT("ï"), wxT("ï"), true);
1035 strEncodedHtml.Replace(wxT("ð"), wxT("ð"), true);
1036 strEncodedHtml.Replace(wxT("ñ"), wxT("ñ"), true);
1037 strEncodedHtml.Replace(wxT("ò"), wxT("ò"), true);
1038 strEncodedHtml.Replace(wxT("ó"), wxT("ó"), true);
1039 strEncodedHtml.Replace(wxT("ô"), wxT("ô"), true);
1040 strEncodedHtml.Replace(wxT("õ"), wxT("õ"), true);
1041 strEncodedHtml.Replace(wxT("ö"), wxT("ö"), true);
1042 strEncodedHtml.Replace(wxT("÷"), wxT("÷"), true);
1043 strEncodedHtml.Replace(wxT("ø"), wxT("ø"), true);
1044 strEncodedHtml.Replace(wxT("ù"), wxT("ù"), true);
1045 strEncodedHtml.Replace(wxT("ú"), wxT("ú"), true);
1046 strEncodedHtml.Replace(wxT("û"), wxT("û"), true);
1047 strEncodedHtml.Replace(wxT("ü"), wxT("ü"), true);
1048 strEncodedHtml.Replace(wxT("ý"), wxT("ý"), true);
1049 strEncodedHtml.Replace(wxT("þ"), wxT("þ"), true);
1050 strEncodedHtml.Replace(wxT("ÿ"), wxT("ÿ"), true);
1051 #endif
1052
1053 return strEncodedHtml;
1054 }
1055
HtmlEntityDecode(wxString strRaw)1056 wxString CBOINCBaseView::HtmlEntityDecode(wxString strRaw) {
1057 wxString strDecodedHtml(strRaw);
1058
1059 if (0 <= strDecodedHtml.Find(wxT("&"))) {
1060 #ifdef __WXMSW__
1061 strDecodedHtml.Replace(wxT("&"), wxT("&"), true);
1062 strDecodedHtml.Replace(wxT("""), wxT("\""), true);
1063 strDecodedHtml.Replace(wxT("<"), wxT("<"), true);
1064 strDecodedHtml.Replace(wxT(">"), wxT(">"), true);
1065 strDecodedHtml.Replace(wxT("‚"), wxT("‚"), true);
1066 strDecodedHtml.Replace(wxT("ƒ"), wxT("ƒ"), true);
1067 strDecodedHtml.Replace(wxT("„"), wxT("„"), true);
1068 strDecodedHtml.Replace(wxT("…"), wxT("…"), true);
1069 strDecodedHtml.Replace(wxT("†"), wxT("†"), true);
1070 strDecodedHtml.Replace(wxT("‡"), wxT("‡"), true);
1071 strDecodedHtml.Replace(wxT("Š"), wxT("Š"), true);
1072 strDecodedHtml.Replace(wxT("Œ"), wxT("Œ"), true);
1073 strDecodedHtml.Replace(wxT("‘"), wxT("‘"), true);
1074 strDecodedHtml.Replace(wxT("’"), wxT("’"), true);
1075 strDecodedHtml.Replace(wxT("“"), wxT("“"), true);
1076 strDecodedHtml.Replace(wxT("”"), wxT("”"), true);
1077 strDecodedHtml.Replace(wxT("•"), wxT("•"), true);
1078 strDecodedHtml.Replace(wxT("–"), wxT("–"), true);
1079 strDecodedHtml.Replace(wxT("—"), wxT("—"), true);
1080 strDecodedHtml.Replace(wxT("˜"), wxT("˜˜~"), true);
1081 strDecodedHtml.Replace(wxT("™"), wxT("™"), true);
1082 strDecodedHtml.Replace(wxT("š"), wxT("š"), true);
1083 strDecodedHtml.Replace(wxT("œ"), wxT("œ"), true);
1084 strDecodedHtml.Replace(wxT("Ÿ"), wxT("Ÿ"), true);
1085 strDecodedHtml.Replace(wxT("¡"), wxT("¡"), true);
1086 strDecodedHtml.Replace(wxT("¢"), wxT("¢"), true);
1087 strDecodedHtml.Replace(wxT("£"), wxT("£"), true);
1088 strDecodedHtml.Replace(wxT("¤"), wxT("¤"), true);
1089 strDecodedHtml.Replace(wxT("¥"), wxT("¥"), true);
1090 strDecodedHtml.Replace(wxT("¦"), wxT("¦"), true);
1091 strDecodedHtml.Replace(wxT("§"), wxT("§"), true);
1092 strDecodedHtml.Replace(wxT("¨"), wxT("¨"), true);
1093 strDecodedHtml.Replace(wxT("©"), wxT("©"), true);
1094 strDecodedHtml.Replace(wxT("ª"), wxT("ª"), true);
1095 strDecodedHtml.Replace(wxT("«"), wxT("«"), true);
1096 strDecodedHtml.Replace(wxT("¬"), wxT("¬"), true);
1097 strDecodedHtml.Replace(wxT("®"), wxT("®"), true);
1098 strDecodedHtml.Replace(wxT("¯"), wxT("¯"), true);
1099 strDecodedHtml.Replace(wxT("°"), wxT("°"), true);
1100 strDecodedHtml.Replace(wxT("±"), wxT("±"), true);
1101 strDecodedHtml.Replace(wxT("²"), wxT("²"), true);
1102 strDecodedHtml.Replace(wxT("³"), wxT("³"), true);
1103 strDecodedHtml.Replace(wxT("´"), wxT("´"), true);
1104 strDecodedHtml.Replace(wxT("µ"), wxT("µ"), true);
1105 strDecodedHtml.Replace(wxT("¶"), wxT("¶"), true);
1106 strDecodedHtml.Replace(wxT("·"), wxT("·"), true);
1107 strDecodedHtml.Replace(wxT("¸"), wxT("¸"), true);
1108 strDecodedHtml.Replace(wxT("¹"), wxT("¹"), true);
1109 strDecodedHtml.Replace(wxT("º"), wxT("º"), true);
1110 strDecodedHtml.Replace(wxT("»"), wxT("»"), true);
1111 strDecodedHtml.Replace(wxT("¼"), wxT("¼"), true);
1112 strDecodedHtml.Replace(wxT("½"), wxT("½"), true);
1113 strDecodedHtml.Replace(wxT("¾"), wxT("¾"), true);
1114 strDecodedHtml.Replace(wxT("¿"), wxT("¿"), true);
1115 strDecodedHtml.Replace(wxT("À"), wxT("À"), true);
1116 strDecodedHtml.Replace(wxT("Á"), wxT("Á"), true);
1117 strDecodedHtml.Replace(wxT("Â"), wxT("Â"), true);
1118 strDecodedHtml.Replace(wxT("Ã"), wxT("Ã"), true);
1119 strDecodedHtml.Replace(wxT("Ä"), wxT("Ä"), true);
1120 strDecodedHtml.Replace(wxT("Å"), wxT("Å"), true);
1121 strDecodedHtml.Replace(wxT("Æ"), wxT("Æ"), true);
1122 strDecodedHtml.Replace(wxT("Ç"), wxT("Ç"), true);
1123 strDecodedHtml.Replace(wxT("È"), wxT("È"), true);
1124 strDecodedHtml.Replace(wxT("É"), wxT("É"), true);
1125 strDecodedHtml.Replace(wxT("Ê"), wxT("Ê"), true);
1126 strDecodedHtml.Replace(wxT("Ë"), wxT("Ë"), true);
1127 strDecodedHtml.Replace(wxT("Ì"), wxT("Ì"), true);
1128 strDecodedHtml.Replace(wxT("Í"), wxT("Í"), true);
1129 strDecodedHtml.Replace(wxT("Î"), wxT("Î"), true);
1130 strDecodedHtml.Replace(wxT("Ï"), wxT("Ï"), true);
1131 strDecodedHtml.Replace(wxT("Ð"), wxT("Ð"), true);
1132 strDecodedHtml.Replace(wxT("Ñ"), wxT("Ñ"), true);
1133 strDecodedHtml.Replace(wxT("Ò"), wxT("Ò"), true);
1134 strDecodedHtml.Replace(wxT("Ó"), wxT("Ó"), true);
1135 strDecodedHtml.Replace(wxT("Ô"), wxT("Ô"), true);
1136 strDecodedHtml.Replace(wxT("Õ"), wxT("Õ"), true);
1137 strDecodedHtml.Replace(wxT("Ö"), wxT("Ö"), true);
1138 strDecodedHtml.Replace(wxT("×"), wxT("×"), true);
1139 strDecodedHtml.Replace(wxT("Ø"), wxT("Ø"), true);
1140 strDecodedHtml.Replace(wxT("Ù"), wxT("Ù"), true);
1141 strDecodedHtml.Replace(wxT("Ú"), wxT("Ú"), true);
1142 strDecodedHtml.Replace(wxT("Û"), wxT("Û"), true);
1143 strDecodedHtml.Replace(wxT("Ü"), wxT("Ü"), true);
1144 strDecodedHtml.Replace(wxT("Ý"), wxT("Ý"), true);
1145 strDecodedHtml.Replace(wxT("Þ"), wxT("Þ"), true);
1146 strDecodedHtml.Replace(wxT("ß"), wxT("ß"), true);
1147 strDecodedHtml.Replace(wxT("à"), wxT("à"), true);
1148 strDecodedHtml.Replace(wxT("á"), wxT("á"), true);
1149 strDecodedHtml.Replace(wxT("â"), wxT("â"), true);
1150 strDecodedHtml.Replace(wxT("ã"), wxT("ã"), true);
1151 strDecodedHtml.Replace(wxT("ä"), wxT("ä"), true);
1152 strDecodedHtml.Replace(wxT("å"), wxT("å"), true);
1153 strDecodedHtml.Replace(wxT("æ"), wxT("æ"), true);
1154 strDecodedHtml.Replace(wxT("ç"), wxT("ç"), true);
1155 strDecodedHtml.Replace(wxT("è"), wxT("è"), true);
1156 strDecodedHtml.Replace(wxT("é"), wxT("é"), true);
1157 strDecodedHtml.Replace(wxT("ê"), wxT("ê"), true);
1158 strDecodedHtml.Replace(wxT("ë"), wxT("ë"), true);
1159 strDecodedHtml.Replace(wxT("ì"), wxT("ì"), true);
1160 strDecodedHtml.Replace(wxT("í"), wxT("í"), true);
1161 strDecodedHtml.Replace(wxT("î"), wxT("î"), true);
1162 strDecodedHtml.Replace(wxT("ï"), wxT("ï"), true);
1163 strDecodedHtml.Replace(wxT("ð"), wxT("ð"), true);
1164 strDecodedHtml.Replace(wxT("ñ"), wxT("ñ"), true);
1165 strDecodedHtml.Replace(wxT("ò"), wxT("ò"), true);
1166 strDecodedHtml.Replace(wxT("ó"), wxT("ó"), true);
1167 strDecodedHtml.Replace(wxT("ô"), wxT("ô"), true);
1168 strDecodedHtml.Replace(wxT("õ"), wxT("õ"), true);
1169 strDecodedHtml.Replace(wxT("ö"), wxT("ö"), true);
1170 strDecodedHtml.Replace(wxT("÷"), wxT("÷"), true);
1171 strDecodedHtml.Replace(wxT("ø"), wxT("ø"), true);
1172 strDecodedHtml.Replace(wxT("ù"), wxT("ù"), true);
1173 strDecodedHtml.Replace(wxT("ú"), wxT("ú"), true);
1174 strDecodedHtml.Replace(wxT("û"), wxT("û"), true);
1175 strDecodedHtml.Replace(wxT("ü"), wxT("ü"), true);
1176 strDecodedHtml.Replace(wxT("ý"), wxT("ý"), true);
1177 strDecodedHtml.Replace(wxT("þ"), wxT("þ"), true);
1178 strDecodedHtml.Replace(wxT("ÿ"), wxT("ÿ"), true);
1179 #endif
1180 }
1181
1182 return strDecodedHtml;
1183 }
1184
1185