15.1.331. tablet_qt/menu/singletaskmenu.cpp¶
/*
Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
Created by Rudolf Cardinal (rnc1001@cam.ac.uk).
This file is part of CamCOPS.
CamCOPS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CamCOPS 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
*/
// #define DEBUG_TASK_MENU_CREATION
#include "singletaskmenu.h"
#include <QPushButton>
#include "common/uiconst.h"
#include "common/urlconst.h"
#include "dbobjects/patient.h"
#include "dialogs/scrollmessagebox.h"
#include "lib/uifunc.h"
#include "lib/stringfunc.h"
#include "menulib/menuheader.h"
#include "menulib/menuitem.h"
#include "tasklib/task.h"
#include "tasklib/taskfactory.h"
SingleTaskMenu::SingleTaskMenu(const QString& tablename, CamcopsApp& app) :
MenuWindow(app, ""), // start with a blank title
m_tablename(tablename)
{
}
void SingleTaskMenu::extraLayoutCreation()
{
// Title
TaskFactory* factory = m_app.taskFactory();
TaskPtr specimen = factory->create(m_tablename);
m_anonymous = specimen->isAnonymous();
if (m_anonymous) {
setIcon(uifunc::iconFilename(uiconst::ICON_ANONYMOUS));
}
const bool crippled = specimen->isCrippled();
m_p_header->setCrippled(crippled);
// m_items is EXPENSIVE (and depends on security), so leave it to build()
// Signals
connect(&m_app, &CamcopsApp::selectedPatientChanged,
this, &SingleTaskMenu::selectedPatientChanged,
Qt::UniqueConnection);
connect(&m_app, &CamcopsApp::taskAlterationFinished,
this, &SingleTaskMenu::refreshTaskList,
Qt::UniqueConnection);
connect(&m_app, &CamcopsApp::lockStateChanged,
this, &SingleTaskMenu::refreshTaskList,
Qt::UniqueConnection);
connect(m_p_header, &MenuHeader::addClicked,
this, &SingleTaskMenu::addTask,
Qt::UniqueConnection);
}
QString SingleTaskMenu::title() const
{
TaskFactory* factory = m_app.taskFactory();
TaskPtr specimen = factory->create(m_tablename);
return specimen->menutitle();
}
void SingleTaskMenu::makeItems()
{
TaskFactory* factory = m_app.taskFactory();
TaskPtr specimen = factory->create(m_tablename);
// Common items
const QString info_icon_filename = uifunc::iconFilename(uiconst::ICON_INFO);
m_items = {
MenuItem(tr("Options")).setLabelOnly(),
};
if (!m_anonymous) {
m_items.append(MAKE_CHANGE_PATIENT(m_app));
}
m_items.append(
MenuItem(
tr("Task information"),
UrlMenuItem(
urlconst::taskDocUrl(specimen->infoFilenameStem())
),
info_icon_filename
)
);
m_items.append(MenuItem(tr("Task status"),
std::bind(&SingleTaskMenu::showTaskStatus, this),
info_icon_filename));
m_items.append(
MenuItem(
tr("Task instances") + ": " + specimen->menutitle()
).setLabelOnly()
);
// Task items
TaskPtrList tasklist = factory->fetchTasks(m_tablename);
#ifdef DEBUG_TASK_MENU_CREATION
qDebug() << Q_FUNC_INFO << "-" << tasklist.size() << "tasks";
#endif
const bool show_patient_name = specimen->isAnonymous() ||
!m_app.isPatientSelected();
for (const TaskPtr& task : tasklist) {
m_items.append(MenuItem(task, false, show_patient_name));
}
}
void SingleTaskMenu::afterBuild()
{
emit offerAdd(m_anonymous || m_app.isPatientSelected());
}
void SingleTaskMenu::addTask()
{
// The task we create here needs to stay in scope for the duration of the
// editing! The simplest way is to use a member object to hold the pointer.
TaskFactory* factory = m_app.taskFactory();
TaskPtr task = factory->create(m_tablename);
QString failure_reason;
// ------------------------------------------------------------------------
// Hard stops: reasons we may say no
// ------------------------------------------------------------------------
// Task not permitted?
// (Intellectual property restriction, or lack of correct string data.)
if (!task->isTaskPermissible(failure_reason)) {
const QString reason = QString("%1<br><br>%2: %3").arg(
tr("You cannot add this task with your current settings."),
tr("Current reason"),
stringfunc::bold(failure_reason)
);
uifunc::alert(reason, tr("Not permitted to add task"));
return;
}
// No patient selected, but trying to create task requiring a patient?
const int patient_id = m_app.selectedPatientId();
if (!task->isAnonymous()) {
if (patient_id == dbconst::NONEXISTENT_PK) {
qCritical() << Q_FUNC_INFO << "- no patient selected";
return;
}
}
// ------------------------------------------------------------------------
// Soft stops: reasons the user may want to pause
// ------------------------------------------------------------------------
// Not able to upload at present?
if (!task->isTaskUploadable(failure_reason)) {
ScrollMessageBox msgbox(
QMessageBox::Warning,
tr("Really create?"),
tr("This task is not currently uploadable.") + "\n\n" +
failure_reason + "\n\n" + tr("Create anyway?"),
this
);
QAbstractButton* yes = msgbox.addButton(tr("Yes, create"),
QMessageBox::YesRole);
msgbox.addButton(tr("No, cancel"), QMessageBox::NoRole);
msgbox.exec();
if (msgbox.clickedButton() != yes) {
return;
}
}
// OK; off we go!
task->setupForEditingAndSave(patient_id);
editTaskConfirmed(task);
}
void SingleTaskMenu::selectedPatientChanged(const Patient* patient)
{
refreshTaskList();
emit offerAdd(m_anonymous || patient);
}
void SingleTaskMenu::showTaskStatus() const
{
TaskFactory* factory = m_app.taskFactory();
TaskPtr specimen = factory->create(m_tablename);
QStringList info;
QString why_not_permissible;
QString why_not_uploadable;
auto add = [&info](const QString& desc, const QString& value) -> void {
info.append(QString("%1: %2")
.arg(desc, stringfunc::bold(value)));
};
add(tr("Long name"), specimen->longname());
add(tr("Short name"), specimen->shortname());
add(tr("Main database table name"), specimen->tablename());
add(tr("Implementation type"), specimen->implementationTypeDescription());
add(tr("Anonymous"), uifunc::yesNo(specimen->isAnonymous()));
add(tr("Has a clinician"), uifunc::yesNo(specimen->hasClinician()));
add(tr("Has a respondent"), uifunc::yesNo(specimen->hasRespondent()));
add(tr("Prohibits clinical use"), uifunc::yesNo(specimen->prohibitsClinical()));
add(tr("Prohibits commercial use"), uifunc::yesNo(specimen->prohibitsCommercial()));
add(tr("Prohibits educational use"), uifunc::yesNo(specimen->prohibitsEducational()));
add(tr("Prohibits research use"), uifunc::yesNo(specimen->prohibitsResearch()));
add(tr("Extra strings present from server"), uifunc::yesNo(
specimen->hasExtraStrings()));
add(tr("Permissible (creatable) with current settings"), uifunc::yesNo(
specimen->isTaskPermissible(why_not_permissible)));
add(tr("If not, why not permissible"), why_not_permissible);
add(tr("Uploadable to current server"), uifunc::yesNo(
specimen->isTaskUploadable(why_not_uploadable)));
add(tr("If not, why not uploadable"), why_not_uploadable);
add(tr("Fully functional"), uifunc::yesNo(!specimen->isCrippled()));
add(tr("Editable once created"), uifunc::yesNo(specimen->isEditable()));
uifunc::alert(info.join("<br>"), tr("Task status"));
}
void SingleTaskMenu::refreshTaskList()
{
rebuild(false); // no need to recreate hader
}