File indexing completed on 2024-11-10 04:40:30

0001 /*
0002     SPDX-FileCopyrightText: 2006 Tobias Koenig <tokoe@kde.org>
0003                   2006 Marc Mutz <mutz@kde.org>
0004                   2006 - 2007 Volker Krause <vkrause@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #pragma once
0010 
0011 #include "akonadicore_export.h"
0012 
0013 #include <KCompositeJob>
0014 
0015 #include <memory>
0016 
0017 class QString;
0018 
0019 namespace Akonadi
0020 {
0021 namespace Protocol
0022 {
0023 class Command;
0024 using CommandPtr = QSharedPointer<Command>;
0025 }
0026 
0027 class JobPrivate;
0028 class Session;
0029 class SessionPrivate;
0030 
0031 /**
0032  * @short Base class for all actions in the Akonadi storage.
0033  *
0034  * This class encapsulates a request to the pim storage service,
0035  * the code looks like
0036  *
0037  * @code
0038  *
0039  *  Akonadi::Job *job = new Akonadi::SomeJob( some parameter );
0040  *  connect( job, SIGNAL(result(KJob*)),
0041  *           this, SLOT(slotResult(KJob*)) );
0042  *
0043  * @endcode
0044  *
0045  * The job is queued for execution as soon as the event loop is entered
0046  * again.
0047  *
0048  * And the slotResult is usually at least:
0049  *
0050  * @code
0051  *
0052  *  if ( job->error() ) {
0053  *    // handle error...
0054  *  }
0055  *
0056  * @endcode
0057  *
0058  * With the synchronous interface the code looks like
0059  *
0060  * @code
0061  *   Akonadi::SomeJob *job = new Akonadi::SomeJob( some parameter );
0062  *   if ( !job->exec() ) {
0063  *     qDebug() << "Error:" << job->errorString();
0064  *   } else {
0065  *     // do something
0066  *   }
0067  * @endcode
0068  *
0069  * @warning Using the synchronous method is error prone, use this only
0070  *          if the asynchronous access is not possible. See the documentation of
0071  *          KJob::exec() for more details.
0072  *
0073  * Subclasses must reimplement doStart().
0074  *
0075  * @note KJob-derived objects delete itself, it is thus not possible
0076  * to create job objects on the stack!
0077  *
0078  * @author Volker Krause <vkrause@kde.org>, Tobias Koenig <tokoe@kde.org>, Marc Mutz <mutz@kde.org>
0079  */
0080 class AKONADICORE_EXPORT Job : public KCompositeJob
0081 {
0082     Q_OBJECT
0083 
0084     friend class Session;
0085     friend class SessionPrivate;
0086 
0087 public:
0088     /**
0089      * Describes a list of jobs.
0090      */
0091     using List = QList<Job *>;
0092 
0093     /**
0094      * Describes the error codes that can be emitted by this class.
0095      * Subclasses can provide additional codes, starting from UserError
0096      * onwards
0097      */
0098     enum Error {
0099         ConnectionFailed = UserDefinedError, ///< The connection to the Akonadi server failed.
0100         ProtocolVersionMismatch, ///< The server protocol version is too old or too new.
0101         UserCanceled, ///< The user canceled this job.
0102         Unknown, ///< Unknown error.
0103         UserError = UserDefinedError + 42 ///< Starting point for error codes defined by sub-classes.
0104     };
0105 
0106     /**
0107      * Creates a new job.
0108      *
0109      * If the parent object is a Job object, the new job will be a subjob of @p parent.
0110      * If the parent object is a Session object, it will be used for server communication
0111      * instead of the default session.
0112      *
0113      * @param parent The parent object, job or session.
0114      */
0115     explicit Job(QObject *parent = nullptr);
0116 
0117     /**
0118      * Destroys the job.
0119      */
0120     ~Job() override;
0121 
0122     /**
0123      * Jobs are started automatically once entering the event loop again, no need
0124      * to explicitly call this.
0125      */
0126     void start() override;
0127 
0128     /**
0129      * Returns the error string, if there has been an error, an empty
0130      * string otherwise.
0131      */
0132     [[nodiscard]] QString errorString() const final;
0133 
0134 Q_SIGNALS:
0135     /**
0136      * This signal is emitted directly before the job will be started.
0137      *
0138      * @param job The started job.
0139      */
0140     void aboutToStart(Akonadi::Job *job);
0141 
0142     /**
0143      * This signal is emitted if the job has finished all write operations, ie.
0144      * if this signal is emitted, the job guarantees to not call writeData() again.
0145      * Do not emit this signal directly, call emitWriteFinished() instead.
0146      *
0147      * @param job This job.
0148      * @see emitWriteFinished()
0149      */
0150     void writeFinished(Akonadi::Job *job);
0151 
0152 protected:
0153     /**
0154      * This method must be reimplemented in the concrete jobs. It will be called
0155      * after the job has been started and a connection to the Akonadi backend has
0156      * been established.
0157      */
0158     virtual void doStart() = 0;
0159 
0160     /**
0161      * This method should be reimplemented in the concrete jobs in case you want
0162      * to handle incoming data. It will be called on received data from the backend.
0163      * The default implementation does nothing.
0164      *
0165      * @param tag The tag of the corresponding command, empty if this is an untagged response.
0166      * @param response The received response
0167      *
0168      * @return Implementations should return true if the last response was processed and
0169      * the job can emit result. Return false if more responses from server are expected.
0170      */
0171     virtual bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response);
0172 
0173     /**
0174      * Adds the given job as a subjob to this job. This method is automatically called
0175      * if you construct a job using another job as parent object.
0176      * The base implementation does the necessary setup to share the network connection
0177      * with the backend.
0178      *
0179      * @param job The new subjob.
0180      */
0181     bool addSubjob(KJob *job) override;
0182 
0183     /**
0184      * Removes the given subjob of this job.
0185      *
0186      * @param job The subjob to remove.
0187      */
0188     bool removeSubjob(KJob *job) override;
0189 
0190     /**
0191      * Kills the execution of the job.
0192      */
0193     bool doKill() override;
0194 
0195     /**
0196      * Call this method to indicate that this job will not call writeData() again.
0197      * @see writeFinished()
0198      */
0199     void emitWriteFinished();
0200 
0201 protected Q_SLOTS:
0202     void slotResult(KJob *job) override;
0203 
0204 protected:
0205     /// @cond PRIVATE
0206     Job(JobPrivate *dd, QObject *parent);
0207     std::unique_ptr<JobPrivate> const d_ptr;
0208     /// @endcond
0209 
0210 private:
0211     Q_DECLARE_PRIVATE(Job)
0212 
0213     /// @cond PRIVATE
0214     Q_PRIVATE_SLOT(d_func(), void startNext())
0215     Q_PRIVATE_SLOT(d_func(), void signalCreationToJobTracker())
0216     Q_PRIVATE_SLOT(d_func(), void signalStartedToJobTracker())
0217     Q_PRIVATE_SLOT(d_func(), void delayedEmitResult())
0218     /// @endcond
0219 };
0220 
0221 }