File indexing completed on 2024-11-24 04:44:12

0001 /*
0002  * SPDX-FileCopyrightText: 2012 Christian Mollekopf <mollekopf@kolabsys.com>
0003  *
0004  * SPDX-License-Identifier: LGPL-3.0-or-later
0005  */
0006 
0007 #pragma once
0008 
0009 #include "kolab_export.h"
0010 
0011 #include <QDebug>
0012 #include <QIODevice>
0013 #include <QList>
0014 #include <QString>
0015 
0016 namespace Kolab
0017 {
0018 class DebugStream;
0019 /**
0020  * Kolab Error Handler
0021  *
0022  * Errors are reported during an operation, but the operation might still succeed.
0023  * The error handler therefore contains all errors which occurred during a single operation,
0024  * and must be cleared at the start of a new operation.
0025  *
0026  * A user of the kolabobject classes should check ErrorHandler::error() after every operation.
0027  *
0028  * all non-const functions are not for the user of this class and only exist for internal usage.
0029  *
0030  * TODO: Hide everything which is not meant for the user from the interface.
0031  * FIXME: Use Threadlocal storage to make this threadsafe.
0032  */
0033 class KOLAB_EXPORT ErrorHandler
0034 {
0035 public:
0036     enum Severity {
0037         Debug,
0038         Warning, // Warning, error could be corrected, object can be used without dataloss. This warning is also used if dataloss is acceptable because a
0039                  // feature is explicitly not supported.
0040         Error, // Potentially corrupt object, writing the object back could result in dataloss. (Object could still be used to display the data readonly).
0041         Critical // Critical error, produced object cannot be used and should be thrown away (writing back will result in dataloss).
0042     };
0043 
0044     struct Err {
0045         Err(Severity s, const QString &m, const QString &l)
0046             : severity(s)
0047             , message(m)
0048             , location(l)
0049         {
0050         }
0051 
0052         Severity severity;
0053         QString message;
0054         QString location;
0055     };
0056 
0057     static ErrorHandler &instance()
0058     {
0059         static ErrorHandler inst;
0060         return inst;
0061     }
0062 
0063     void addError(Severity s, const QString &message, const QString &location);
0064     const QList<Err> &getErrors() const;
0065     Severity error() const;
0066     QString errorMessage() const;
0067     void clear();
0068 
0069     /**
0070      * Check for errors during the libkolabxml reading/writing process and copy them into this error handler.
0071      */
0072     static void handleLibkolabxmlErrors();
0073 
0074     static void clearErrors()
0075     {
0076         ErrorHandler::instance().clear();
0077     }
0078 
0079     static bool errorOccured()
0080     {
0081         if (ErrorHandler::instance().error() >= Error) {
0082             return true;
0083         }
0084         return false;
0085     }
0086 
0087     /**
0088      * Returns a debug stream to which logs errors
0089      */
0090     static QDebug debugStream(Severity, int line, const char *file);
0091 
0092 private:
0093     ErrorHandler();
0094     ErrorHandler(const ErrorHandler &) = delete;
0095     ErrorHandler &operator=(const ErrorHandler &) = delete;
0096 
0097     Severity m_worstError;
0098     QString m_worstErrorMessage;
0099     QList<Err> m_errorQueue;
0100     QScopedPointer<DebugStream> m_debugStream;
0101 };
0102 
0103 void logMessage(const QString &, const QString &, int, ErrorHandler::Severity s);
0104 
0105 #define LOG(message) logMessage(message, __FILE__, __LINE__, ErrorHandler::Debug);
0106 #define WARNING(message) logMessage(message, __FILE__, __LINE__, ErrorHandler::Warning);
0107 #define ERROR(message) logMessage(message, __FILE__, __LINE__, ErrorHandler::Error);
0108 #define CRITICAL(message) logMessage(message, QStringLiteral(__FILE__), __LINE__, ErrorHandler::Critical);
0109 
0110 class DebugStream : public QIODevice
0111 {
0112     Q_OBJECT
0113 public:
0114     QString m_location;
0115     ErrorHandler::Severity m_severity;
0116     DebugStream();
0117     ~DebugStream() override;
0118     bool isSequential() const override
0119     {
0120         return true;
0121     }
0122 
0123     qint64 readData(char *, qint64) override
0124     {
0125         return 0; /* eof */
0126     }
0127 
0128     qint64 readLineData(char *, qint64) override
0129     {
0130         return 0; /* eof */
0131     }
0132 
0133     qint64 writeData(const char *data, qint64 len) override;
0134 
0135 private:
0136     Q_DISABLE_COPY(DebugStream)
0137 };
0138 
0139 #define Debug() Kolab::ErrorHandler::debugStream(Kolab::ErrorHandler::Debug, __LINE__, __FILE__)
0140 #define Warning() Kolab::ErrorHandler::debugStream(Kolab::ErrorHandler::Warning, __LINE__, __FILE__)
0141 #define Error() Kolab::ErrorHandler::debugStream(Kolab::ErrorHandler::Error, __LINE__, __FILE__)
0142 #define Critical() Kolab::ErrorHandler::debugStream(Kolab::ErrorHandler::Critical, __LINE__, __FILE__)
0143 }
0144 
0145 QDebug operator<<(QDebug dbg, const std::string &s);