Files
pilotclient/src/blackmisc/statusmessage.h

328 lines
13 KiB
C++

/* Copyright (C) 2013
* Swift Project Community / Contributors
*
* This file is part of Swift Project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
//! \file
#ifndef BLACKMISC_STATUSMESSAGE_H
#define BLACKMISC_STATUSMESSAGE_H
#include "blackmiscexport.h"
#include "icon.h"
#include "propertyindex.h"
#include "logcategorylist.h"
#include "timestampbased.h"
#include "typetraits.h"
#include <QReadWriteLock>
namespace BlackMisc
{
class CStatusException;
namespace Private
{
//! Like QString::arg() but accepts a QStringList of args.
BLACKMISC_EXPORT QString arg(const QString &format, const QStringList &args);
}
/*!
* Status severities
*/
enum StatusSeverity
{
SeverityDebug,
SeverityInfo,
SeverityWarning,
SeverityError
};
/*!
* Base class for CStatusMessage and CLogMessage.
*/
template <class Derived>
class CMessageBase
{
public:
//! Default constructor.
CMessageBase() {}
//! Construct a message with some specific category.
explicit CMessageBase(const CLogCategory &category) : m_categories({ category }) {}
//! Construct a message with some specific categories.
explicit CMessageBase(const CLogCategoryList &categories) : m_categories(categories) {}
//! Construct a message with some specific categories.
CMessageBase(const CLogCategoryList &categories, const CLogCategory &extra) : CMessageBase(categories) { m_categories.push_back(extra); }
//! Construct a message with some specific categories.
CMessageBase(const CLogCategoryList &categories, const CLogCategoryList &extra) : CMessageBase(categories) { m_categories.push_back(extra); }
//! Set the severity to debug.
Derived &debug() { return setSeverityAndMessage(SeverityDebug, ""); }
//! Set the severity to info, providing a format string.
Derived &info(QString format) { return setSeverityAndMessage(SeverityInfo, format); }
//! Set the severity to warning, providing a format string.
Derived &warning(QString format) { return setSeverityAndMessage(SeverityWarning, format); }
//! Set the severity to error, providing a format string.
Derived &error(QString format) { return setSeverityAndMessage(SeverityError, format); }
//! Set the severity to info, providing a format string, and adding the validation category.
Derived &validationInfo(QString format) { setValidation(); return setSeverityAndMessage(SeverityInfo, format); }
//! Set the severity to warning, providing a format string, and adding the validation category.
Derived &validationWarning(QString format) { setValidation(); return setSeverityAndMessage(SeverityWarning, format); }
//! Set the severity to error, providing a format string, and adding the validation category.
Derived &validationError(QString format) { setValidation(); return setSeverityAndMessage(SeverityError, format); }
//! Streaming operators.
//! \details If the format string is empty, the message will consist of all streamed values separated by spaces.
//! Otherwise, the streamed values will replace the place markers %1, %2, %3... in the format string.
//! \see QString::arg
//! @{
Derived &operator <<(const QString &v) { return arg(v); }
Derived &operator <<(int v) { return arg(QString::number(v)); }
Derived &operator <<(uint v) { return arg(QString::number(v)); }
Derived &operator <<(long v) { return arg(QString::number(v)); }
Derived &operator <<(ulong v) { return arg(QString::number(v)); }
Derived &operator <<(qlonglong v) { return arg(QString::number(v)); }
Derived &operator <<(qulonglong v) { return arg(QString::number(v)); }
Derived &operator <<(short v) { return arg(QString::number(v)); }
Derived &operator <<(ushort v) { return arg(QString::number(v)); }
Derived &operator <<(QChar v) { return arg(v); }
Derived &operator <<(char v) { return arg(QChar(v)); }
Derived &operator <<(double v) { return arg(QString::number(v)); }
template <class T, class = std::enable_if_t<HasToQString<T>::value>>
Derived &operator <<(const T &v) { return arg(v.toQString()); }
//! @}
private:
void setValidation() { m_categories.remove(CLogCategory::uncategorized()); m_categories.push_back(CLogCategory::validation()); }
Derived &setSeverityAndMessage(StatusSeverity s, const QString &m) { m_message = m; m_severity = s; return derived(); }
Derived &arg(QString value) { m_args.push_back(value); return derived(); }
Derived &derived() { return static_cast<Derived &>(*this); }
protected:
//! \private
//! @{
QString m_message;
QStringList m_args;
CLogCategoryList m_categories = CLogCategoryList { CLogCategory::uncategorized() };
StatusSeverity m_severity = SeverityDebug;
QString message() const { return Private::arg(m_message, m_args); }
//! @}
};
/*!
* Streamable status message, e.g. from Core -> GUI
*/
class BLACKMISC_EXPORT CStatusMessage :
public CValueObject<CStatusMessage>,
public CMessageBase<CStatusMessage>,
public ITimestampBased
{
public:
//! \copydoc BlackMisc::StatusSeverity
//! @{
using StatusSeverity = BlackMisc::StatusSeverity;
constexpr static auto SeverityDebug = BlackMisc::SeverityDebug;
constexpr static auto SeverityInfo = BlackMisc::SeverityInfo;
constexpr static auto SeverityWarning = BlackMisc::SeverityWarning;
constexpr static auto SeverityError = BlackMisc::SeverityError;
//! @}
//! Properties by index
enum ColumnIndex
{
IndexCategoriesAsString = BlackMisc::CPropertyIndex::GlobalIndexCStatusMessage,
IndexCategoriesHumanReadableAsString,
IndexCategoryHumanReadableOrTechnicalAsString,
IndexSeverity,
IndexSeverityAsString,
IndexMessage
};
//! Inheriting constructors.
using CMessageBase::CMessageBase;
//! Constructor
CStatusMessage();
//! Copy constructor (because of mutex)
CStatusMessage(const CStatusMessage &other);
//! Copy assignment (because of mutex)
CStatusMessage &operator =(const CStatusMessage &other);
//! Constructor
CStatusMessage(const QString &message);
//! Constructor
CStatusMessage(StatusSeverity severity, const QString &message);
//! Constructor, also a verification messsage can be directly created
CStatusMessage(const CLogCategoryList &categories, StatusSeverity severity, const QString &message, bool verification = false);
//! Construct from a Qt logging triple
//! \sa QtMessageHandler
CStatusMessage(QtMsgType type, const QMessageLogContext &context, const QString &message);
//! Convert to a Qt logging triple
//! \sa QtMessageHandler
void toQtLogTriple(QtMsgType *o_type, QString *o_category, QString *o_message) const;
//! Return a throwable exception object containing this status message.
CStatusException asException() const;
//! If message is empty then do nothing, otherwise throw a CStatusException.
void maybeThrow() const;
//! Message categories
const CLogCategoryList &getCategories() const { return this->m_categories; }
//! Message categories as string
QString getCategoriesAsString() const;
//! Human readable category
QString getHumanReadablePattern() const;
//! All human readable categories
QStringList getHumanReadablePatterns() const;
//! The human or technical categories
QString getHumanOrTechnicalCategoriesAsString() const;
//! Message severity
StatusSeverity getSeverity() const { return this->m_severity; }
//! Info or debug, no warning or error
bool isSeverityInfoOrLess() const { return this->m_severity == SeverityInfo || this->m_severity == SeverityDebug; }
//! Warning or above
bool isWarningOrAbove() const { return this->m_severity == SeverityWarning || this->m_severity == SeverityError; }
//! Operation considered successful
bool isSuccess() const;
//! Operation considered unsuccessful
bool isFailure() const;
//! Message
QString getMessage() const { return this->message(); }
//! Prepend message
void prependMessage(const QString &msg);
//! Append message
void appendMessage(const QString &msg);
//! Message empty
bool isEmpty() const { return this->m_message.isEmpty() && this->m_args.isEmpty(); }
//! Returns true if this message was sent by an instance of class T.
template <class T>
bool isFromClass(const T *pointer = nullptr) const
{
CLogCategoryList classCategories(pointer);
return std::all_of(classCategories.begin(), classCategories.end(), [this](const CLogCategory & cat) { return m_categories.contains(cat); });
}
//! Mark the message as having been handled by the given object
void markAsHandledBy(const QObject *object) const;
//! Returns true if the message was marked as having been handled by the given object
bool wasHandledBy(const QObject *object) const;
//! Severity
void setSeverity(StatusSeverity severity) { this->m_severity = severity; }
//! Add category
void addCategory(const CLogCategory &category) { this->m_categories.push_back(category); }
//! Adds verification as category
void addVerificationCategory();
//! Add categories
void addCategories(const CLogCategoryList &categories) { this->m_categories.push_back(categories); }
//! Reset category
void setCategory(const CLogCategory &category) { this->m_categories = CLogCategoryList { category }; }
//! Reset categories
void setCategories(const CLogCategoryList &categories) { this->m_categories = categories; }
//! Representing icon
CIcon toIcon() const { return convertToIcon(*this); }
//! Severity as string
const QString &getSeverityAsString() const;
//! Severity as string
static const QString &severityToString(StatusSeverity severity);
//! Severity set as string
static QString severitiesToString(const QSet<StatusSeverity> &severities);
//! Severity as string, if not possible to convert \sa CSeverityInfo
static StatusSeverity stringToSeverity(const QString &severity);
//! Severities as strings
static const QStringList &allSeverityStrings();
//! \copydoc BlackMisc::Mixin::Index::propertyByIndex
CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const;
//! \copydoc BlackMisc::Mixin::Index::setPropertyByIndex
void setPropertyByIndex(const CVariant &variant, const BlackMisc::CPropertyIndex &index);
//! Compare for index
int comparePropertyByIndex(const CStatusMessage &compareValue, const CPropertyIndex &index) const;
//! To HTML
QString toHtml() const;
//! \copydoc BlackMisc::Mixin::String::toQString
QString convertToQString(bool i18n = false) const;
//! Representing icon
static const CIcon &convertToIcon(const CStatusMessage &statusMessage);
//! Representing icon
static const CIcon &convertToIcon(CStatusMessage::StatusSeverity severity);
//! Object from JSON
static CStatusMessage fromDatabaseJson(const QJsonObject &json);
//! \copydoc BlackMisc::CValueObject::registerMetadata
static void registerMetadata();
private:
BLACK_ENABLE_TUPLE_CONVERSION(CStatusMessage)
mutable QVector<quintptr> m_handledByObjects;
mutable QReadWriteLock m_lock; //!< lock (because of mutable members)
};
} // namespace
BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::CStatusMessage, (
o.m_categories,
o.m_severity,
o.m_message,
o.m_args,
o.m_timestampMSecsSinceEpoch
))
Q_DECLARE_METATYPE(BlackMisc::CStatusMessage)
Q_DECLARE_METATYPE(BlackMisc::CStatusMessage::StatusSeverity)
#endif // guard