15.1.461. tablet_qt/questionnairelib/quheight.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 "quheight.h"
#include <QObject>
#include <QString>
#include <QWidget>
#include "db/fieldref.h"
#include "layouts/layouts.h"
#include "lib/convert.h"
#include "questionnairelib/commonoptions.h"
#include "questionnairelib/questionnaire.h"
#include "questionnairelib/questionnairefunc.h"
#include "questionnairelib/qulineeditdouble.h"
#include "questionnairelib/qulineeditinteger.h"
#include "questionnairelib/quunitselector.h"
#include "questionnairelib/qumcq.h"


QuHeight::QuHeight(FieldRefPtr fieldref, QPointer<QuUnitSelector> unit_selector)
    : QuMeasurement(fieldref, unit_selector),
    m_fr_m(nullptr),
    m_fr_ft(nullptr),
    m_fr_in(nullptr)
{
}


FieldRefPtrList QuHeight::getMetricFieldrefs() const
{
    return FieldRefPtrList({m_fr_m});
}


FieldRefPtrList QuHeight::getImperialFieldrefs() const
{
    return FieldRefPtrList({m_fr_ft, m_fr_in});
}

QPointer<QuElement> QuHeight::buildMetricGrid()
{
    auto metres_edit = new QuLineEditDouble(m_fr_m, 0, 5, 3);
    return questionnairefunc::defaultGridRawPointer(
        {
            {CommonOptions::metres(), metres_edit},
        },
        1, 1);
}


QPointer<QuElement> QuHeight::buildImperialGrid()
{
    auto ft_edit = new QuLineEditInteger(m_fr_ft, 0, 15);
    auto in_edit = new QuLineEditDouble(m_fr_in, 0, convert::INCHES_PER_FOOT, 2);

    return questionnairefunc::defaultGridRawPointer(
        {
            {CommonOptions::feet(), ft_edit},
            {CommonOptions::inches(), in_edit},
        }, 1, 1);
}


void QuHeight::setUpFields()
{
    FieldRef::GetterFunction get_m = std::bind(&QuHeight::getM, this);
    FieldRef::GetterFunction get_ft = std::bind(&QuHeight::getFt, this);
    FieldRef::GetterFunction get_in = std::bind(&QuHeight::getIn, this);
    FieldRef::SetterFunction set_m = std::bind(&QuHeight::setM, this, std::placeholders::_1);
    FieldRef::SetterFunction set_ft = std::bind(&QuHeight::setFt, this, std::placeholders::_1);
    FieldRef::SetterFunction set_in = std::bind(&QuHeight::setIn, this, std::placeholders::_1);
    m_fr_m = FieldRefPtr(new FieldRef(get_m, set_m, true));
    m_fr_ft = FieldRefPtr(new FieldRef(get_ft, set_ft, true));
    m_fr_in = FieldRefPtr(new FieldRef(get_in, set_in, true));
}


QVariant QuHeight::getM() const
{
    return getFieldrefValue();
}


QVariant QuHeight::getFt() const
{
    return m_ft;
}


QVariant QuHeight::getIn() const
{
    return m_in;
}


bool QuHeight::setM(const QVariant& value)
{
#ifdef DEBUG_DATA_FLOW
    qDebug() << Q_FUNC_INFO << value;
#endif
    const bool changed = setFieldrefValue(value);
    if (changed) {
        updateImperial();
    }
    return changed;
}


bool QuHeight::setFt(const QVariant& value)
{
#ifdef DEBUG_DATA_FLOW
    qDebug() << Q_FUNC_INFO << value;
#endif
    const bool changed = value != m_ft;
    if (changed) {
        m_ft = value;
        updateMetric();
    }
    return changed;
}


bool QuHeight::setIn(const QVariant& value)
{
#ifdef DEBUG_DATA_FLOW
    qDebug() << Q_FUNC_INFO << value;
#endif
    Q_ASSERT(m_fr_m);
    const bool changed = value != m_in;
    if (changed) {
        m_in = value;
        updateMetric();
    }
    return changed;
}


void QuHeight::updateMetric()
{
    // Called when imperial units have been changed.
#ifdef DEBUG_DATA_FLOW
    qDebug() << Q_FUNC_INFO;
#endif
    Q_ASSERT(m_fr_m);
    if (m_ft.isNull() && m_in.isNull()) {
        setFieldrefValue(QVariant());
    } else {
        const int feet = m_ft.toInt();
        const double inches = m_in.toDouble();
        setFieldrefValue(convert::metresFromFeetInches(feet, inches));
    }
    m_fr_m->emitValueChanged();
    emit elementValueChanged();
}


void QuHeight::updateImperial()
{
#ifdef DEBUG_DATA_FLOW
    qDebug() << Q_FUNC_INFO;
#endif
    Q_ASSERT(m_fr_ft);
    Q_ASSERT(m_fr_in);
    QVariant height_m_var = getFieldrefValue();
    if (height_m_var.isNull()) {
        m_ft.clear();
        m_in.clear();
    } else {
        const double height_m = height_m_var.toDouble();
        int feet;
        double inches;
        convert::feetInchesFromMetres(height_m, feet, inches);
        m_ft = feet;
        m_in = inches;
    }
    m_fr_ft->emitValueChanged();
    m_fr_in->emitValueChanged();
    emit elementValueChanged();
}