15.1.658. tablet_qt/tasks/cpftresearchpreferences.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/>.
*/

#include <QPointer>
#include <QString>
#include <QStringList>
#include <QVector>

#include "cpftresearchpreferences.h"

#include "core/camcopsapp.h"
#include "db/databasemanager.h"
#include "db/databaseobject.h"
#include "lib/uifunc.h"
#include "questionnairelib/namevalueoptions.h"
#include "questionnairelib/namevaluepair.h"
#include "questionnairelib/quboolean.h"
#include "questionnairelib/questionnaire.h"
#include "questionnairelib/quheading.h"
#include "questionnairelib/qumcq.h"
#include "questionnairelib/qupage.h"
#include "questionnairelib/quspacer.h"
#include "questionnairelib/qutext.h"
#include "tasklib/taskfactory.h"
#include "tasklib/taskregistrar.h"

const QString CPFTResearchPreferences::CPFTRESEARCHPREFERENCES_TABLENAME(
    "cpft_research_preferences");

// Field names
const QString FN_CONTACT_PREFERENCE("contact_preference");
const QString FN_CONTACT_BY_EMAIL("contact_by_email");
const QString FN_RESEARCH_OPT_OUT("research_opt_out");

const QString Q_XML_PREFIX = "q_";

const QChar CHOICE_RED = 'R';
const QChar CHOICE_YELLOW = 'Y';
const QChar CHOICE_GREEN = 'G';


void initializeCPFTResearchPreferences(TaskFactory& factory)
{
    static TaskRegistrar<CPFTResearchPreferences> registered(factory);
}


CPFTResearchPreferences::CPFTResearchPreferences(
        CamcopsApp& app, DatabaseManager& db, const int load_pk) :
    Task(app, db, CPFTRESEARCHPREFERENCES_TABLENAME,
         false, false, false),  // ... anon, clin, resp
    m_questionnaire(nullptr)
{
    addField(FN_CONTACT_PREFERENCE, QMetaType::fromType<QChar>());
    addField(FN_CONTACT_BY_EMAIL, QMetaType::fromType<bool>());
    addField(FN_RESEARCH_OPT_OUT,
             QMetaType::fromType<bool>(),
             true,   // Mandatory
             false,  // Unique
             false,  // pk
             false); // default

    load(load_pk);  // MUST ALWAYS CALL from derived Task constructor.
}


// ============================================================================
// Class info
// ============================================================================

QString CPFTResearchPreferences::shortname() const
{
    return "CPFT_Research_Preferences";
}


QString CPFTResearchPreferences::longname() const
{
    return tr("CPFT Research Preferences");
}


QString CPFTResearchPreferences::description() const
{
    return tr("CPFT patients' preferences for being contacted about research");
}


// ============================================================================
// Instance info
// ============================================================================

bool CPFTResearchPreferences::isComplete() const
{
    if (valueIsNull(FN_CONTACT_PREFERENCE)) {
        return false;
    }

    if (emailQuestionMandatory()) {
        return !valueIsNull(FN_CONTACT_BY_EMAIL);
    }

    // Opt-out defaults to false

    return true;
}


QStringList CPFTResearchPreferences::summary() const
{
    QStringList lines;

    const QString fmt = QString("%1: <b>%2</b><br>");

    lines.append(fmt.arg(xstring(Q_XML_PREFIX + FN_CONTACT_PREFERENCE + "_short"),
                         xstring(valueQChar(FN_CONTACT_PREFERENCE), "?")));
    lines.append(fmt.arg(xstring(Q_XML_PREFIX + FN_CONTACT_BY_EMAIL + "_short"),
                         uifunc::yesNoNull(value(FN_CONTACT_BY_EMAIL))));
    lines.append(fmt.arg(xstring(Q_XML_PREFIX + FN_RESEARCH_OPT_OUT + "_short"),
                         uifunc::yesNo(valueBool(FN_RESEARCH_OPT_OUT))));

    return lines;
}


QStringList CPFTResearchPreferences::detail() const
{
    return completenessInfo() + summary();
}


