File indexing completed on 2024-04-28 15:17:53

0001 /*
0002  * BluezQt - Asynchronous BlueZ wrapper library
0003  *
0004  * SPDX-FileCopyrightText: 2014 Alejandro Fiestas Olivares <afiestas@kde.org>
0005  * SPDX-FileCopyrightText: 2014-2015 David Rosca <nowrep@gmail.com>
0006  *
0007  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0008  */
0009 
0010 #ifndef BLUEZQT_JOB_H
0011 #define BLUEZQT_JOB_H
0012 
0013 #include <QObject>
0014 
0015 #include "bluezqt_export.h"
0016 
0017 namespace BluezQt
0018 {
0019 class JobPrivate;
0020 
0021 /**
0022  * @class BluezQt::Job job.h <BluezQt/Job>
0023  *
0024  * This class represents an asynchronous job performed by BluezQt,
0025  * it is usually not used directly but instead it is inherit by some
0026  * other class.
0027  *
0028  * There are two ways of using this class, one is via exec() which will block
0029  * the thread until a result is fetched, the other is via connecting to the
0030  * signal result()
0031  *
0032  * Please, think twice before using exec(), it should be used only in either
0033  * unittest or cli apps.
0034  *
0035  * @note Job and its subclasses are meant to be used in a fire-and-forget way.
0036  * Jobs will delete themselves when they finish using deleteLater().
0037  *
0038  * @note Even given their asynchronous nature, Jobs are still executed in the
0039  * main thread, so any blocking code executed in it will block the app calling it.
0040  *
0041  * @see InitManagerJob
0042  * @see InitObexManagerJob
0043  */
0044 class BLUEZQT_EXPORT Job : public QObject
0045 {
0046     Q_OBJECT
0047     Q_PROPERTY(int error READ error)
0048     Q_PROPERTY(QString errorText READ errorText)
0049     Q_PROPERTY(bool running READ isRunning)
0050     Q_PROPERTY(bool finished READ isFinished)
0051 
0052 public:
0053     /**
0054      * Creates a new Job object.
0055      *
0056      * @param parent
0057      */
0058     explicit Job(QObject *parent = nullptr);
0059 
0060     /**
0061      * Destroys a Job object.
0062      */
0063     ~Job() override;
0064 
0065     /**
0066      * Error type
0067      *
0068      * @see error() const
0069      */
0070     enum Error {
0071         /** Indicates there is no error */
0072         NoError = 0,
0073         /** Subclasses should define error codes starting at this value */
0074         UserDefinedError = 100
0075     };
0076     Q_ENUM(Error)
0077 
0078     /**
0079      * Executes the job synchronously.
0080      *
0081      * This will start a nested QEventLoop internally. Nested event loop can be dangerous and
0082      * can have unintended side effects, you should avoid calling exec() whenever you can and use the
0083      * asynchronous interface of Job instead.
0084      *
0085      * Should you indeed call this method, you need to make sure that all callers are reentrant,
0086      * so that events delivered by the inner event loop don't cause non-reentrant functions to be
0087      * called, which usually wreaks havoc.
0088      *
0089      * Note that the event loop started by this method does not process user input events, which means
0090      * your user interface will effectively be blocked. Other events like paint or network events are
0091      * still being processed. The advantage of not processing user input events is that the chance of
0092      * accidental reentrancy is greatly reduced. Still you should avoid calling this function.
0093      *
0094      * @warning This method blocks until the job finishes!
0095      *
0096      * @return true if the job has been executed without error, false otherwise
0097      */
0098     bool exec();
0099 
0100     /**
0101      * Returns the error code, if there has been an error.
0102      *
0103      * Make sure to call this once result() has been emitted
0104      *
0105      * @return the error code for this job, 0 if no error.
0106      */
0107     int error() const;
0108 
0109     /**
0110      * Returns the error text if there has been an error.
0111      *
0112      * Only call if error is not 0.
0113      *
0114      * This is usually some extra data associated with the error,
0115      * such as a URL.  Use errorString() to get a human-readable,
0116      * translated message.
0117      *
0118      * @return a string to help understand the error
0119      */
0120     QString errorText() const;
0121 
0122     /**
0123      * Returns whether the job is currently running
0124      *
0125      * @return true if the job is running
0126      */
0127     bool isRunning() const;
0128 
0129     /**
0130      * Returns whether the job have already finished
0131      *
0132      * @return true if the job already finished
0133      */
0134     bool isFinished() const;
0135 
0136 public Q_SLOTS:
0137     /**
0138      * Starts the job asynchronously.
0139      *
0140      * This method will schedule doStart() to be executed in the next
0141      * loop. This is done so this method returns as soon as possible.
0142      *
0143      * When the job is finished, result() is emitted.
0144      */
0145     void start();
0146 
0147     /**
0148      * Kills the job.
0149      *
0150      * This method will kill the job and then call deleteLater().
0151      * Only jobs started with start() can be killed.
0152      *
0153      * It will not emit result signal.
0154      */
0155     void kill();
0156 
0157 protected Q_SLOTS:
0158     /**
0159      * Implementation for start() that will be executed in next loop
0160      *
0161      * This slot is always called in the next loop, triggered by start().
0162      *
0163      * When implementing this method is important to remember that jobs
0164      * are not executed on a different thread (unless done that way), so any
0165      * blocking task has to be done in a different thread or process.
0166      */
0167     virtual void doStart() = 0;
0168 
0169 protected:
0170     /**
0171      * Sets the error code.
0172      *
0173      * It should be called when an error
0174      * is encountered in the job, just before calling emitResult().
0175      *
0176      * You should define an enum of error codes,
0177      * with values starting at Job::UserDefinedError, and use
0178      * those. For example:
0179      * @code
0180      * enum ExampleErrors{
0181      *   InvalidFoo = UserDefinedError,
0182      *   BarNotFound
0183      * };
0184      * @endcode
0185      *
0186      * @param errorCode the error code
0187      * @see emitResult()
0188      */
0189     void setError(int errorCode);
0190 
0191     /**
0192      * Sets the error text.
0193      *
0194      * It should be called when an error
0195      * is encountered in the job, just before calling emitResult().
0196      *
0197      * Provides extra information about the error that cannot be
0198      * determined directly from the error code.  For example, a
0199      * URL or filename.  This string is not normally translatable.
0200      *
0201      * @param errorText the error text
0202      * @see emitResult(), setError()
0203      */
0204     void setErrorText(const QString &errorText);
0205 
0206     /**
0207      * Utility function to emit the result signal, and suicide this job.
0208      *
0209      * @note Deletes this job using deleteLater().
0210      * @see result() const
0211      */
0212     void emitResult();
0213 
0214     /**
0215      * Implementation for emitting the result signal
0216      *
0217      * This function is needed to be able to emit result() signal
0218      * with the job pointer's type being subclass
0219      */
0220     virtual void doEmitResult() = 0;
0221 
0222 private:
0223     JobPrivate *const d_ptr;
0224 
0225     Q_DECLARE_PRIVATE(Job)
0226 };
0227 
0228 } // namespace BluezQt
0229 
0230 #endif // BLUEZQT_JOB_H