1 // This file is part of BOINC.
2 // http://boinc.berkeley.edu
3 // Copyright (C) 2008 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 "ViewProjects.h"
20 #endif
21
22 #include "stdwx.h"
23 #include "str_util.h"
24 #include "BOINCGUIApp.h"
25 #include "BOINCBaseFrame.h"
26 #include "MainDocument.h"
27 #include "AdvancedFrame.h"
28 #include "BOINCTaskCtrl.h"
29 #include "BOINCListCtrl.h"
30 #include "ViewProjects.h"
31 #include "Events.h"
32 #include "DlgItemProperties.h"
33
34
35 #include "res/proj.xpm"
36
37 // Column IDs must be equal to the column's default
38 // position (left to right, zero-based) when all
39 // columns are shown. However, any column may be
40 // hidden, either by default or by the user.
41 // (On MS Windows only, the user can also rearrange
42 // the columns from the default order.)
43 //
44 // Column IDs
45 #define COLUMN_PROJECT 0
46 #define COLUMN_ACCOUNTNAME 1
47 #define COLUMN_TEAMNAME 2
48 #define COLUMN_TOTALCREDIT 3
49 #define COLUMN_AVGCREDIT 4
50 #define COLUMN_RESOURCESHARE 5
51 #define COLUMN_STATUS 6
52
53 // DefaultShownColumns is an array containing the
54 // columnIDs of the columns to be shown by default,
55 // in ascending order. It may or may not include
56 // all columns.
57 //
58 // For now, show all columns by default
59 static int DefaultShownColumns[] = { COLUMN_PROJECT, COLUMN_ACCOUNTNAME, COLUMN_TEAMNAME,
60 COLUMN_TOTALCREDIT, COLUMN_AVGCREDIT,
61 COLUMN_RESOURCESHARE, COLUMN_STATUS};
62
63 // groups that contain buttons
64 #define GRP_TASKS 0
65 #define GRP_WEBSITES 1
66
67 // buttons in the "tasks" area
68 #define BTN_UPDATE 0
69 #define BTN_SUSPEND 1
70 #define BTN_NOWORK 2
71 #define BTN_RESET 3
72 #define BTN_DETACH 4
73 #define BTN_PROPERTIES 5
74
format_total_credit(double credit,wxString & strBuffer)75 static void format_total_credit(double credit, wxString& strBuffer) {
76 strBuffer = format_number(credit, 0);
77 }
format_avg_credit(double credit,wxString & strBuffer)78 static void format_avg_credit(double credit, wxString& strBuffer) {
79 strBuffer = format_number(credit, 2);
80 }
81
CProject()82 CProject::CProject() {
83 m_fTotalCredit = -1.0;
84 m_fAVGCredit = -1.0;
85 m_fResourceShare = -1.0;
86 m_fResourcePercent = -1.0;
87 }
88
89
~CProject()90 CProject::~CProject() {
91 m_strProjectName.Clear();
92 m_strAccountName.Clear();
93 m_strTeamName.Clear();
94 m_strStatus.Clear();
95 }
96
97
98 IMPLEMENT_DYNAMIC_CLASS(CViewProjects, CBOINCBaseView)
99
100 BEGIN_EVENT_TABLE (CViewProjects, CBOINCBaseView)
101 EVT_BUTTON(ID_TASK_PROJECT_UPDATE, CViewProjects::OnProjectUpdate)
102 EVT_BUTTON(ID_TASK_PROJECT_SUSPEND, CViewProjects::OnProjectSuspend)
103 EVT_BUTTON(ID_TASK_PROJECT_NONEWWORK, CViewProjects::OnProjectNoNewWork)
104 EVT_BUTTON(ID_TASK_PROJECT_RESET, CViewProjects::OnProjectReset)
105 EVT_BUTTON(ID_TASK_PROJECT_DETACH, CViewProjects::OnProjectDetach)
106 EVT_BUTTON(ID_TASK_PROJECT_SHOW_PROPERTIES, CViewProjects::OnShowItemProperties)
107 EVT_CUSTOM_RANGE(wxEVT_COMMAND_BUTTON_CLICKED, ID_TASK_PROJECT_WEB_PROJDEF_MIN, ID_TASK_PROJECT_WEB_PROJDEF_MAX, CViewProjects::OnProjectWebsiteClicked)
108 // We currently handle EVT_LIST_CACHE_HINT on Windows or
109 // EVT_CHECK_SELECTION_CHANGED on Mac & Linux instead of EVT_LIST_ITEM_SELECTED
110 // or EVT_LIST_ITEM_DESELECTED. See CBOINCBaseView::OnCacheHint() for info.
111 #if USE_LIST_CACHE_HINT
112 EVT_LIST_CACHE_HINT(ID_LIST_PROJECTSVIEW, CViewProjects::OnCacheHint)
113 #else
114 EVT_CHECK_SELECTION_CHANGED(CViewProjects::OnCheckSelectionChanged)
115 #endif
116 EVT_LIST_COL_CLICK(ID_LIST_PROJECTSVIEW, CViewProjects::OnColClick)
117 EVT_LIST_COL_END_DRAG(ID_LIST_PROJECTSVIEW, CViewProjects::OnColResize)
118 END_EVENT_TABLE ()
119
120
121 static CViewProjects* myCViewProjects;
122
CompareViewProjectsItems(int iRowIndex1,int iRowIndex2)123 static bool CompareViewProjectsItems(int iRowIndex1, int iRowIndex2) {
124 CProject* project1;
125 CProject* project2;
126 int result = 0;
127
128 try {
129 project1 = myCViewProjects->m_ProjectCache.at(iRowIndex1);
130 } catch ( std::out_of_range ) {
131 return 0;
132 }
133
134 try {
135 project2 = myCViewProjects->m_ProjectCache.at(iRowIndex2);
136 } catch ( std::out_of_range ) {
137 return 0;
138 }
139
140 switch (myCViewProjects->m_iSortColumnID) {
141 case COLUMN_PROJECT:
142 result = project1->m_strProjectName.CmpNoCase(project2->m_strProjectName);
143 break;
144 case COLUMN_ACCOUNTNAME:
145 result = project1->m_strAccountName.CmpNoCase(project2->m_strAccountName);
146 break;
147 case COLUMN_TEAMNAME:
148 result = project1->m_strTeamName.CmpNoCase(project2->m_strTeamName);
149 break;
150 case COLUMN_TOTALCREDIT:
151 if (project1->m_fTotalCredit < project2->m_fTotalCredit) {
152 result = -1;
153 } else if (project1->m_fTotalCredit > project2->m_fTotalCredit) {
154 result = 1;
155 }
156 break;
157 case COLUMN_AVGCREDIT:
158 if (project1->m_fAVGCredit < project2->m_fAVGCredit) {
159 result = -1;
160 } else if (project1->m_fAVGCredit > project2->m_fAVGCredit) {
161 result = 1;
162 }
163 break;
164 case COLUMN_RESOURCESHARE:
165 if (project1->m_fResourceShare < project2->m_fResourceShare) {
166 result = -1;
167 } else if (project1->m_fResourceShare > project2->m_fResourceShare) {
168 result = 1;
169 }
170 break;
171 case COLUMN_STATUS:
172 result = project1->m_strStatus.CmpNoCase(project2->m_strStatus);
173 break;
174 }
175
176 // Always return FALSE for equality (result == 0)
177 return (myCViewProjects->m_bReverseSort ? (result > 0) : (result < 0));
178 }
179
180
CViewProjects()181 CViewProjects::CViewProjects()
182 {}
183
184
CViewProjects(wxNotebook * pNotebook)185 CViewProjects::CViewProjects(wxNotebook* pNotebook) :
186 CBOINCBaseView(pNotebook, ID_TASK_PROJECTSVIEW, DEFAULT_TASK_FLAGS, ID_LIST_PROJECTSVIEW, DEFAULT_LIST_FLAGS)
187 {
188 CTaskItemGroup* pGroup = NULL;
189 CTaskItem* pItem = NULL;
190
191 wxASSERT(m_pTaskPane);
192 wxASSERT(m_pListPane);
193
194
195 //
196 // Setup View
197 //
198 pGroup = new CTaskItemGroup( _("Commands") );
199 m_TaskGroups.push_back( pGroup );
200
201 pItem = new CTaskItem(
202 _("Update"),
203 _("Report all completed tasks, get latest credit, get latest preferences, and possibly get more tasks."),
204 ID_TASK_PROJECT_UPDATE
205 );
206 pGroup->m_Tasks.push_back( pItem );
207
208 pItem = new CTaskItem(
209 _("Suspend"),
210 _("Suspend tasks for this project."),
211 ID_TASK_PROJECT_SUSPEND
212 );
213 pGroup->m_Tasks.push_back( pItem );
214
215 pItem = new CTaskItem(
216 _("No new tasks"),
217 _("Don't get new tasks for this project."),
218 ID_TASK_PROJECT_NONEWWORK
219 );
220 pGroup->m_Tasks.push_back( pItem );
221
222 pItem = new CTaskItem(
223 _("Reset project"),
224 _("Delete all files and tasks associated with this project, and get new tasks. You can update the project first to report any completed tasks."),
225 ID_TASK_PROJECT_RESET
226 );
227 pGroup->m_Tasks.push_back( pItem );
228
229 pItem = new CTaskItem(
230 _("Remove"),
231 _("Remove this project. Tasks in progress will be lost (use 'Update' first to report any completed tasks)."),
232 ID_TASK_PROJECT_DETACH
233 );
234 pGroup->m_Tasks.push_back( pItem );
235
236 pItem = new CTaskItem(
237 _("Properties"),
238 _("Show project details."),
239 ID_TASK_PROJECT_SHOW_PROPERTIES
240 );
241 pGroup->m_Tasks.push_back( pItem );
242
243 // Create Task Pane Items
244 m_pTaskPane->UpdateControls();
245
246 // m_aStdColNameOrder is an array of all column heading labels
247 // (localized) in order of ascending Column ID.
248 // Once initialized, it should not be modified.
249 //
250 m_aStdColNameOrder = new wxArrayString;
251 m_aStdColNameOrder->Insert(_("Project"), COLUMN_PROJECT);
252 m_aStdColNameOrder->Insert(_("Account"), COLUMN_ACCOUNTNAME);
253 m_aStdColNameOrder->Insert(_("Team"), COLUMN_TEAMNAME);
254 m_aStdColNameOrder->Insert(_("Work done"), COLUMN_TOTALCREDIT);
255 m_aStdColNameOrder->Insert(_("Avg. work done"), COLUMN_AVGCREDIT);
256 m_aStdColNameOrder->Insert(_("Resource share"), COLUMN_RESOURCESHARE);
257 m_aStdColNameOrder->Insert(_("Status"), COLUMN_STATUS);
258
259 // m_iStdColWidthOrder is an array of the width for each column.
260 // Entries must be in order of ascending Column ID. We initalize
261 // it here to the default column widths. It is updated by
262 // CBOINCListCtrl::OnRestoreState() and also when a user resizes
263 // a column by dragging the divider between two columns.
264 //
265 m_iStdColWidthOrder.Clear();
266 m_iStdColWidthOrder.Insert(150, COLUMN_PROJECT);
267 m_iStdColWidthOrder.Insert(80, COLUMN_ACCOUNTNAME);
268 m_iStdColWidthOrder.Insert(80, COLUMN_TEAMNAME);
269 m_iStdColWidthOrder.Insert(80, COLUMN_TOTALCREDIT);
270 m_iStdColWidthOrder.Insert(80, COLUMN_AVGCREDIT);
271 m_iStdColWidthOrder.Insert(80, COLUMN_RESOURCESHARE);
272 m_iStdColWidthOrder.Insert(80, COLUMN_STATUS);
273
274 wxASSERT(m_iStdColWidthOrder.size() == m_aStdColNameOrder->size());
275
276 m_iDefaultShownColumns = DefaultShownColumns;
277 m_iNumDefaultShownColumns = sizeof(DefaultShownColumns) / sizeof(int);
278 m_iProgressColumn = COLUMN_RESOURCESHARE;
279
280 // Needed by static sort routine;
281 myCViewProjects = this;
282 m_funcSortCompare = CompareViewProjectsItems;
283
284 UpdateSelection();
285 }
286
287
~CViewProjects()288 CViewProjects::~CViewProjects() {
289 EmptyCache();
290 EmptyTasks();
291 }
292
293
294 // Create List Pane Items
AppendColumn(int columnID)295 void CViewProjects::AppendColumn(int columnID){
296 switch(columnID) {
297 case COLUMN_PROJECT:
298 m_pListPane->AppendColumn((*m_aStdColNameOrder)[COLUMN_PROJECT],
299 wxLIST_FORMAT_LEFT, m_iStdColWidthOrder[COLUMN_PROJECT]);
300 break;
301 case COLUMN_ACCOUNTNAME:
302 m_pListPane->AppendColumn((*m_aStdColNameOrder)[COLUMN_ACCOUNTNAME],
303 wxLIST_FORMAT_LEFT, m_iStdColWidthOrder[COLUMN_ACCOUNTNAME]);
304 break;
305 case COLUMN_TEAMNAME:
306 m_pListPane->AppendColumn((*m_aStdColNameOrder)[COLUMN_TEAMNAME],
307 wxLIST_FORMAT_LEFT, m_iStdColWidthOrder[COLUMN_TEAMNAME]);
308 break;
309 case COLUMN_TOTALCREDIT:
310 m_pListPane->AppendColumn((*m_aStdColNameOrder)[COLUMN_TOTALCREDIT],
311 wxLIST_FORMAT_RIGHT, m_iStdColWidthOrder[COLUMN_TOTALCREDIT]);
312 break;
313 case COLUMN_AVGCREDIT:
314 m_pListPane->AppendColumn((*m_aStdColNameOrder)[COLUMN_AVGCREDIT],
315 wxLIST_FORMAT_RIGHT, m_iStdColWidthOrder[COLUMN_AVGCREDIT]);
316 break;
317 case COLUMN_RESOURCESHARE:
318 m_pListPane->AppendColumn((*m_aStdColNameOrder)[COLUMN_RESOURCESHARE],
319 wxLIST_FORMAT_CENTRE, m_iStdColWidthOrder[COLUMN_RESOURCESHARE]);
320 break;
321 case COLUMN_STATUS:
322 m_pListPane->AppendColumn((*m_aStdColNameOrder)[COLUMN_STATUS],
323 wxLIST_FORMAT_LEFT, m_iStdColWidthOrder[COLUMN_STATUS]);
324 break;
325 }
326 }
327
328
GetViewName()329 wxString& CViewProjects::GetViewName() {
330 static wxString strViewName(wxT("Projects"));
331 return strViewName;
332 }
333
334
GetViewDisplayName()335 wxString& CViewProjects::GetViewDisplayName() {
336 static wxString strViewName(_("Projects"));
337 return strViewName;
338 }
339
340
GetViewIcon()341 const char** CViewProjects::GetViewIcon() {
342 return proj_xpm;
343 }
344
345
GetViewCurrentViewPage()346 int CViewProjects::GetViewCurrentViewPage() {
347 return VW_PROJ;
348 }
349
350
GetKeyValue1(int iRowIndex)351 wxString CViewProjects::GetKeyValue1(int iRowIndex) {
352 CProject* project;
353
354 if (GetProjectCacheAtIndex(project, m_iSortedIndexes[iRowIndex])) {
355 return wxEmptyString;
356 }
357
358 if (m_iColumnIDToColumnIndex[COLUMN_PROJECT] < 0) {
359 // Column is hidden, so SynchronizeCacheItem() did not set its value
360 GetDocProjectURL(m_iSortedIndexes[iRowIndex], project->m_strProjectURL);
361 }
362
363 return project->m_strProjectURL;
364 }
365
366
FindRowIndexByKeyValues(wxString & key1,wxString &)367 int CViewProjects::FindRowIndexByKeyValues(wxString& key1, wxString&) {
368 CProject* project;
369 unsigned int iRowIndex, n = GetCacheCount();
370 for(iRowIndex=0; iRowIndex < n; iRowIndex++) {
371 if (GetProjectCacheAtIndex(project, m_iSortedIndexes[iRowIndex])) {
372 continue;
373 }
374 if((project->m_strProjectURL).IsSameAs(key1)) return iRowIndex;
375 }
376 return -1;
377 }
378
379
OnProjectUpdate(wxCommandEvent & WXUNUSED (event))380 void CViewProjects::OnProjectUpdate( wxCommandEvent& WXUNUSED(event) ) {
381 wxLogTrace(wxT("Function Start/End"), wxT("CViewProjects::OnProjectUpdate - Function Begin"));
382
383 CMainDocument* pDoc = wxGetApp().GetDocument();
384 CAdvancedFrame* pFrame = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
385 int row;
386
387 wxASSERT(pDoc);
388 wxASSERT(wxDynamicCast(pDoc, CMainDocument));
389 wxASSERT(pFrame);
390 wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
391 wxASSERT(m_pListPane);
392
393 row = -1;
394 while (1) {
395 // Step through all selected items
396 row = m_pListPane->GetNextItem(row, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
397 if (row < 0) break;
398
399 pDoc->ProjectUpdate(m_iSortedIndexes[row]);
400 }
401
402 m_bForceUpdateSelection = true;
403 UpdateSelection();
404 pFrame->ResetReminderTimers();
405 pFrame->FireRefreshView();
406
407 wxLogTrace(wxT("Function Start/End"), wxT("CViewProjects::OnProjectUpdate - Function End"));
408 }
409
410
OnProjectSuspend(wxCommandEvent & WXUNUSED (event))411 void CViewProjects::OnProjectSuspend( wxCommandEvent& WXUNUSED(event) ) {
412 wxLogTrace(wxT("Function Start/End"), wxT("CViewProjects::OnProjectSuspend - Function Begin"));
413
414 CMainDocument* pDoc = wxGetApp().GetDocument();
415 CAdvancedFrame* pFrame = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
416 int row;
417
418 wxASSERT(pDoc);
419 wxASSERT(wxDynamicCast(pDoc, CMainDocument));
420 wxASSERT(pFrame);
421 wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
422 wxASSERT(m_pListPane);
423
424 row = -1;
425 while (1) {
426 // Step through all selected items
427 row = m_pListPane->GetNextItem(row, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
428 if (row < 0) break;
429
430 PROJECT* project = pDoc->project(m_iSortedIndexes[row]);
431 if (project) {
432 if (project->suspended_via_gui) {
433 pDoc->ProjectResume(m_iSortedIndexes[row]);
434 } else {
435 pDoc->ProjectSuspend(m_iSortedIndexes[row]);
436 }
437 }
438 }
439
440 m_bForceUpdateSelection = true;
441 UpdateSelection();
442 pFrame->FireRefreshView();
443
444 wxLogTrace(wxT("Function Start/End"), wxT("CViewProjects::OnProjectSuspend - Function End"));
445 }
446
447
OnProjectNoNewWork(wxCommandEvent & WXUNUSED (event))448 void CViewProjects::OnProjectNoNewWork( wxCommandEvent& WXUNUSED(event) ) {
449 wxLogTrace(wxT("Function Start/End"), wxT("CViewProjects::OnProjectNoNewWork - Function Begin"));
450
451 CMainDocument* pDoc = wxGetApp().GetDocument();
452 CAdvancedFrame* pFrame = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
453 int row;
454
455 wxASSERT(pDoc);
456 wxASSERT(wxDynamicCast(pDoc, CMainDocument));
457 wxASSERT(pFrame);
458 wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
459 wxASSERT(m_pListPane);
460
461 row = -1;
462 while (1) {
463 // Step through all selected items
464 row = m_pListPane->GetNextItem(row, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
465 if (row < 0) break;
466
467 PROJECT* project = pDoc->project(m_iSortedIndexes[row]);
468 if (project) {
469 if (project->dont_request_more_work) {
470 pDoc->ProjectAllowMoreWork(m_iSortedIndexes[row]);
471 } else {
472 pDoc->ProjectNoMoreWork(m_iSortedIndexes[row]);
473 }
474 }
475 }
476
477 m_bForceUpdateSelection = true;
478 UpdateSelection();
479 pFrame->FireRefreshView();
480
481 wxLogTrace(wxT("Function Start/End"), wxT("CViewProjects::OnProjectNoNewWork - Function End"));
482 }
483
484
485
486
OnProjectReset(wxCommandEvent & WXUNUSED (event))487 void CViewProjects::OnProjectReset( wxCommandEvent& WXUNUSED(event) ) {
488 wxLogTrace(wxT("Function Start/End"), wxT("CViewProjects::OnProjectReset - Function Begin"));
489
490 wxInt32 iAnswer = 0;
491 wxString strMessage = wxEmptyString;
492 CMainDocument* pDoc = wxGetApp().GetDocument();
493 CAdvancedFrame* pFrame = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
494 CProject* pProject = NULL;
495 int row;
496
497 wxASSERT(pDoc);
498 wxASSERT(wxDynamicCast(pDoc, CMainDocument));
499 wxASSERT(pFrame);
500 wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
501 wxASSERT(m_pListPane);
502
503 if (!pDoc->IsUserAuthorized())
504 return;
505
506 row = -1;
507 while (1) {
508 // Step through all selected items
509 row = m_pListPane->GetNextItem(row, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
510 if (row < 0) break;
511
512 if (GetProjectCacheAtIndex(pProject, m_iSortedIndexes[row])) {
513 return;
514 }
515
516 strMessage.Printf(
517 _("Are you sure you want to reset project '%s'?"),
518 pProject->m_strProjectName.c_str()
519 );
520
521 iAnswer = wxGetApp().SafeMessageBox(
522 strMessage,
523 _("Reset Project"),
524 wxYES_NO | wxICON_QUESTION,
525 this
526 );
527
528 if (wxYES == iAnswer) {
529 pDoc->ProjectReset(m_iSortedIndexes[row]);
530 }
531 }
532
533 m_bForceUpdateSelection = true;
534 UpdateSelection();
535 pFrame->FireRefreshView();
536
537 wxLogTrace(wxT("Function Start/End"), wxT("CViewProjects::OnProjectReset - Function End"));
538 }
539
540
OnProjectDetach(wxCommandEvent & WXUNUSED (event))541 void CViewProjects::OnProjectDetach( wxCommandEvent& WXUNUSED(event) ) {
542 wxLogTrace(wxT("Function Start/End"), wxT("CViewProjects::OnProjectDetach - Function Begin"));
543
544 wxInt32 iAnswer = 0;
545 wxString strMessage = wxEmptyString;
546 CMainDocument* pDoc = wxGetApp().GetDocument();
547 CAdvancedFrame* pFrame = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
548 CProject* pProject = NULL;
549 int row;
550
551 wxASSERT(pDoc);
552 wxASSERT(wxDynamicCast(pDoc, CMainDocument));
553 wxASSERT(pFrame);
554 wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
555 wxASSERT(m_pListPane);
556
557 if (!pDoc->IsUserAuthorized())
558 return;
559
560 row = -1;
561 while (1) {
562 // Step through all selected items
563 row = m_pListPane->GetNextItem(row, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
564 if (row < 0) break;
565
566 if (GetProjectCacheAtIndex(pProject, m_iSortedIndexes[row])) {
567 return;
568 }
569
570 strMessage.Printf(
571 _("Are you sure you want to remove project '%s'?"),
572 pProject->m_strProjectName.c_str()
573 );
574
575 iAnswer = wxGetApp().SafeMessageBox(
576 strMessage,
577 _("Remove Project"),
578 wxYES_NO | wxICON_QUESTION,
579 this
580 );
581
582 if (wxYES == iAnswer) {
583 pDoc->ProjectDetach(m_iSortedIndexes[row]);
584 }
585 }
586
587 m_bForceUpdateSelection = true;
588 UpdateSelection();
589 pFrame->FireRefreshView();
590
591 wxLogTrace(wxT("Function Start/End"), wxT("CViewProjects::OnProjectDetach - Function End"));
592 }
593
594
OnShowItemProperties(wxCommandEvent & WXUNUSED (event))595 void CViewProjects::OnShowItemProperties( wxCommandEvent& WXUNUSED(event) ) {
596 wxASSERT(m_pListPane);
597
598 long item = m_pListPane->GetFirstSelected();
599 PROJECT* project = wxGetApp().GetDocument()->project(m_iSortedIndexes[item]);
600
601 if(!project) return; // TODO: display some sort of error alert?
602 //displaying the infos on a dialog
603 CDlgItemProperties dlg(this);
604 dlg.renderInfos(project);
605 dlg.ShowModal();
606 }
607
608
OnProjectWebsiteClicked(wxEvent & event)609 void CViewProjects::OnProjectWebsiteClicked( wxEvent& event ) {
610 wxLogTrace(wxT("Function Start/End"), wxT("CViewProjects::OnProjectWebsiteClicked - Function Begin"));
611
612 CAdvancedFrame* pFrame = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
613
614 wxASSERT(pFrame);
615 wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
616
617 int website_task_index = event.GetId() - ID_TASK_PROJECT_WEB_PROJDEF_MIN;
618 wxLaunchDefaultBrowser(
619 m_TaskGroups[1]->m_Tasks[website_task_index]->m_strWebSiteLink
620 );
621
622 UpdateSelection();
623 pFrame->FireRefreshView();
624
625 wxLogTrace(wxT("Function Start/End"), wxT("CViewProjects::OnProjectWebsiteClicked - Function End"));
626 }
627
OnColResize(wxListEvent &)628 void CViewProjects::OnColResize( wxListEvent& ) {
629 // Register the new column widths immediately
630 CAdvancedFrame* pFrame = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
631
632 wxASSERT(pFrame);
633 wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
634 pFrame->SaveState();
635 }
636
637
GetDocCount()638 wxInt32 CViewProjects::GetDocCount() {
639 CMainDocument* pDoc = wxGetApp().GetDocument();
640 if (pDoc) {
641 return pDoc->GetProjectCount();
642 }
643 return -1;
644 }
645
646
OnListGetItemText(long item,long column) const647 wxString CViewProjects::OnListGetItemText(long item, long column) const {
648 CProject* project = NULL;
649 wxString strBuffer = wxEmptyString;
650
651 m_pListPane->AddPendingProgressBar(item);
652
653 try {
654 project = m_ProjectCache.at(m_iSortedIndexes[item]);
655 } catch ( std::out_of_range ) {
656 project = NULL;
657 }
658
659 if (project && (column >= 0)) {
660 switch(m_iColumnIndexToColumnID[column]) {
661 case COLUMN_PROJECT:
662 strBuffer = project->m_strProjectName;
663 break;
664 case COLUMN_ACCOUNTNAME:
665 strBuffer = project->m_strAccountName;
666 break;
667 case COLUMN_TEAMNAME:
668 strBuffer = project->m_strTeamName;
669 break;
670 case COLUMN_TOTALCREDIT:
671 strBuffer = project->m_strTotalCredit;
672 break;
673 case COLUMN_AVGCREDIT:
674 strBuffer = project->m_strAVGCredit;
675 break;
676 case COLUMN_RESOURCESHARE:
677 // CBOINCListCtrl::DrawProgressBars() will draw this using
678 // data provided by GetProgressText() and GetProgressValue(),
679 // but we need it here for accessibility programs.
680 strBuffer = project->m_strResourceShare;
681 break;
682 case COLUMN_STATUS:
683 strBuffer = project->m_strStatus;
684 break;
685 }
686 }
687
688 return strBuffer;
689 }
690
691
AddCacheElement()692 wxInt32 CViewProjects::AddCacheElement() {
693 CProject* pItem = new CProject();
694 wxASSERT(pItem);
695 if (pItem) {
696 m_ProjectCache.push_back(pItem);
697 m_iSortedIndexes.Add((int)m_ProjectCache.size()-1);
698 return 0;
699 }
700 return -1;
701 }
702
703
EmptyCache()704 wxInt32 CViewProjects::EmptyCache() {
705 unsigned int i;
706 for (i=0; i<m_ProjectCache.size(); i++) {
707 delete m_ProjectCache[i];
708 }
709 m_ProjectCache.clear();
710 m_iSortedIndexes.Clear();
711 return 0;
712 }
713
714
GetCacheCount()715 wxInt32 CViewProjects::GetCacheCount() {
716 return (wxInt32)m_ProjectCache.size();
717 }
718
719
RemoveCacheElement()720 wxInt32 CViewProjects::RemoveCacheElement() {
721 unsigned int i;
722 delete m_ProjectCache.back();
723 m_ProjectCache.erase(m_ProjectCache.end() - 1);
724 m_iSortedIndexes.Clear();
725 for (i=0; i<m_ProjectCache.size(); i++) {
726 m_iSortedIndexes.Add(i);
727 }
728 return 0;
729 }
730
731
IsSelectionManagementNeeded()732 bool CViewProjects::IsSelectionManagementNeeded() {
733 return true;
734 }
735
UpdateSelection()736 void CViewProjects::UpdateSelection() {
737 CTaskItemGroup* pGroup = NULL;
738 PROJECT* project = NULL;
739 CMainDocument* pDoc = wxGetApp().GetDocument();
740 int i, n, row;
741 bool wasSuspended=false, wasNoNewWork=false;
742 bool enableUpdate = false;
743 bool enableSuspendResume = false;
744 bool enableNoNewTasks = false;
745 bool enableReset = false;
746 bool enableDetach = false;
747 bool enableProperties = false;
748
749 wxASSERT(pDoc);
750 wxASSERT(wxDynamicCast(pDoc, CMainDocument));
751 wxASSERT(m_pTaskPane);
752 wxASSERT(m_pListPane);
753
754 CBOINCBaseView::PreUpdateSelection();
755
756 // Update the tasks static box buttons
757 //
758 pGroup = m_TaskGroups[0];
759
760 n = m_pListPane->GetSelectedItemCount();
761 if (n > 0) {
762 enableUpdate = true;
763 enableSuspendResume = true;
764 enableNoNewTasks = true;
765 enableReset = true;
766 enableDetach = true;
767 }
768
769 row = -1;
770 for (i=0; i<n; i++) {
771 // Step through all selected items
772 row = m_pListPane->GetNextItem(row, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
773 if (row < 0) break; // Should never happen
774
775 project = pDoc->project(m_iSortedIndexes[row]);
776 if (!project) {
777 m_pTaskPane->DisableTaskGroupTasks(pGroup);
778 if(m_TaskGroups.size()>1) {
779 m_pTaskPane->DisableTaskGroupTasks(m_TaskGroups[1]);
780 }
781 return;
782 }
783
784 if (i == 0) {
785 wasSuspended = project->suspended_via_gui;
786 if (project->suspended_via_gui) {
787 m_pTaskPane->UpdateTask(
788 pGroup->m_Tasks[BTN_SUSPEND], _("Resume"), _("Resume tasks for this project.")
789 );
790 } else {
791 m_pTaskPane->UpdateTask(
792 pGroup->m_Tasks[BTN_SUSPEND], _("Suspend"), _("Suspend tasks for this project.")
793 );
794 }
795 } else {
796 if (wasSuspended != project->suspended_via_gui) {
797 // Disable Suspend / Resume button if the multiple selection
798 // has a mix of suspended and not suspended projects
799 enableSuspendResume = false;
800 }
801 }
802
803 if (i == 0) {
804 wasNoNewWork = project->dont_request_more_work;
805 if (project->dont_request_more_work) {
806 m_pTaskPane->UpdateTask(
807 pGroup->m_Tasks[BTN_NOWORK], _("Allow new tasks"), _("Allow fetching new tasks for this project.")
808 );
809 } else {
810 m_pTaskPane->UpdateTask(
811 pGroup->m_Tasks[BTN_NOWORK], _("No new tasks"), _("Don't fetch new tasks for this project.")
812 );
813 }
814 } else {
815 if (wasNoNewWork != project->dont_request_more_work) {
816 // Disable Allow New Work / No New Work button if the multiple
817 // selection has a mix of Allow New Work and No New Work projects
818 enableNoNewTasks = false;
819 }
820 }
821
822 if (project->attached_via_acct_mgr) {
823 enableDetach = false;
824 }
825 }
826
827 if (n == 1) {
828 enableProperties = true;
829
830 UpdateWebsiteSelection(GRP_WEBSITES, project);
831 if(m_TaskGroups.size()>1) {
832 m_pTaskPane->EnableTaskGroupTasks(m_TaskGroups[1]);
833 }
834 } else {
835 UpdateWebsiteSelection(GRP_WEBSITES, NULL);
836 if(m_TaskGroups.size()>1) {
837 m_pTaskPane->DisableTaskGroupTasks(m_TaskGroups[1]);
838 }
839 }
840
841 // To minimize flicker, set each button only once to the final desired state
842 pGroup->m_Tasks[BTN_UPDATE]->m_pButton->Enable(enableUpdate);
843 pGroup->m_Tasks[BTN_SUSPEND]->m_pButton->Enable(enableSuspendResume);
844 pGroup->m_Tasks[BTN_NOWORK]->m_pButton->Enable(enableNoNewTasks);
845 pGroup->m_Tasks[BTN_RESET]->m_pButton->Enable(enableReset);
846 pGroup->m_Tasks[BTN_DETACH]->m_pButton->Enable(enableDetach);
847 pGroup->m_Tasks[BTN_PROPERTIES]->m_pButton->Enable(enableProperties);
848
849 CBOINCBaseView::PostUpdateSelection();
850 }
851
852
SynchronizeCacheItem(wxInt32 iRowIndex,wxInt32 iColumnIndex)853 bool CViewProjects::SynchronizeCacheItem(wxInt32 iRowIndex, wxInt32 iColumnIndex) {
854 wxString strDocumentText = wxEmptyString;
855 wxString strDocumentText2 = wxEmptyString;
856 double x = 0.0;
857 double fDocumentPercent = 0.0;
858 CProject* project;
859 bool dirty = false;
860
861 if (GetProjectCacheAtIndex(project, m_iSortedIndexes[iRowIndex])) {
862 return false;
863 }
864
865 if (iColumnIndex < 0) return false;
866
867 strDocumentText.Empty();
868
869 switch (m_iColumnIndexToColumnID[iColumnIndex]) {
870 case COLUMN_PROJECT:
871 GetDocProjectName(m_iSortedIndexes[iRowIndex], strDocumentText);
872 GetDocProjectURL(m_iSortedIndexes[iRowIndex], strDocumentText2);
873 if (!strDocumentText.IsSameAs(project->m_strProjectName) || !strDocumentText2.IsSameAs(project->m_strProjectURL)) {
874 project->m_strProjectName = strDocumentText;
875 project->m_strProjectURL = strDocumentText2;
876 return true;
877 }
878 break;
879 case COLUMN_ACCOUNTNAME:
880 GetDocAccountName(m_iSortedIndexes[iRowIndex], strDocumentText);
881 if (!strDocumentText.IsSameAs(project->m_strAccountName)) {
882 project->m_strAccountName = strDocumentText;
883 return true;
884 }
885 break;
886 case COLUMN_TEAMNAME:
887 GetDocTeamName(m_iSortedIndexes[iRowIndex], strDocumentText);
888 if (!strDocumentText.IsSameAs(project->m_strTeamName)) {
889 project->m_strTeamName = strDocumentText;
890 return true;
891 }
892 break;
893 case COLUMN_TOTALCREDIT:
894 GetDocTotalCredit(m_iSortedIndexes[iRowIndex], x);
895 if (x != project->m_fTotalCredit) {
896 project->m_fTotalCredit = x;
897 format_total_credit(x, project->m_strTotalCredit);
898 return true;
899 }
900 break;
901 case COLUMN_AVGCREDIT:
902 GetDocAVGCredit(m_iSortedIndexes[iRowIndex], x);
903 if (x != project->m_fAVGCredit) {
904 project->m_fAVGCredit = x;
905 format_avg_credit(x, project->m_strAVGCredit);
906 return true;
907 }
908 break;
909 case COLUMN_RESOURCESHARE:
910 GetDocResourceShare(m_iSortedIndexes[iRowIndex], x);
911 if (x != project->m_fResourceShare) {
912 project->m_fResourceShare = x;
913 dirty = true;
914 }
915 GetDocResourcePercent(m_iSortedIndexes[iRowIndex], fDocumentPercent);
916 if (fDocumentPercent != project->m_fResourcePercent) {
917 project->m_fResourcePercent = fDocumentPercent;
918 dirty = true;
919 }
920 if (dirty) {
921 FormatResourceShare(x, fDocumentPercent, project->m_strResourceShare);
922 return true;
923 }
924 break;
925 case COLUMN_STATUS:
926 GetDocStatus(m_iSortedIndexes[iRowIndex], strDocumentText);
927 if (!strDocumentText.IsSameAs(project->m_strStatus)) {
928 project->m_strStatus = strDocumentText;
929 return true;
930 }
931 break;
932 }
933
934 return false;
935 }
936
937
GetDocProjectName(wxInt32 item,wxString & strBuffer) const938 void CViewProjects::GetDocProjectName(wxInt32 item, wxString& strBuffer) const {
939 PROJECT* project = NULL;
940 CMainDocument* pDoc = wxGetApp().GetDocument();
941 std::string project_name;
942
943 if (pDoc) {
944 project = pDoc->project(item);
945 }
946
947 if (project) {
948 project->get_name(project_name);
949 strBuffer = HtmlEntityDecode(wxString(project_name.c_str(), wxConvUTF8));
950 } else {
951 strBuffer = wxEmptyString;
952 }
953 }
954
955
FormatProjectName(wxInt32 item,wxString & strBuffer) const956 wxInt32 CViewProjects::FormatProjectName(wxInt32 item, wxString& strBuffer) const {
957 CProject* project;
958
959 try {
960 project = m_ProjectCache.at(m_iSortedIndexes[item]);
961 } catch ( std::out_of_range ) {
962 project = NULL;
963 }
964
965 if (project) {
966 strBuffer = project->m_strProjectName;
967 } else {
968 strBuffer = wxEmptyString;
969 }
970
971 return 0;
972 }
973
974
GetDocAccountName(wxInt32 item,wxString & strBuffer) const975 void CViewProjects::GetDocAccountName(wxInt32 item, wxString& strBuffer) const {
976 PROJECT* project = NULL;
977 CMainDocument* pDoc = wxGetApp().GetDocument();
978
979 if (pDoc) {
980 project = pDoc->project(item);
981 }
982
983 if (project) {
984 strBuffer = HtmlEntityDecode(wxString(project->user_name.c_str(), wxConvUTF8));
985 } else {
986 strBuffer = wxEmptyString;
987 }
988 }
989
990
FormatAccountName(wxInt32 item,wxString & strBuffer) const991 wxInt32 CViewProjects::FormatAccountName(wxInt32 item, wxString& strBuffer) const {
992 CProject* project;
993
994 try {
995 project = m_ProjectCache.at(m_iSortedIndexes[item]);
996 } catch ( std::out_of_range ) {
997 project = NULL;
998 }
999 if (project) {
1000 strBuffer = project->m_strAccountName;
1001 } else {
1002 strBuffer = wxEmptyString;
1003 }
1004
1005 return 0;
1006 }
1007
1008
GetDocTeamName(wxInt32 item,wxString & strBuffer) const1009 void CViewProjects::GetDocTeamName(wxInt32 item, wxString& strBuffer) const {
1010 PROJECT* project = NULL;
1011 CMainDocument* pDoc = wxGetApp().GetDocument();
1012
1013 if (pDoc) {
1014 project = pDoc->project(item);
1015 }
1016
1017 if (project) {
1018 strBuffer = HtmlEntityDecode(wxString(project->team_name.c_str(), wxConvUTF8));
1019 } else {
1020 strBuffer = wxEmptyString;
1021 }
1022 }
1023
1024
FormatTeamName(wxInt32 item,wxString & strBuffer) const1025 wxInt32 CViewProjects::FormatTeamName(wxInt32 item, wxString& strBuffer) const {
1026 CProject* project;
1027
1028 try {
1029 project = m_ProjectCache.at(m_iSortedIndexes[item]);
1030 } catch ( std::out_of_range ) {
1031 project = NULL;
1032 }
1033
1034 if (project) {
1035 strBuffer = project->m_strTeamName;
1036 } else {
1037 strBuffer = wxEmptyString;
1038 }
1039
1040 return 0;
1041 }
1042
1043
GetDocTotalCredit(wxInt32 item,double & fBuffer) const1044 void CViewProjects::GetDocTotalCredit(wxInt32 item, double& fBuffer) const {
1045 PROJECT* project = NULL;
1046 CMainDocument* pDoc = wxGetApp().GetDocument();
1047
1048 if (pDoc) {
1049 project = pDoc->project(item);
1050 }
1051
1052 if (project) {
1053 fBuffer = project->user_total_credit;
1054 } else {
1055 fBuffer = 0.0;
1056 }
1057 }
1058
1059
GetDocAVGCredit(wxInt32 item,double & fBuffer) const1060 void CViewProjects::GetDocAVGCredit(wxInt32 item, double& fBuffer) const {
1061 PROJECT* project = NULL;
1062 CMainDocument* pDoc = wxGetApp().GetDocument();
1063
1064 if (pDoc) {
1065 project = pDoc->project(item);
1066 }
1067
1068 if (project) {
1069 fBuffer = project->user_expavg_credit;
1070 } else {
1071 fBuffer = 0.0;
1072 }
1073 }
1074
GetDocResourceShare(wxInt32 item,double & fBuffer) const1075 void CViewProjects::GetDocResourceShare(wxInt32 item, double& fBuffer) const {
1076 PROJECT* project = NULL;
1077 CMainDocument* pDoc = wxGetApp().GetDocument();
1078
1079 if (pDoc) {
1080 project = pDoc->project(item);
1081 }
1082
1083 if (project) {
1084 fBuffer = project->resource_share;
1085 } else {
1086 fBuffer = 0.0;
1087 }
1088 }
1089
1090
GetDocResourcePercent(wxInt32 item,double & fBuffer) const1091 void CViewProjects::GetDocResourcePercent(wxInt32 item, double& fBuffer) const {
1092 PROJECT* project = NULL;
1093 CMainDocument* pDoc = wxGetApp().GetDocument();
1094
1095 if (pDoc) {
1096 project = pDoc->project(item);
1097 }
1098
1099 if (project && pDoc) {
1100 fBuffer = (project->resource_share / pDoc->m_fProjectTotalResourceShare) * 100;
1101 } else {
1102 fBuffer = 0.0;
1103 }
1104 }
1105
1106
FormatResourceShare(double share,double share_pct,wxString & strBuffer) const1107 wxInt32 CViewProjects::FormatResourceShare(double share, double share_pct, wxString& strBuffer) const {
1108 strBuffer.Printf(wxT("%s (%s%%)"), format_number(share, 0), format_number(share_pct, 2));
1109
1110 return 0;
1111 }
1112
rpc_reason_string_translated(int reason)1113 wxString rpc_reason_string_translated(int reason) {
1114 switch (reason) {
1115 case RPC_REASON_USER_REQ: return _("Requested by user");
1116 case RPC_REASON_NEED_WORK: return _("To fetch work");
1117 case RPC_REASON_RESULTS_DUE: return _("To report completed tasks");
1118 case RPC_REASON_TRICKLE_UP: return _("To send trickle-up message");
1119 case RPC_REASON_ACCT_MGR_REQ: return _("Requested by account manager");
1120 case RPC_REASON_INIT: return _("Project initialization");
1121 case RPC_REASON_PROJECT_REQ: return _("Requested by project");
1122 default: return _("Unknown reason");
1123 }
1124 }
1125
GetDocStatus(wxInt32 item,wxString & strBuffer) const1126 void CViewProjects::GetDocStatus(wxInt32 item, wxString& strBuffer) const {
1127 PROJECT* project = NULL;
1128 CMainDocument* pDoc = wxGetApp().GetDocument();
1129
1130 if (pDoc) {
1131 project = pDoc->project(item);
1132 }
1133
1134 if (project) {
1135 if (project->suspended_via_gui) {
1136 append_to_status(strBuffer, _("Suspended by user"));
1137 }
1138 if (project->dont_request_more_work) {
1139 append_to_status(strBuffer, _("Won't get new tasks"));
1140 }
1141 if (project->ended) {
1142 append_to_status(strBuffer, _("Project ended - OK to remove"));
1143 }
1144 if (project->detach_when_done) {
1145 append_to_status(strBuffer, _("Will remove when tasks done"));
1146 }
1147 if (project->sched_rpc_pending) {
1148 append_to_status(strBuffer, _("Scheduler request pending"));
1149 append_to_status(strBuffer,
1150 rpc_reason_string_translated(project->sched_rpc_pending)
1151 );
1152 }
1153 if (project->scheduler_rpc_in_progress) {
1154 append_to_status(strBuffer, _("Scheduler request in progress"));
1155 }
1156 if (project->trickle_up_pending) {
1157 append_to_status(strBuffer, _("Trickle up message pending"));
1158 }
1159 wxDateTime dtNextRPC((time_t)project->min_rpc_time);
1160 wxDateTime dtNow(wxDateTime::Now());
1161 if (dtNextRPC > dtNow) {
1162 wxTimeSpan tsNextRPC(dtNextRPC - dtNow);
1163 append_to_status(strBuffer, _("Communication deferred") + wxString(" ") + tsNextRPC.Format());
1164 }
1165 }
1166 }
1167
1168
FormatStatus(wxInt32 item,wxString & strBuffer) const1169 wxInt32 CViewProjects::FormatStatus(wxInt32 item, wxString& strBuffer) const {
1170 CProject* project;
1171
1172 try {
1173 project = m_ProjectCache.at(m_iSortedIndexes[item]);
1174 } catch ( std::out_of_range ) {
1175 project = NULL;
1176 }
1177
1178 if (project) {
1179 strBuffer = project->m_strStatus;
1180 } else {
1181 strBuffer = wxEmptyString;
1182 }
1183
1184 return 0;
1185 }
1186
1187
GetDocProjectURL(wxInt32 item,wxString & strBuffer) const1188 void CViewProjects::GetDocProjectURL(wxInt32 item, wxString& strBuffer) const {
1189 PROJECT* project = NULL;
1190 CMainDocument* pDoc = wxGetApp().GetDocument();
1191
1192 if (pDoc) {
1193 project = pDoc->project(item);
1194 }
1195
1196 if (project) {
1197 strBuffer = wxString(project->master_url, wxConvUTF8);
1198 } else {
1199 strBuffer = wxEmptyString;
1200 }
1201 }
1202
1203
GetProgressValue(long item)1204 double CViewProjects::GetProgressValue(long item) {
1205 CProject* project;
1206
1207 try {
1208 project = m_ProjectCache.at(m_iSortedIndexes[item]);
1209 } catch ( std::out_of_range ) {
1210 project = NULL;
1211 }
1212
1213 if (project) {
1214 return (project->m_fResourcePercent) / 100.0;
1215 }
1216
1217 return 0.0;
1218 }
1219
1220
GetProgressText(long item)1221 wxString CViewProjects::GetProgressText( long item) {
1222 CProject* project = NULL;
1223 wxString strBuffer = wxEmptyString;
1224
1225 try {
1226 project = m_ProjectCache.at(m_iSortedIndexes[item]);
1227 } catch ( std::out_of_range ) {
1228 project = NULL;
1229 }
1230
1231 if (project) {
1232 strBuffer = project->m_strResourceShare;
1233 }
1234 return strBuffer;
1235 }
1236
1237
IsWebsiteLink(const wxString & strLink)1238 bool CViewProjects::IsWebsiteLink(const wxString& strLink) {
1239 bool bReturnValue = false;
1240
1241 if (strLink.StartsWith(wxT("web:")))
1242 bReturnValue = true;
1243
1244 return bReturnValue;
1245 }
1246
1247
ConvertWebsiteIndexToLink(wxInt32 iProjectIndex,wxInt32 iWebsiteIndex,wxString & strLink)1248 wxInt32 CViewProjects::ConvertWebsiteIndexToLink(wxInt32 iProjectIndex, wxInt32 iWebsiteIndex, wxString& strLink) {
1249 strLink.Printf(wxT("web:%d:%d"), iProjectIndex, iWebsiteIndex);
1250 return 0;
1251 }
1252
1253
ConvertLinkToWebsiteIndex(const wxString & strLink,wxInt32 & iProjectIndex,wxInt32 & iWebsiteIndex)1254 wxInt32 CViewProjects::ConvertLinkToWebsiteIndex(const wxString& strLink, wxInt32& iProjectIndex, wxInt32& iWebsiteIndex) {
1255 wxString strTemplate = strLink;
1256 wxString strBuffer = wxEmptyString;
1257 long lProjectIndex, lWebsiteIndex;
1258
1259 strTemplate.Replace(wxT("web:"), wxEmptyString);
1260
1261 strBuffer = strTemplate;
1262 strBuffer.Remove(strBuffer.Find(wxT(":")));
1263 strBuffer.ToLong((long*) &lProjectIndex);
1264 iProjectIndex = lProjectIndex;
1265
1266 strBuffer = strTemplate;
1267 strBuffer = strBuffer.Mid(strBuffer.Find(wxT(":")) + 1);
1268 strBuffer.ToLong((long*) &lWebsiteIndex);
1269 iWebsiteIndex = lWebsiteIndex;
1270
1271 return 0;
1272 }
1273
1274
GetProjectCacheAtIndex(CProject * & projectPtr,int index)1275 int CViewProjects::GetProjectCacheAtIndex(CProject*& projectPtr, int index) {
1276 try {
1277 projectPtr = m_ProjectCache.at(index);
1278 } catch ( std::out_of_range ) {
1279 projectPtr = NULL;
1280 return -1;
1281 }
1282
1283 return 0;
1284 }
1285
1286