15.1.507. tablet_qt/questionnairelib/qupickerinline.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 "qupickerinline.h"
#include <QComboBox>
#include <QLabel>
#include "common/cssconst.h"
#include "lib/widgetfunc.h"
#include "questionnairelib/questionnaire.h"
#include "questionnairelib/questionnairefunc.h"


const int MAX_LENGTH = 100;


QuPickerInline::QuPickerInline(FieldRefPtr fieldref,
                               const NameValueOptions& options,
                               QObject* parent) :
    QuElement(parent),
    m_fieldref(fieldref),
    m_options(options),
    m_randomize(false),
    m_cbox(nullptr)
{
    m_options.validateOrDie();
    Q_ASSERT(m_fieldref);
    connect(m_fieldref.data(), &FieldRef::valueChanged,
            this, &QuPickerInline::fieldValueChanged);
    connect(m_fieldref.data(), &FieldRef::mandatoryChanged,
            this, &QuPickerInline::fieldValueChanged);
}


QuPickerInline* QuPickerInline::setRandomize(const bool randomize)
{
    m_randomize = randomize;
    return this;
}


QPointer<QWidget> QuPickerInline::makeWidget(Questionnaire* questionnaire)
{
    // Randomize?
    if (m_randomize) {
        m_options.shuffle();
    }

    const bool read_only = questionnaire->readOnly();
    m_cbox = new QComboBox();
    m_cbox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
    for (int position = 0; position < m_options.size(); ++position) {
        const NameValuePair& nvp = m_options.atPosition(position);
        m_cbox->insertItem(position, nvp.name().left(MAX_LENGTH));
        // No real point in passing the third QVariant parameter.
    }
    // QComboBox has two signals named currentIndexChanged, differing only
    // in the parameter they pass (int versus QString&). You get
    // "no matching function for call to ... unresolved overloaded function
    // type..."
    // Disambiguate like this:
    void (QComboBox::*ic_signal)(int) = &QComboBox::currentIndexChanged;
    if (!read_only) {
        // The currentIndex on the QCombobox is what we are calling the position
        // of the item in the list of options (the index being the original,
        // unrandomized position).
        connect(m_cbox.data(), ic_signal,
                this, &QuPickerInline::currentItemChanged);
    }
    m_cbox->setEnabled(!read_only);
    m_cbox->setObjectName(cssconst::PICKER_INLINE);
    setFromField();
    return QPointer<QWidget>(m_cbox);
}


void QuPickerInline::currentItemChanged(const int position)
{
    // qDebug().nospace() << "QuPickerInline::currentItemChanged(" << position << ")";
    if (!m_options.validIndex(position)) {
        return;
    }
    const QVariant newvalue = m_options.atPosition(position).value();
    const bool changed = m_fieldref->setValue(newvalue);  // Will trigger valueChanged
    if (changed) {
        emit elementValueChanged();
    }
}


void QuPickerInline::setFromField()
{
    fieldValueChanged(m_fieldref.data());
}


void QuPickerInline::fieldValueChanged(const FieldRef* fieldref)
{
    const int index = m_options.indexFromValue(fieldref->value());
    const bool missing = fieldref->missingInput();
    if (m_cbox) {
        {
            const QSignalBlocker blocker(m_cbox);
            // qDebug() << "QuPickerInline::valueChanged(): index =" << index;
            m_cbox->setCurrentIndex(index);  // it's happy with -1
        }
        widgetfunc::setPropertyMissing(m_cbox, missing);
    }
}


FieldRefPtrList QuPickerInline::fieldrefs() const
{
    return FieldRefPtrList{m_fieldref};
}