mirror of https://github.com/BOINC/boinc.git
338 lines
10 KiB
C++
338 lines
10 KiB
C++
// This file is part of BOINC.
|
|
// http://boinc.berkeley.edu
|
|
// Copyright (C) 2022 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 "BOINCTaskCtrl.h"
|
|
#endif
|
|
|
|
#include "stdwx.h"
|
|
#include "BOINCBaseView.h"
|
|
#include "BOINCTaskCtrl.h"
|
|
#include "MainDocument.h"
|
|
|
|
const int taskPaneWidth = 200;
|
|
const int taskButtonWidth = taskPaneWidth - 55;
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(CBOINCTaskCtrl, wxScrolledWindow)
|
|
|
|
#ifdef __WXMSW__
|
|
BEGIN_EVENT_TABLE (CBOINCTaskCtrl, CBOINCBaseView)
|
|
EVT_CHILD_FOCUS(CBOINCTaskCtrl::OnChildFocus)
|
|
END_EVENT_TABLE ()
|
|
#endif
|
|
|
|
|
|
CBOINCTaskCtrl::CBOINCTaskCtrl() {}
|
|
|
|
|
|
CBOINCTaskCtrl::CBOINCTaskCtrl(CBOINCBaseView* pView, wxWindowID iTaskWindowID, wxInt32 iTaskWindowFlags) :
|
|
wxScrolledWindow(pView, iTaskWindowID, wxDefaultPosition, wxSize(taskPaneWidth, -1), iTaskWindowFlags)
|
|
{
|
|
m_pParent = pView;
|
|
m_pSizer = NULL;
|
|
|
|
SetVirtualSize( taskPaneWidth, 1000 );
|
|
EnableScrolling(false, true);
|
|
SetScrollRate( 0, 10 );
|
|
}
|
|
|
|
|
|
CBOINCTaskCtrl::~CBOINCTaskCtrl() {}
|
|
|
|
|
|
wxInt32 CBOINCTaskCtrl::DeleteTaskGroupAndTasks( CTaskItemGroup* pGroup ) {
|
|
unsigned int i;
|
|
CTaskItem* pItem = NULL;
|
|
|
|
for (i=0; i < pGroup->m_Tasks.size(); i++) {
|
|
pItem = pGroup->m_Tasks[i];
|
|
DeleteTask(pGroup, pItem);
|
|
}
|
|
if (pGroup->m_pStaticBoxSizer) {
|
|
m_pSizer->Detach(pGroup->m_pStaticBoxSizer);
|
|
pGroup->m_pStaticBoxSizer->Detach(pGroup->m_pStaticBox);
|
|
|
|
delete pGroup->m_pStaticBox;
|
|
delete pGroup->m_pStaticBoxSizer;
|
|
|
|
pGroup->m_pStaticBox = NULL;
|
|
pGroup->m_pStaticBoxSizer = NULL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
wxInt32 CBOINCTaskCtrl::DisableTaskGroupTasks( CTaskItemGroup* pGroup ) {
|
|
unsigned int i;
|
|
CTaskItem* pItem = NULL;
|
|
|
|
if (pGroup) {
|
|
for (i=0; i < pGroup->m_Tasks.size(); i++) {
|
|
pItem = pGroup->m_Tasks[i];
|
|
DisableTask(pItem);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
wxInt32 CBOINCTaskCtrl::EnableTaskGroupTasks( CTaskItemGroup* pGroup ) {
|
|
unsigned int i;
|
|
CTaskItem* pItem = NULL;
|
|
|
|
if (pGroup) {
|
|
for (i=0; i < pGroup->m_Tasks.size(); i++) {
|
|
pItem = pGroup->m_Tasks[i];
|
|
EnableTask(pItem);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
wxInt32 CBOINCTaskCtrl::DeleteTask( CTaskItemGroup* pGroup, CTaskItem* pItem ) {
|
|
if (pItem->m_pButton) {
|
|
pGroup->m_pStaticBoxSizer->Detach(pItem->m_pButton);
|
|
delete pItem->m_pButton;
|
|
pItem->m_pButton = NULL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
wxInt32 CBOINCTaskCtrl::DisableTask( CTaskItem* pItem ) {
|
|
if (pItem->m_pButton) {
|
|
pItem->m_pButton->Disable();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
wxInt32 CBOINCTaskCtrl::EnableTask( CTaskItem* pItem ) {
|
|
if (pItem->m_pButton) {
|
|
pItem->m_pButton->Enable();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
wxInt32 CBOINCTaskCtrl::UpdateTask( CTaskItem* pItem, wxString strName, wxString strDescription ) {
|
|
if (pItem->m_pButton) {
|
|
if (!pItem->m_strName.Cmp(strName) &&
|
|
!pItem->m_strDescription.Cmp(strDescription)) {
|
|
return 0;
|
|
}
|
|
pItem->m_strName = strName;
|
|
pItem->m_strNameEllipsed = pItem->m_strName;
|
|
EllipseStringIfNeeded(pItem->m_strNameEllipsed);
|
|
pItem->m_strDescription = strDescription;
|
|
pItem->m_pButton->SetLabel( pItem->m_strNameEllipsed );
|
|
pItem->m_pButton->SetHelpText( strDescription );
|
|
#if wxUSE_TOOLTIPS
|
|
pItem->m_pButton->SetToolTip(pItem->m_strDescription);
|
|
#endif
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
wxInt32 CBOINCTaskCtrl::UpdateControls() {
|
|
unsigned int i;
|
|
unsigned int j;
|
|
bool bCreateMainSizer = false;
|
|
int layoutChanged = 0;
|
|
CTaskItemGroup* pGroup = NULL;
|
|
CTaskItem* pItem = NULL;
|
|
|
|
|
|
bCreateMainSizer = !GetSizer();
|
|
if (bCreateMainSizer) {
|
|
SetAutoLayout(TRUE);
|
|
m_pSizer = new wxBoxSizer( wxVERTICAL );
|
|
m_pSizer->Add(5, 5, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);
|
|
layoutChanged = 1;
|
|
}
|
|
|
|
|
|
// Create static boxes and sizers if they don't exist
|
|
for (i=0; i < m_pParent->m_TaskGroups.size(); i++) {
|
|
pGroup = m_pParent->m_TaskGroups[i];
|
|
if (!pGroup->m_pStaticBoxSizer) {
|
|
pGroup->m_pStaticBox = new wxStaticBox(this, wxID_ANY, pGroup->m_strName);
|
|
pGroup->m_pStaticBoxSizer = new wxStaticBoxSizer(pGroup->m_pStaticBox, wxVERTICAL);
|
|
m_pSizer->Add(pGroup->m_pStaticBoxSizer, 0, wxEXPAND|wxALL, 5);
|
|
layoutChanged = 1;
|
|
}
|
|
}
|
|
|
|
// Create buttons if they don't exist
|
|
for (i=0; i < m_pParent->m_TaskGroups.size(); i++) {
|
|
pGroup = m_pParent->m_TaskGroups[i];
|
|
for (j=0; j < pGroup->m_Tasks.size(); j++) {
|
|
pItem = pGroup->m_Tasks[j];
|
|
if (!pItem->m_pButton) {
|
|
pItem->m_pButton = new wxButton;
|
|
pItem->m_strNameEllipsed = pItem->m_strName;
|
|
EllipseStringIfNeeded(pItem->m_strNameEllipsed);
|
|
#ifdef __WXMSW__
|
|
// On Windows with wxWidgets 2.9.4, buttons don't refresh properly unless
|
|
// they are children of the wxStaticBox, but on Mac the layout is wrong
|
|
// unless the buttons are children of the parent of the wxStaticBox.
|
|
// ToDo: merge these cases when these bugs are fixed in wxWidgets.
|
|
pItem->m_pButton->Create(pGroup->m_pStaticBox, pItem->m_iEventID, pItem->m_strNameEllipsed, wxDefaultPosition, wxSize(taskButtonWidth, -1), 0);
|
|
#else
|
|
pItem->m_pButton->Create(this, pItem->m_iEventID, pItem->m_strNameEllipsed, wxDefaultPosition, wxSize(taskButtonWidth, -1), 0);
|
|
#endif
|
|
pItem->m_pButton->SetHelpText(pItem->m_strDescription);
|
|
#if wxUSE_TOOLTIPS
|
|
pItem->m_pButton->SetToolTip(pItem->m_strDescription);
|
|
#endif
|
|
pGroup->m_pStaticBoxSizer->Add(pItem->m_pButton, 0, wxEXPAND|wxALL, 5);
|
|
layoutChanged = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bCreateMainSizer) {
|
|
SetSizer(m_pSizer);
|
|
}
|
|
|
|
// Force update layout and scrollbars, since nothing we do here
|
|
// necessarily generates a size event which would do it for us.
|
|
if (layoutChanged) {
|
|
Fit ();
|
|
}
|
|
|
|
return layoutChanged;
|
|
}
|
|
|
|
|
|
bool CBOINCTaskCtrl::OnSaveState(wxConfigBase* pConfig) {
|
|
wxString strBaseConfigLocation = wxEmptyString;
|
|
|
|
wxASSERT(pConfig);
|
|
|
|
|
|
// Retrieve the base location to store configuration information
|
|
// Should be in the following form: "/Projects/"
|
|
strBaseConfigLocation = pConfig->GetPath() + wxT("/");
|
|
|
|
pConfig->SetPath(strBaseConfigLocation + wxT("TaskCtrl/"));
|
|
|
|
//WriteCustomization(pConfig);
|
|
|
|
pConfig->SetPath(strBaseConfigLocation);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CBOINCTaskCtrl::OnRestoreState(wxConfigBase* pConfig) {
|
|
wxString strBaseConfigLocation = wxEmptyString;
|
|
|
|
wxASSERT(pConfig);
|
|
|
|
|
|
// Retrieve the base location to store configuration information
|
|
// Should be in the following form: "/Projects/"
|
|
strBaseConfigLocation = pConfig->GetPath() + wxT("/");
|
|
|
|
pConfig->SetPath(strBaseConfigLocation + wxT("TaskCtrl/"));
|
|
|
|
//ReadCustomization(pConfig);
|
|
|
|
pConfig->SetPath(strBaseConfigLocation);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
#ifdef __WXMSW__
|
|
// Work around a problem on Windows where clicking on a button
|
|
// in the web sites Task Item Group sometimes causes the task
|
|
// control panel to scroll that button out of view but does not
|
|
// send the button clicked event. This is because the task
|
|
// control panel is the parent of the Task Item Group's
|
|
// wxStaticBox, which is the parent of the button; if we have
|
|
// scroll bars the Child Focus Event scrolls the task control
|
|
// panel to make the wxStaticBox fully visible. To prevent this,
|
|
// we intercept the Child Focus Event, scroll only enough to
|
|
// make the button visible if it is not already visible, and
|
|
// do not call event.Skip.
|
|
void CBOINCTaskCtrl::OnChildFocus(wxChildFocusEvent&) {
|
|
int stepx, stepy;
|
|
int startx, starty;
|
|
int diff = 0;
|
|
|
|
wxWindow* theButton = wxWindow::FindFocus();
|
|
if (!theButton) return;
|
|
|
|
// Get button position relative to Task Control's viewing area
|
|
wxRect buttonRect(
|
|
ScreenToClient(theButton->GetScreenPosition()), theButton->GetSize()
|
|
);
|
|
|
|
const wxRect viewRect(GetClientRect());
|
|
if (viewRect.Contains(buttonRect)){
|
|
return; // Already fully visible
|
|
}
|
|
|
|
GetScrollPixelsPerUnit(&stepx, &stepy);
|
|
|
|
GetViewStart(&startx, &starty);
|
|
|
|
if (buttonRect.GetTop() < 0) {
|
|
diff = buttonRect.GetTop();
|
|
} else if (buttonRect.GetBottom() > viewRect.GetHeight()) {
|
|
diff = buttonRect.GetBottom() - viewRect.GetHeight() + 1;
|
|
// round up to next scroll step if we can't get exact position,
|
|
// so that the button is fully visible
|
|
diff += stepy - 1;
|
|
}
|
|
|
|
starty = (starty * stepy + diff) / stepy;
|
|
Scroll(startx, starty);
|
|
}
|
|
#endif
|
|
|
|
|
|
void CBOINCTaskCtrl::EllipseStringIfNeeded(wxString& s) {
|
|
int w, h;
|
|
const int maxWidth = taskButtonWidth - 10;
|
|
|
|
GetTextExtent(s, &w, &h);
|
|
|
|
// Adapted from ellipis code in wxRendererGeneric::DrawHeaderButtonContents()
|
|
if (w > maxWidth) {
|
|
int ellipsisWidth;
|
|
GetTextExtent( wxT("..."), &ellipsisWidth, NULL);
|
|
if (ellipsisWidth > maxWidth) {
|
|
s.Clear();
|
|
w = 0;
|
|
} else {
|
|
do {
|
|
s.Truncate( s.length() - 1 );
|
|
GetTextExtent( s, &w, &h);
|
|
} while (((w + ellipsisWidth) > maxWidth) && s.length() );
|
|
s.append( wxT("...") );
|
|
}
|
|
}
|
|
}
|