diff options
-rw-r--r-- | CMakeLists.txt | 48 | ||||
-rw-r--r-- | connectionprivate.cpp | 64 | ||||
-rw-r--r-- | connectionprivate.h | 11 | ||||
-rw-r--r-- | jobs/basejob.cpp | 67 | ||||
-rw-r--r-- | jobs/basejob.h | 102 |
5 files changed, 143 insertions, 149 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 3745f3c2..fa5abe56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,25 +10,6 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) # Instruct CMake to run moc automatically when needed. set(CMAKE_AUTOMOC ON) -# Whether to build with the bundled KCoreAddons or system KCoreAddons -set( BUNDLE_KCOREADDONS "AUTO" CACHE STRING "Build own KCoreAddons, one of ON, OFF and AUTO" ) -set( KCOREADDONS_DIR "kcoreaddons" CACHE STRING "Local path to bundled KCoreAddons sources, if own KCoreAddons is built" ) - -find_package(Qt5Core 5.2.0) # For JSON (de)serialization -find_package(Qt5Network 5.2.0) # For networking -find_package(Qt5Gui 5.2.0) # For userpics - -if ( (NOT BUNDLE_KCOREADDONS STREQUAL "ON") - AND (NOT BUNDLE_KCOREADDONS STREQUAL "OFF") - AND (NOT BUNDLE_KCOREADDONS STREQUAL "AUTO") ) - message( FATAL_ERROR "BUNDLE_KCOREADDONS must be one of ON, OFF or AUTO" ) -endif () - -if ( BUNDLE_KCOREADDONS STREQUAL "AUTO" ) - find_package(KF5CoreAddons QUIET) -elseif ( BUNDLE_KCOREADDONS STREQUAL "OFF" ) - find_package(KF5CoreAddons REQUIRED) -endif () message( STATUS ) message( STATUS "================================================================================" ) @@ -37,14 +18,6 @@ message( STATUS "=============================================================== message( STATUS "Building with: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}" ) message( STATUS "Install Prefix: ${CMAKE_INSTALL_PREFIX}" ) message( STATUS "Path to Qt Core: ${Qt5Core_DIR}" ) -message( STATUS "Build own KCoreAddons (BUNDLE_KCOREADDONS): ${BUNDLE_KCOREADDONS}" ) -if ( NOT BUNDLE_KCOREADDONS STREQUAL "ON" ) - if ( KF5CoreAddons_FOUND ) - message( STATUS "'- Path to system KCoreAddons: ${KF5CoreAddons_DIR}" ) - else ( KF5CoreAddons_FOUND ) - message( STATUS "'- System KCoreAddons not found, using the bundled version at ${PROJECT_SOURCE_DIR}/${KCOREADDONS_DIR}" ) - endif ( KF5CoreAddons_FOUND ) -endif ( NOT BUNDLE_KCOREADDONS STREQUAL "ON" ) message( STATUS "================================================================================" ) message( STATUS ) @@ -80,16 +53,6 @@ set(libqmatrixclient_SRCS jobs/mediathumbnailjob.cpp jobs/logoutjob.cpp ) -# Add bundled KCoreAddons sources if we haven't found the system sources -# or if we ignore them -if ( NOT KF5CoreAddons_FOUND ) - set (libqmatrixclient_SRCS ${libqmatrixclient_SRCS} - ${KCOREADDONS_DIR}/src/lib/jobs/kjob.cpp - ${KCOREADDONS_DIR}/src/lib/jobs/kcompositejob.cpp - ${KCOREADDONS_DIR}/src/lib/jobs/kjobtrackerinterface.cpp - ${KCOREADDONS_DIR}/src/lib/jobs/kjobuidelegate.cpp - ) -endif ( NOT KF5CoreAddons_FOUND ) add_library(qmatrixclient ${libqmatrixclient_SRCS}) @@ -109,14 +72,3 @@ else ( CMAKE_VERSION VERSION_LESS "3.1" ) endif ( CMAKE_VERSION VERSION_LESS "3.1" ) target_link_libraries(qmatrixclient Qt5::Core Qt5::Network Qt5::Gui) -if ( KF5CoreAddons_FOUND ) - # The proper way of doing things would be to make a separate config.h.in - # file and use configure_file() command here to generate config.h with - # needed C++ preprocessor macros. If we have more than one or two - # dependencies like that, we should turn to that more scalable way. - # As for now, passing a macro through -D is easier to observe and maintain. - target_compile_definitions ( qmatrixclient PRIVATE USING_SYSTEM_KCOREADDONS ) - target_link_libraries(qmatrixclient KF5::CoreAddons) -else ( KF5CoreAddons_FOUND ) - include_directories( ${KCOREADDONS_DIR}/src/lib/jobs ) -endif ( KF5CoreAddons_FOUND ) diff --git a/connectionprivate.cpp b/connectionprivate.cpp index 62840473..4d49c014 100644 --- a/connectionprivate.cpp +++ b/connectionprivate.cpp @@ -116,69 +116,7 @@ Room* ConnectionPrivate::provideRoom(QString id) return room; } -//void ConnectionPrivate::connectDone(KJob* job) -//{ -// PasswordLogin* realJob = static_cast<PasswordLogin*>(job); -// if( !realJob->error() ) -// { -// isConnected = true; -// userId = realJob->id(); -// qDebug() << "Our user ID: " << userId; -// emit q->connected(); -// } -// else { -// emit q->loginError( job->errorString() ); -// } -//} - -//void ConnectionPrivate::reconnectDone(KJob* job) -//{ -// PasswordLogin* realJob = static_cast<PasswordLogin*>(job); -// if( !realJob->error() ) -// { -// userId = realJob->id(); -// emit q->reconnected(); -// } -// else { -// emit q->loginError( job->errorString() ); -// isConnected = false; -// } -//} - -//void ConnectionPrivate::syncDone(KJob* job) -//{ -// SyncJob* syncJob = static_cast<SyncJob*>(job); -// if( !syncJob->error() ) -// { -// data->setLastEvent(syncJob->nextBatch()); -// processRooms(syncJob->roomData()); -// emit q->syncDone(); -// } -// else { -// if( syncJob->error() == BaseJob::NetworkError ) -// emit q->connectionError( syncJob->errorString() ); -// else -// qDebug() << "syncJob failed, error:" << syncJob->error(); -// } -//} - -//void ConnectionPrivate::gotJoinRoom(KJob* job) -//{ -// qDebug() << "gotJoinRoom"; -// JoinRoomJob* joinJob = static_cast<JoinRoomJob*>(job); -// if( !joinJob->error() ) -// { -// if ( Room* r = provideRoom(joinJob->roomId()) ) -// emit q->joinedRoom(r); -// } -// else -// { -// if( joinJob->error() == BaseJob::NetworkError ) -// emit q->connectionError( joinJob->errorString() ); -// } -//} - -void ConnectionPrivate::gotRoomMembers(KJob* job) +void ConnectionPrivate::gotRoomMembers(BaseJob* job) { RoomMembersJob* membersJob = static_cast<RoomMembersJob*>(job); if( !membersJob->error() ) diff --git a/connectionprivate.h b/connectionprivate.h index 8e37a934..d1199081 100644 --- a/connectionprivate.h +++ b/connectionprivate.h @@ -19,15 +19,12 @@ #ifndef QMATRIXCLIENT_CONNECTIONPRIVATE_H #define QMATRIXCLIENT_CONNECTIONPRIVATE_H -class KJob; - #include <QtCore/QObject> #include <QtCore/QHash> #include <QtCore/QJsonObject> #include "connection.h" #include "connectiondata.h" -#include "jobs/syncjob.h" namespace QMatrixClient { @@ -35,6 +32,8 @@ namespace QMatrixClient class Event; class State; class User; + class BaseJob; + class SyncRoomData; class ConnectionPrivate : public QObject { @@ -60,11 +59,7 @@ namespace QMatrixClient QString userId; public slots: -// void connectDone(KJob* job); -// void reconnectDone(KJob* job); -// void syncDone(KJob* job); -// void gotJoinRoom(KJob* job); - void gotRoomMembers(KJob* job); + void gotRoomMembers(BaseJob* job); }; } diff --git a/jobs/basejob.cpp b/jobs/basejob.cpp index 6c68ab66..2c95ef11 100644 --- a/jobs/basejob.cpp +++ b/jobs/basejob.cpp @@ -31,24 +31,21 @@ class BaseJob::Private { public: Private(ConnectionData* c, JobHttpType t, bool nt) - : connection(c), reply(nullptr), type(t), needsToken(nt) {} + : connection(c), reply(nullptr), type(t), needsToken(nt), errorCode(NoError) + {} ConnectionData* connection; QNetworkReply* reply; JobHttpType type; bool needsToken; + + int errorCode; + QString errorText; }; BaseJob::BaseJob(ConnectionData* connection, JobHttpType type, QString name, bool needsToken) : d(new Private(connection, type, needsToken)) { - // Work around KJob inability to separate success and failure signals - connect(this, &BaseJob::result, [this]() { - if (error() == NoError) - emit success(this); - else - emit failure(this); - }); setObjectName(name); qDebug() << "Job" << objectName() << " created"; } @@ -119,6 +116,55 @@ void BaseJob::start() // this, &BaseJob::networkError ); // http://doc.qt.io/qt-5/qnetworkreply.html#error-1 } +void BaseJob::finishJob(bool emitResult) +{ + if( d->reply->isRunning() ) + d->reply->abort(); + + // Notify those that are interested in any completion of the job (including killing) + emit finished(this); + + if (emitResult) { + emit result(this); + if (error()) + emit failure(this); + else + emit success(this); + } + + deleteLater(); +} + +int BaseJob::error() const +{ + return d->errorCode; +} + +QString BaseJob::errorString() const +{ + return d->errorText; +} + +void BaseJob::setError(int errorCode) +{ + d->errorCode = errorCode; +} + +void BaseJob::setErrorText(QString errorText) +{ + d->errorText = errorText; +} + +void BaseJob::emitResult() +{ + finishJob(true); +} + +void BaseJob::abandon() +{ + finishJob(false); +} + void BaseJob::fail(int errorCode, QString errorString) { setError( errorCode ); @@ -134,11 +180,6 @@ QNetworkReply* BaseJob::networkReply() const return d->reply; } -// void BaseJob::networkError(QNetworkReply::NetworkError code) -// { -// fail( KJob::UserDefinedError+1, d->reply->errorString() ); -// } - void BaseJob::gotReply() { switch( d->reply->error() ) diff --git a/jobs/basejob.h b/jobs/basejob.h index 150d39e8..9d00c0ac 100644 --- a/jobs/basejob.h +++ b/jobs/basejob.h @@ -19,12 +19,6 @@ #ifndef QMATRIXCLIENT_BASEJOB_H #define QMATRIXCLIENT_BASEJOB_H -#ifdef USING_SYSTEM_KCOREADDONS -#include <KCoreAddons/KJob> -#else -#include "kjob.h" -#endif // KCOREADDONS_FOUND - #include <QtCore/QJsonDocument> #include <QtCore/QJsonObject> #include <QtCore/QUrlQuery> @@ -36,28 +30,75 @@ namespace QMatrixClient enum class JobHttpType { GetJob, PutJob, PostJob }; - class BaseJob: public KJob + class BaseJob: public QObject { Q_OBJECT public: + /* Just in case, the values are compatible with KJob + * (which BaseJob used to inherit from). */ + enum ErrorCode { NoError = 0, NetworkError = 100, + JsonParseError, TimeoutError, ContentAccessError, + UserDefinedError = 512 }; + BaseJob(ConnectionData* connection, JobHttpType type, QString name, bool needsToken=true); virtual ~BaseJob(); - void start() override; + void start(); - enum ErrorCode { NetworkError = KJob::UserDefinedError, - JsonParseError, TimeoutError, ContentAccessError, - UserDefinedError = 512 }; + /** + * Abandons the result of this job, arrived or unarrived. + * + * This aborts waiting for a reply from the server (if there was + * any pending) and deletes the job object. It is always done quietly + * (as opposed to KJob::kill() that can trigger emitting the result). + */ + void abandon(); + + int error() const; + virtual QString errorString() const; signals: /** - * Emitted together with KJob::result() but only if there's no error. + * Emitted when the job is finished, in any case. It is used to notify + * observers that the job is terminated and that progress can be hidden. + * + * This should not be emitted directly by subclasses; + * use emitResult() instead. + * + * In general, to be notified of a job's completion, client code + * should connect to success() and failure() + * rather than finished(), so that kill() is indeed quiet. + * However if you store a list of jobs and they might get killed + * silently, then you must connect to this instead of result(), + * to avoid dangling pointers in your list. + * + * @param job the job that emitted this signal + * @internal + * + * @see success, failure + */ + void finished(BaseJob* job); + + /** + * Emitted when the job is finished (except when killed). + * + * Use error to know if the job was finished with error. + * + * @param job the job that emitted this signal + * + * @see success, failure + */ + void result(BaseJob* job); + + /** + * Emitted together with result() but only if there's no error. */ void success(BaseJob*); + /** - * Emitted together with KJob::result() if there's an error. - * Same as result(), this won't be emitted in case of kill(Quietly). + * Emitted together with result() if there's an error. + * Same as result(), this won't be emitted in case of kill(). */ void failure(BaseJob*); @@ -70,6 +111,34 @@ namespace QMatrixClient virtual QJsonObject data() const; virtual void parseJson(const QJsonDocument& data); + /** + * Sets the error code. + * + * It should be called when an error is encountered in the job, + * just before calling emitResult(). Normally you might want to + * use fail() instead - it sets error code, error text, makes sure + * the job has finished and invokes emitResult after that. + * + * To extend the list of error codes, define an (anonymous) enum + * with additional values starting at BaseJob::UserDefinedError + * + * @param errorCode the error code + * @see emitResult(), fail() + */ + void setError(int errorCode); + void setErrorText(QString errorText); + + /** + * Utility function to emit the result signal, and suicide this job. + * It first notifies the observers to hide the progress for this job using + * the finished() signal. + * + * @note: Deletes this job using deleteLater(). + * + * @see result() + * @see finished() + */ + void emitResult(); void fail( int errorCode, QString errorString ); QNetworkReply* networkReply() const; @@ -79,10 +148,9 @@ namespace QMatrixClient void timeout(); void sslErrors(const QList<QSslError>& errors); - //void networkError(QNetworkReply::NetworkError code); - - private: + void finishJob(bool emitResult); + class Private; Private* d; }; |