/* This file is part of the KDE project Copyright (C) 2008 Lukas Appelhans Copyright (C) 2009 Matthias Fuchs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. */ #ifndef DATASOURCEFACTORY_H #define DATASOURCEFACTORY_H #include "kget_export.h" #include "transferdatasource.h" #include "job.h" #include #include class BitSet; class KioDownload; class TransferDataSource; class QTimer; class Signature; class Verifier; namespace KIO { class FileJob; } /** This class manages multiple DataSources and saves the received data to the file */ class KGET_EXPORT DataSourceFactory : public QObject { Q_OBJECT public: /** * In general use this constructor, if the size is 0, the datasourcefactory will try to * find the filesize * @note when you want to load a datasourcefactory you do not have to specify the url and segSize */ explicit DataSourceFactory(QObject *parent, const KUrl &dest = KUrl(), KIO::filesize_t size = 0, KIO::fileoffset_t segSize = 512000); ~DataSourceFactory(); /** * The capabilities the DataSourceFactory supports */ Transfer::Capabilities capabilities() const {return m_capabilities;} /** * Deletes the created (downloadInitialized() is true) file if the download was not finished * Does not delete anything if the download never got started * @see downloadInitialized() */ void deinit(); /** * @return true if the DataSourceFactory has enough information to start a download */ bool isValid() const; void start(); void stop(); KIO::filesize_t size() const {return m_size;} KIO::filesize_t downloadedSize() const {return m_downloadedSize;} ulong currentSpeed() const {return m_speed;} ulong percent() const {return m_percent;} KUrl dest() const {return m_dest;} /** * The maximum number of mirrors that will be used for downloading, default is 3 */ int maxMirrorsUsed() const {return m_maxMirrorsUsed;} /** * Change the maximum number off mirrors that will be used for downloading, * if the download started already some mirrors might be added or removed automatically */ void setMaxMirrorsUsed(int maxMirrorsUsed) {m_maxMirrorsUsed = maxMirrorsUsed;} /** * Add a mirror that can be used for downloading * @param url the url to the file * @param used defines whether the mirror should initially be used for downloading or not, * if true m_maxMirrorsUsed might be increased if needed * @param numParalellConnections the number of simultanous connections allowed to that mirror, * minimum is 1 * @note when you add an already existing mirror only the numParalellConnections are adapted * to the new value, so to change the number of paralell connections of a mirror you are already * using simply call addMirror again */ void addMirror(const KUrl &url, bool used, int numParalellConnections = 1); /** * Add a mirror that can be used for downloading, if it will be used depends if maxMirrorsUsed * has been reached yet * @param url the url to the file * @param numParalellConnections the number of simultanous connections allowed to that mirror, * minimum is 1 * @note when you add an already existing mirror only the numParalellConnections are adapted * to the new value, so to change the number of paralell connections of a mirror you are already * using simply call addMirror again */ void addMirror(const KUrl &url, int numParalellConnections = 1); /** * Does not use the specified mirror for downloading the file * @note if the mirror has bee unsed for downloading it will be moved to m_unusedMirrors, * otherwise nohting will happen * @param url the mirror that should not be used anymore */ void removeMirror(const KUrl &url); /** * Sets the mirrors that should be used/not used for downloading * @param mirrors url of the mirror, if it should be used and its number of paralell connections * (minimum is 1) * @note if you want the download to work at least one entry should be set to true */ void setMirrors(const QHash > &mirrors); /** * Return all mirrors, where bool defines if the mirror is used, * while in defines the number of paralell connections for that mirror */ QHash > mirrors() const; /** * Returns whether the datasourcefactory should download the file or not, * true by default * @note can be used for multiple datasourcefactory downloads */ bool doDownload() const {return m_doDownload;} /** * Set if the datasourcefactory should download the file or not, * if set to false the download will be stopped if needed * @note can be used for multiple datasourcefactory downloads */ void setDoDownload(bool doDownload); bool setNewDestination(const KUrl &newDest); Job::Status status() const {return m_status;} /** * @return true if the download was already initialized, i.e. a file has been * created and maybe even written to * @see deinit() */ bool downloadInitialized() const {return m_downloadInitialized;} /** * Tries to repair a broken download, via completely redownloading it * or only the borken parts * @note call this if verification returned NotVerified */ void repair(); Verifier *verifier(); Signature *signature(); Q_SIGNALS: void capabilitiesChanged(); void dataSourceFactoryChange(Transfer::ChangesFlags change); void log(const QString &message, Transfer::LogLevel logLevel); public slots: void save(const QDomElement &element); void load(const QDomElement *e); private slots: void slotUpdateCapabilities(); void slotRemovedFile(); /** * Tries to find the size of the file, automatically called * by start if no file size has been specified */ void findFileSize(); void slotFoundFileSize(TransferDataSource *source, KIO::filesize_t fileSize, const QPair &segmentRange); void assignSegments(TransferDataSource *source); /** * Called when segments are broken */ void brokenSegments(TransferDataSource *source, const QPair &segmentRange); void finishedSegment(TransferDataSource *source, int segmentNumber, bool connectionFinished = true); /** * A TransferDataSource is broken */ void broken(TransferDataSource *source, TransferDataSource::Error error); /** * Emitted when a Datasource itself decides to not download a specific segmentRange, * e.g. when there are too many connections for this TransferDataSource */ void slotFreeSegments(TransferDataSource *source, QPair segmentRange); void slotWriteData(KIO::fileoffset_t offset, const QByteArray &data, bool &worked); void slotOffset(KIO::Job *job, KIO::filesize_t offset); void slotDataWritten(KIO::Job *job, KIO::filesize_t offset); void slotPercent(KJob *job, ulong percent); void open(KIO::Job *job); void speedChanged(); /** * Kills the putjob and starts the moving of files */ void startMove(); void slotPutJobDestroyed(QObject *job); void newDestResult(KJob *job); void slotRepair(const QList &offsets, KIO::filesize_t length); void slotFinishedDownload(TransferDataSource *source, KIO::filesize_t size); void slotUrlChanged(const KUrl &, const KUrl &); private: /** * Add a mirror that can be used for downloading * @param used always true if usedDefined is false * @param usedDefined true if the user defined used, otherwise false, * needed to know if m_maxMirrorsUsed should be changed or not */ void addMirror(const KUrl &url, bool used, int numParalellConnections, bool usedDefined); /** * Checks if an assign is needed, i.e. there are no (running) TransferDataSources, * yet some segements are still not finished */ bool assignNeeded() const; bool checkLocalFile(); void init(); void killPutJob(); void changeStatus(Job::Status status); private: Transfer::Capabilities m_capabilities; KUrl m_dest; KUrl m_newDest; KIO::filesize_t m_size; KIO::filesize_t m_downloadedSize; QList m_prevDownloadedSizes; KIO::fileoffset_t m_segSize; ulong m_speed; ulong m_percent; /** * the cache of data that could not be written yet */ QHash m_cache; KIO::filesize_t m_tempOffset; QByteArray m_tempData; BitSet *m_startedChunks; BitSet *m_finishedChunks; KIO::FileJob* m_putJob; bool m_doDownload; bool m_open; /** * the write access is currently blocked, the data gets cached in m_cache */ bool m_blocked; /** * If start() was called but did not work this is true, once the conditions changed * start() could be recalled */ bool m_startTried; bool m_findFilesizeTried; bool m_assignTried; bool m_movingFile; bool m_finished; /** * True if download gets started the first time, if it gets never started there * is no reason to remove any -- maybe preexisting -- file */ bool m_downloadInitialized; /** * Wether the file-size has been initially defined (it is to be trusted) or not */ bool m_sizeInitiallyDefined; /** * Downloadsize has only been found out once the download was finished */ bool m_sizeFoundOnFinish; int m_maxMirrorsUsed; QHash m_sources; QList m_unusedUrls; QList m_unusedConnections; QTimer *m_speedTimer; Job::Status m_status; Job::Status m_statusBeforeMove; Verifier *m_verifier; Signature *m_signature; }; #endif