/*
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/>.
*/
#include "dad.h"
#include "common/textconst.h"
#include "maths/mathfunc.h"
#include "questionnairelib/commonoptions.h"
#include "questionnairelib/questionnaire.h"
#include "questionnairelib/qugridcell.h"
#include "questionnairelib/qugridcontainer.h"
#include "questionnairelib/qumcq.h"
#include "questionnairelib/qutext.h"
#include "tasklib/taskfactory.h"
#include "tasklib/taskregistrar.h"
using mathfunc::noneNull;
const QString Dad::DAD_TABLENAME("dad");
const int YES = 1;
const int NO = 0;
const int NA = -99;
const QString HYGIENE("hygiene");
const QString DRESSING("dressing");
const QString CONTINENCE("continence");
const QString EATING("eating");
const QString MEALPREP("mealprep");
const QString TELEPHONE("telephone");
const QString OUTING("outing");
const QString FINANCE("finance");
const QString MEDICATIONS("medications");
const QString LEISURE("leisure");
const QStringList GROUPS{
HYGIENE,
DRESSING,
CONTINENCE,
EATING,
MEALPREP,
TELEPHONE,
OUTING,
FINANCE,
MEDICATIONS,
LEISURE,
};
const QString INIT("init");
const QString PLAN("plan");
const QString EXEC("exec");
const QStringList ITEMS{
"hygiene_init_wash",
"hygiene_init_teeth",
"hygiene_init_hair",
"hygiene_plan_wash",
"hygiene_exec_wash",
"hygiene_exec_hair",
"hygiene_exec_teeth",
"dressing_init_dress",
"dressing_plan_clothing",
"dressing_plan_order",
"dressing_exec_dress",
"dressing_exec_undress",
"continence_init_toilet",
"continence_exec_toilet",
"eating_init_eat",
"eating_plan_utensils",
"eating_exec_eat",
"mealprep_init_meal",
"mealprep_plan_meal",
"mealprep_exec_meal",
"telephone_init_phone",
"telephone_plan_dial",
"telephone_exec_conversation",
"telephone_exec_message",
"outing_init_outing",
"outing_plan_outing",
"outing_exec_reach_destination",
"outing_exec_mode_transportation",
"outing_exec_return_with_shopping",
"finance_init_interest",
"finance_plan_pay_bills",
"finance_plan_organise_correspondence",
"finance_exec_handle_money",
"medications_init_medication",
"medications_exec_take_medications",
"leisure_init_interest_leisure",
"leisure_init_interest_chores",
"leisure_plan_chores",
"leisure_exec_complete_chores",
"leisure_exec_safe_at_home",
};
const int LEFTCOL_STRETCH = 1;
const int RIGHTCOL_STRETCH = 2;
void initializeDad(TaskFactory& factory)
{
static TaskRegistrar<Dad> registered(factory);
}
Dad::Dad(CamcopsApp& app, DatabaseManager& db, const int load_pk) :
Task(app, db, DAD_TABLENAME, false, true, true) // ... anon, clin, resp
{
for (const QString& item : ITEMS) {
addField(item, QMetaType::fromType<int>());
}
load(load_pk); // MUST ALWAYS CALL from derived Task constructor.
}
// ============================================================================
// Class info
// ============================================================================
QString Dad::shortname() const
{
return "DAD";
}
QString Dad::longname() const
{
return tr("Disability Assessment for Dementia");
}
QString Dad::description() const
{
return tr("40-item clinician-administered, carer-rated scale.");
}
// ============================================================================
// Instance info
// ============================================================================
bool Dad::isComplete() const
{
return noneNull(values(ITEMS));
}
QStringList Dad::summary() const
{
QStringList lines;
lines.append("Total: " + getScore(ITEMS) + ".");
lines.append(
"BADL ACTIVITIES: "
"hygiene "
+ getScore(getItemsActivity(HYGIENE)) + "; dressing "
+ getScore(getItemsActivity(DRESSING)) + "; continence "
+ getScore(getItemsActivity(CONTINENCE)) + "; eating "
+ getScore(getItemsActivity(EATING)) + "."
);
lines.append(
"BADL OVERALL: "
+ getScore(getItemsActivities({HYGIENE, DRESSING, CONTINENCE, EATING}))
+ "."
);
lines.append(
"IADL ACTIVITIES: "
"mealprep "
+ getScore(getItemsActivity(MEALPREP)) + "; telephone "
+ getScore(getItemsActivity(TELEPHONE)) + "; outing "
+ getScore(getItemsActivity(OUTING)) + "; finance "
+ getScore(getItemsActivity(FINANCE)) + "; medications "
+ getScore(getItemsActivity(MEDICATIONS)) + "; leisure "
+ getScore(getItemsActivity(LEISURE)) + "."
);
lines.append(
"BADL OVERALL: "
+ getScore(getItemsActivities(
{MEALPREP, TELEPHONE, OUTING, FINANCE, MEDICATIONS, LEISURE}
))
+ "."
);
lines.append(
"PHASES: "
"initiation "
+ getScore(getItemsPhase(INIT)) + "; planning/organisation "
+ getScore(getItemsPhase(PLAN)) + "; execution/performance "
+ getScore(getItemsPhase(EXEC)) + "."
);
return lines;
}
QStringList Dad::detail() const
{
return completenessInfo() + summary();
}
OpenableWidget* Dad::editor(const bool read_only)
{
const NameValueOptions y_n_na_options{
{CommonOptions::yes(), YES},
{CommonOptions::no(), NO},
{TextConst::notApplicable(), NA},
};
QuPagePtr page1 = getClinicianAndRespondentDetailsPage(false);
QVector<QuElement*> elements{
(new QuText(
xstring("instruction_1") + " " + getPatientName() + " "
+ xstring("instruction_2")
))
->setBold(),
};
for (const QString& groupname : GROUPS) {
elements.append(
(new QuText(xstring(groupname)))->setBold()->setItalic()
);
auto grid = new QuGridContainer();
int row = 0;
grid->setColumnStretch(0, LEFTCOL_STRETCH);
grid->setColumnStretch(1, RIGHTCOL_STRETCH);
for (const QString& itemname : getItemsActivity(groupname)) {
grid->addCell(QuGridCell(new QuText(xstring(itemname)), row, 0));
grid->addCell(QuGridCell(
(new QuMcq(fieldRef(itemname), y_n_na_options))
->setHorizontal(true),
row,
1
));
++row;
}
elements.append(grid);
}
QuPagePtr page2((new QuPage(elements))->setTitle(longname()));
auto questionnaire = new Questionnaire(m_app, {page1, page2});
questionnaire->setType(QuPage::PageType::Clinician);
questionnaire->setReadOnly(read_only);
return questionnaire;
}
// ============================================================================
// Task-specific calculations
// ============================================================================
QStringList Dad::getItemsActivity(const QString& activity) const
{
QStringList activity_items;
for (const QString& item : ITEMS) {
if (item.startsWith(activity)) {
activity_items.append(item);
}
}
return activity_items;
}
QStringList Dad::getItemsActivities(const QStringList& activities) const
{
QStringList activity_items;
for (const QString& item : ITEMS) {
for (const QString& activity : activities) {
if (item.startsWith(activity)) {
activity_items.append(item);
}
}
}
return activity_items;
}
QStringList Dad::getItemsPhase(const QString& phase) const
{
QStringList phase_items;
for (const QString& item : ITEMS) {
if (item.contains(phase)) {
phase_items.append(item);
}
}
return phase_items;
}
QString Dad::getScore(const QStringList& fieldnames) const
{
const QVector<QVariant> v = values(fieldnames);
const int score = mathfunc::countWhere(v, QVector<QVariant>{YES});
const int possible
= mathfunc::countWhereNot(v, QVector<QVariant>{QVariant(), NA});
return mathfunc::scoreString(score, possible);
}