/*
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 "namevalueoptions.h"
#include <QDebug>
#include "lib/convert.h"
#include "lib/errorfunc.h"
#include "maths/ccrandom.h"
NameValueOptions::NameValueOptions()
{
}
NameValueOptions::NameValueOptions(std::initializer_list<NameValuePair> options
) :
m_options(options)
{
for (int i = 0; i < m_options.size(); ++i) {
m_indexes.append(i);
}
}
void NameValueOptions::append(const NameValuePair& nvp)
{
m_indexes.append(m_options.size());
m_options.append(nvp);
}
void NameValueOptions::replace(
const NameValuePair& nvp, bool append_if_not_found
)
{
const int n = m_options.size();
const QVariant v = nvp.value();
for (int i = 0; i < n; ++i) {
if (atIndex(i).value() == v) {
m_options[i] = nvp;
return;
}
}
if (append_if_not_found) {
append(nvp);
}
}
int NameValueOptions::size() const
{
return m_options.size();
}
const NameValuePair& NameValueOptions::atIndex(const int index) const
{
return m_options.at(index);
}
const NameValuePair& NameValueOptions::atPosition(const int position) const
{
return atIndex(m_indexes.at(position));
}
int NameValueOptions::indexFromName(const QString& name) const
{
const int n = m_options.size();
for (int i = 0; i < n; ++i) {
if (atIndex(i).name() == name) {
return i;
}
}
return -1;
}
int NameValueOptions::indexFromValue(const QVariant& value) const
{
if (value.isNull()) {
return -1;
}
const int n = m_options.size();
for (int i = 0; i < n; ++i) {
if (atIndex(i).value() == value) {
// The behaviour of QVariant == has changed from Qt6.0
// https://www.qt.io/blog/whats-new-in-qmetatype-qvariant
// Apart from a few exceptions, if the types do not match,
// the values will not be considered equal.
return i;
}
}
return -1;
}
int NameValueOptions::indexFromPosition(const int position) const
{
return m_indexes.at(position);
}
int NameValueOptions::positionFromValue(const QVariant& value) const
{
if (value.isNull()) {
return -1;
}
const int n = m_indexes.size();
for (int position = 0; position < n; ++position) {
if (atPosition(position).value() == value) {
return position;
}
}
return -1;
}
void NameValueOptions::validateOrDie()
{
QVector<QVariant> values;
for (const NameValuePair& nvp : m_options) {
const QVariant& v = nvp.value();
if (values.contains(v)) {
QString error = QString(
"NameValueOptions::validateOrDie: "
"Duplicate value %1 found for name %2"
)
.arg(convert::prettyValue(v), nvp.name());
errorfunc::fatalError(error);
}
values.append(v);
}
}
bool NameValueOptions::validIndex(const int index) const
{
return index >= 0 && index < m_options.size();
}
void NameValueOptions::shuffle()
{
ccrandom::shuffle(m_indexes);
}
void NameValueOptions::reverse()
{
std::reverse(m_indexes.begin(), m_indexes.end());
}
QString NameValueOptions::nameFromIndex(const int index) const
{
if (!validIndex(index)) {
return "";
}
return atIndex(index).name();
}
QVariant NameValueOptions::valueFromIndex(const int index) const
{
if (!validIndex(index)) {
return QVariant();
}
return atIndex(index).value();
}
QString NameValueOptions::nameFromPosition(const int position) const
{
if (!validIndex(position)) {
return "";
}
return atPosition(position).name();
}
QVariant NameValueOptions::valueFromPosition(const int position) const
{
if (!validIndex(position)) {
return QVariant();
}
return atPosition(position).value();
}
NameValueOptions NameValueOptions::makeNumbers(
const int first, const int last, const int step
)
{
NameValueOptions nvo;
if (first < last && step > 0) {
for (int i = first; i <= last; i += step) {
nvo.append(NameValuePair{QString::number(i), i});
}
} else if (last < first && step < 0) {
for (int i = first; i >= last; i += step) {
nvo.append(NameValuePair{QString::number(i), i});
}
} else {
errorfunc::fatalError("Bad arguments to NameValueOptions");
}
return nvo;
}
QString NameValueOptions::nameFromValue(
const QVariant& value, const QString& default_
) const
{
const int idx = indexFromValue(value);
if (idx == -1) {
return default_;
}
return nameFromIndex(idx);
}
QVariant NameValueOptions::valueFromName(
const QString& name, const QVariant& default_
) const
{
const int idx = indexFromName(name);
if (idx == -1) {
return default_;
}
return valueFromIndex(idx);
}
bool NameValueOptions::valuesMatch(const NameValueOptions& other) const
{
const int s = size();
if (s != other.size()) {
return false;
}
for (int i = 0; i < s; ++i) {
const QVariant& self_value = m_options[i].value();
const QVariant& other_value = other.m_options[i].value();
if (self_value != other_value) {
return false;
}
}
return true;
}
// ========================================================================
// For friends
// ========================================================================
QDebug operator<<(QDebug debug, const NameValueOptions& nvo)
{
QDebug& d = debug.nospace();
d << "NameValueOptions{";
bool first = true;
for (const NameValuePair& nvp : nvo.m_options) {
if (!first) {
d << ", ";
} else {
first = false;
}
d << nvp.name() << ": " << nvp.value() << "}";
}
d << "}";
return debug;
}