/*
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/>.
*/
#pragma once
#include "db/databaseobject.h"
#include <QDate>
#include <QJsonObject>
#include <QMap>
#include <QPointer>
class CamcopsApp;
class IdPolicy;
class OpenableWidget;
class Questionnaire;
extern const QString FORENAME_FIELD;
extern const QString SURNAME_FIELD;
extern const QString DOB_FIELD;
extern const QString SEX_FIELD;
extern const QString ADDRESS_FIELD;
extern const QString GP_FIELD;
extern const QString EMAIL_FIELD;
extern const QString OTHER_DETAILS_POLICYNAME; // policy name, not field name
extern const QString IDNUM_FIELD_PREFIX;
extern const QString IDNUM_FIELD_FORMAT;
extern const QString ANY_IDNUM_POLICYNAME;
extern const QString OTHER_IDNUM_POLICYNAME;
// Represents a patient.
class Patient : public DatabaseObject
{
Q_OBJECT
using AttributesType = QMap<QString, bool>;
public:
// ------------------------------------------------------------------------
// Creation
// ------------------------------------------------------------------------
// Normal constructor.
Patient(CamcopsApp& app,
DatabaseManager& db,
int load_pk = dbconst::NONEXISTENT_PK);
// Construct from JSON (except ID numbers -- because they are in a separate
// table that needs to refer to this patient, so the patient needs to be
// saved first).
Patient(CamcopsApp& app,
DatabaseManager& db,
const QJsonObject& json_obj);
// Sets details (except for ID numbers)
void setPatientDetailsFromJson(const QJsonObject& json_obj);
// Adds ID numbers from JSON.
void addIdNums(const QJsonObject& json_obj);
// Sets ID numbers from JSON -- that is, remove any existing ID numbers and
// add these new ones.
void setIdNums(const QJsonObject& json_obj);
// ------------------------------------------------------------------------
// Ancillary management
// ------------------------------------------------------------------------
virtual void loadAllAncillary(int pk) override;
virtual QVector<DatabaseObjectPtr> getAncillarySpecimens() const override;
virtual QVector<DatabaseObjectPtr> getAllAncillary() const override;
// ------------------------------------------------------------------------
// Information about patients
// ------------------------------------------------------------------------
// Returns the patient's database PK.
int id() const;
// Returns the forename.
QString forename() const;
// Returns the surname.
QString surname() const;
// Returns the sex; see CommonOptions::SEX_*.
QString sex() const;
// Is the patient female?
bool isFemale() const;
// Is the patient male?
bool isMale() const;
// Returns the date of birth, as a QDate.
QDate dob() const;
// Returns the date of birth as text, e.g. "31 Dec 2000".
QString dobText() const;
// Returns the conventional age in years (i.e. rounded down).
int ageYears() const;
// Do we know the forename?
bool hasForename() const;
// Do we know the surname?
bool hasSurname() const;
// Do we know the sex?
bool hasSex() const;
// Do we know the DOB?
bool hasDob() const;
// Do we know the e-mail address?
bool hasEmail() const;
// Do we know the address?
bool hasAddress() const;
// Do we know the GP?
bool hasGP() const;
// Is there information in the "other" field?
bool hasOtherDetails() const;
// Do we have an ID number of the specified type?
bool hasIdnum(int which_idnum) const;
// Which ID number types are present and have an ID number?
QVector<int> whichIdnumsPresent() const;
// Which ID number types have entries present?
// (They do not necessarily have data.)
QVector<int> whichIdnumsHaveEntries() const;
// Returns an ID number of the specified ID type as a QVariant.
QVariant idnumVariant(int which_idnum) const;
// Returns an ID number of the specified ID type as a qint64 (qlonglong).
// = 64-bit signed integer: up to 2^63 - 1 = 9,223,372,036,854,775,807
qint64 idnumInteger(int which_idnum) const;
// Returns the attributes possessed by the patient (e.g. "sex and
// forename and id number type 3"), to provide information for checking
// against an ID policy mentioning the specified ID number types.
AttributesType policyAttributes(
const QVector<int>& policy_mentioned_idnums) const;
// Returns a JSON representation of the patient.
QJsonObject jsonDescription() const;
// Does the patient comply with the specified ID policy?
bool compliesWith(const IdPolicy& policy) const;
// Does the patient comply with the tablet software's standard minimum
// ID policy?
bool compliesWithTablet() const;
// Does the patient comply with the server's upload policy?
bool compliesWithUpload() const;
// Does the patient comply with the server's finalize (preserve) policy?
bool compliesWithFinalize() const;
// Returns a short ID number summary, like "RiO 12345, NHS 9876543210".
QString shortIdnumSummary() const;
// Do other patients in our database clash on the specified ID number type?
bool othersClashOnIdnum(int which_idnum) const;
// Do other patients in our database clash on any ID number types?
bool anyIdClash() const;
// How many tasks are in the database for this patient?
int numTasks() const;
// Delete the patient (and associated tasks) from the database.
virtual void deleteFromDatabase() override;
// Does this patient match another, allowing them to be merged?
bool matchesForMerge(const Patient* other) const;
// Helper functions for various viewers:
// e.g. "<b>JONES, Bob</b><br>M, 19y, DOB 1 Jan 2000<br>RiO 12345, NHS 9876543210"
QString descriptionForMerge() const;
// e.g. "Bob Jones"
QString forenameSurname() const;
// e.g. "JONES, Bob"
QString surnameUpperForename() const;
// e.g. "M, 19y, DOB 1 Jan 2000"
QString sexAgeDob() const;
// e.g. "19y, M, DOB 1 Jan 2000"
QString ageSexDob() const;
// e.g. "JONES, Bob (M, 19y, DOB 1 Jan 2000)\nRiO 12345, NHS 9876543210"
QString twoLineDetailString() const;
// e.g. "<b>JONES, Bob</b> (M, 19y, DOB 1 Jan 2000); RiO 12345, NHS 9876543210"
QString oneLineHtmlDetailString() const;
// e.g. "<b>Bob Jones</b>"
QString oneLineHtmlSimpleString() const;
// ------------------------------------------------------------------------
// Editing and other manipulations
// ------------------------------------------------------------------------
// Returns an editor to edit this patient.
OpenableWidget* editor(bool read_only);
// Merge with another patient. Move tasks from "other" to "this".
void mergeInDetailsAndTakeTasksFrom(const Patient* other);
public:
static const QString TABLENAME;
protected:
// Build the editor page.
void buildPage(bool read_only);
// Ask the user for input and add an ID number entry.
void addIdNum();
// Delete an ID number of the specified type.
// Asks for confirmation.
void deleteIdNum(int which_idnum);
// Remove all ID numbers.
// Does not ask for confirmation; used internally.
void deleteAllIdNums();
// Sort ID numbers by their type, and if we are editing the patient,
// refresh the questionnaire to reflect the current ID numbers.
void sortIdNums();
// Updates the "missing" alerts etc.
void updateQuestionnaireIndicators(const FieldRef* fieldref = nullptr,
const QObject* originator = nullptr);
protected:
// ID number objects
QVector<PatientIdNumPtr> m_idnums;
// Records our editing questionnaire's page.
QuPagePtr m_page;
// Records our editing questionnaire.
QPointer<Questionnaire> m_questionnaire;
};