OpenableWidget* CPFTResearchPreferences::editor(const bool read_only)
{
    QuPagePtr page(new QuPage);
    page->setTitle(description());
    page->addElement(new QuHeading(xstring("title")));
    page->addElement(new QuText(xstring("intro")));

    page->addElement((new QuText(xstring("decisions")))->setBold(true)->setItalic(true));
    page->addElement(new QuSpacer(QSize(uiconst::BIGSPACE, uiconst::BIGSPACE)));
    page->addElement((new QuText(xstring("research_info")))->setOpenLinks());
    page->addElement((new QuText(xstring("database_info")))->setOpenLinks());
    page->addElement(new QuSpacer(QSize(uiconst::BIGSPACE, uiconst::BIGSPACE)));
    page->addElement((new QuText(xstring("permission")))->setBold(true)->setItalic(true));
    page->addElement(new QuSpacer(QSize(uiconst::BIGSPACE, uiconst::BIGSPACE)));
    page->addElement((new QuText(xstring(Q_XML_PREFIX + FN_CONTACT_PREFERENCE)))->setBold(true));
    NameValueOptions contact_options;
    contact_options.append(
        NameValuePair(
            xstring(Q_XML_PREFIX + FN_CONTACT_PREFERENCE + "_option_R"),
            CHOICE_RED
        )
    );
    contact_options.append(
        NameValuePair(
            xstring(Q_XML_PREFIX + FN_CONTACT_PREFERENCE + "_option_Y"),
            CHOICE_YELLOW
        )
    );
    contact_options.append(
        NameValuePair(
            xstring(Q_XML_PREFIX + FN_CONTACT_PREFERENCE + "_option_G"),
            CHOICE_GREEN
        )
    );

    QStringList contact_styles = {"color:white; background-color:red;",
                                  "color:black; background-color:yellow;",
                                  "color:white; background-color:green;"};

    FieldRefPtr fieldref = fieldRef(FN_CONTACT_PREFERENCE);
    connect(fieldref.data(), &FieldRef::valueChanged,
            this, &CPFTResearchPreferences::updateEmailQuestion);

    page->addElement(new QuMcq(fieldref, contact_options, &contact_styles));
    page->addElement(new QuSpacer(QSize(uiconst::BIGSPACE, uiconst::BIGSPACE)));

    auto email_text = new QuText(xstring(Q_XML_PREFIX + FN_CONTACT_BY_EMAIL));
    email_text->setBold(true);
    email_text->addTag(FN_CONTACT_BY_EMAIL);

    page->addElement(email_text);
    NameValueOptions email_options;
    email_options.append(NameValuePair(xstring(Q_XML_PREFIX + FN_CONTACT_BY_EMAIL + "_option_Y"), true));
    email_options.append(NameValuePair(xstring(Q_XML_PREFIX + FN_CONTACT_BY_EMAIL + "_option_N"), false));

    auto email_mcq = new QuMcq(fieldRef(FN_CONTACT_BY_EMAIL), email_options);
    page->addElement(email_mcq);
    email_mcq->addTag(FN_CONTACT_BY_EMAIL);
    auto email_spacer = new QuSpacer(QSize(uiconst::BIGSPACE, uiconst::BIGSPACE));
    email_spacer->addTag(FN_CONTACT_BY_EMAIL);
    page->addElement(email_spacer);

    auto opt_out_text = new QuText(xstring(Q_XML_PREFIX + FN_RESEARCH_OPT_OUT+ "_intro"));
    opt_out_text->setBold(true);
    page->addElement(opt_out_text);
    auto opt_out_checkbox = new QuBoolean(xstring(Q_XML_PREFIX + FN_RESEARCH_OPT_OUT),
                                          fieldRef(FN_RESEARCH_OPT_OUT));
    opt_out_checkbox->setFalseAppearsBlank();
    page->addElement(opt_out_checkbox);
    page->addElement(new QuSpacer(QSize(uiconst::BIGSPACE, uiconst::BIGSPACE)));

    QVector<QuPagePtr> pages{page};

    m_questionnaire = new Questionnaire(m_app, pages);
    m_questionnaire->setType(QuPage::PageType::Patient);
    m_questionnaire->setReadOnly(read_only);

    updateEmailQuestion();

    return m_questionnaire;
}


// ============================================================================
// Signal handlers
// ============================================================================

void CPFTResearchPreferences::updateEmailQuestion()
{
    const bool mandatory = emailQuestionMandatory();

    if (mandatory) {
        fieldRef(FN_CONTACT_BY_EMAIL)->setMandatory(mandatory);
    }

    if (m_questionnaire) {
        m_questionnaire->setVisibleByTag(FN_CONTACT_BY_EMAIL, mandatory);
    }
}


bool CPFTResearchPreferences::emailQuestionMandatory() const
{
   return valueQChar(FN_CONTACT_PREFERENCE) != 'R';
}