annotate data/fileio/FileSource.h @ 392:183ee2a55fc7

* More work to abstract out interactive components used in the data library, so that it does not need to depend on QtGui.
author Chris Cannam
date Fri, 14 Mar 2008 17:14:21 +0000
parents b92513201610
children 93fb1ebff76b
rev   line source
Chris@208 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@208 2
Chris@208 3 /*
Chris@208 4 Sonic Visualiser
Chris@208 5 An audio file viewer and annotation editor.
Chris@208 6 Centre for Digital Music, Queen Mary, University of London.
Chris@208 7 This file copyright 2007 QMUL.
Chris@208 8
Chris@208 9 This program is free software; you can redistribute it and/or
Chris@208 10 modify it under the terms of the GNU General Public License as
Chris@208 11 published by the Free Software Foundation; either version 2 of the
Chris@208 12 License, or (at your option) any later version. See the file
Chris@208 13 COPYING included with this distribution for more information.
Chris@208 14 */
Chris@208 15
Chris@208 16 #ifndef _REMOTE_FILE_H_
Chris@208 17 #define _REMOTE_FILE_H_
Chris@208 18
Chris@208 19 #include <QUrl>
Chris@208 20 #include <QMutex>
Chris@208 21 #include <QString>
Chris@210 22 #include <QTimer>
Chris@208 23
Chris@304 24 #include <map>
Chris@304 25
Chris@208 26 class QFtp;
Chris@208 27 class QHttp;
Chris@208 28 class QFile;
Chris@210 29 class QHttpResponseHeader;
Chris@392 30 class ProgressReporter;
Chris@208 31
Chris@325 32 /**
Chris@325 33 * FileSource is a class used to refer to the contents of a file that
Chris@325 34 * may be either local or at a remote location such as a HTTP URL.
Chris@325 35 *
Chris@325 36 * When a FileSource object is constructed, the file or URL passed to
Chris@325 37 * its constructor is tested for validity, and if it refers to a
Chris@325 38 * remote HTTP or FTP location it is retrieved asynchronously (the Qt
Chris@325 39 * event loop must be running) and cached locally. You can then query
Chris@325 40 * a local path for the file and refer to that as a normal filename.
Chris@325 41 *
Chris@325 42 * Use isAvailable() to test whether the file or remote URL exists,
Chris@325 43 * and isOK() to test for internal validity or transmission errors.
Chris@325 44 * Call waitForStatus() to block until the availability and validity
Chris@325 45 * of the URL have been established so that isAvailable may be called,
Chris@325 46 * and waitForData() to block until the entire file has been cached.
Chris@325 47 *
Chris@325 48 * FileSource handles reference counting for cache files. You can
Chris@325 49 * construct many FileSource objects with the same URL and you will
Chris@325 50 * receive the same cached file for each; it is also reasonable to
Chris@325 51 * pass FileSource objects by value. FileSource only makes sense for
Chris@325 52 * stateless URLs that result in the same data on each request.
Chris@325 53 *
Chris@325 54 * Cached files share a lifetime with their "owning" FileSource
Chris@325 55 * objects; when the last FileSource referring to a given URL is
Chris@325 56 * deleted or goes out of scope, its cached file (if any) is also
Chris@325 57 * removed.
Chris@325 58 */
Chris@317 59 class FileSource : public QObject
Chris@208 60 {
Chris@208 61 Q_OBJECT
Chris@208 62
Chris@208 63 public:
Chris@325 64 /**
Chris@325 65 * Construct a FileSource using the given local file path or URL.
Chris@357 66 * The URL may be raw or encoded.
Chris@357 67 *
Chris@392 68 * If a ProgressReporter is provided, it will be updated with
Chris@392 69 * progress status. Note that the progress() signal will also be
Chris@392 70 * emitted regularly during retrieval, even if no reporter is
Chris@392 71 * supplied here. Caller retains ownership of the reporter object.
Chris@325 72 */
Chris@392 73 FileSource(QString fileOrUrl, ProgressReporter *reporter = 0);
Chris@325 74
Chris@325 75 /**
Chris@357 76 * Construct a FileSource using the given remote URL.
Chris@357 77 *
Chris@392 78 * If a ProgressReporter is provided, it will be updated with
Chris@392 79 * progress status. Note that the progress() signal will also be
Chris@392 80 * emitted regularly during retrieval, even if no reporter is
Chris@392 81 * supplied here. Caller retains ownership of the reporter object.
Chris@325 82 */
Chris@392 83 FileSource(QUrl url, ProgressReporter *reporter = 0);
Chris@325 84
Chris@317 85 FileSource(const FileSource &);
Chris@316 86
Chris@317 87 virtual ~FileSource();
Chris@208 88
Chris@325 89 /**
Chris@325 90 * Block on a sub-event-loop until the availability of the file or
Chris@325 91 * remote URL is known.
Chris@325 92 */
Chris@325 93 void waitForStatus();
Chris@325 94
Chris@325 95 /**
Chris@325 96 * Block on a sub-event-loop until the whole of the data has been
Chris@325 97 * retrieved (if it is remote).
Chris@325 98 */
Chris@325 99 void waitForData();
Chris@325 100
Chris@325 101 /**
Chris@325 102 * Return true if the FileSource object is valid and no error
Chris@325 103 * occurred in looking up the file or remote URL. Non-existence
Chris@325 104 * of the file or URL is not an error -- call isAvailable() to
Chris@325 105 * test for that.
Chris@325 106 */
Chris@325 107 bool isOK() const;
Chris@325 108
Chris@325 109 /**
Chris@325 110 * Return true if the file or remote URL exists. This may block
Chris@325 111 * on a sub-event-loop (calling waitForStatus) if the status is
Chris@325 112 * not yet available.
Chris@325 113 */
Chris@210 114 bool isAvailable();
Chris@210 115
Chris@325 116 /**
Chris@325 117 * Return true if the entire file has been retrieved and is
Chris@325 118 * available.
Chris@325 119 */
Chris@325 120 bool isDone() const;
Chris@316 121
Chris@325 122 /**
Chris@325 123 * Return true if this FileSource is referring to a remote URL.
Chris@325 124 */
Chris@325 125 bool isRemote() const;
Chris@325 126
Chris@325 127 /**
Chris@325 128 * Return the location filename or URL as passed to the
Chris@325 129 * constructor.
Chris@325 130 */
Chris@325 131 QString getLocation() const;
Chris@325 132
Chris@325 133 /**
Chris@325 134 * Return the name of the local file this FileSource refers to.
Chris@325 135 * This is the filename that should be used when reading normally
Chris@325 136 * from the FileSource. If the filename passed to the constructor
Chris@325 137 * was a local file, this will return the same filename; otherwise
Chris@325 138 * this will be the name of the temporary cache file owned by the
Chris@325 139 * FileSource.
Chris@325 140 */
Chris@325 141 QString getLocalFilename() const;
Chris@325 142
Chris@325 143 /**
Chris@325 144 * Return the MIME content type of this file, if known.
Chris@325 145 */
Chris@325 146 QString getContentType() const;
Chris@325 147
Chris@325 148 /**
Chris@325 149 * Return the file extension for this file, if any.
Chris@325 150 */
Chris@325 151 QString getExtension() const;
Chris@325 152
Chris@325 153 /**
Chris@325 154 * Return an error message, if isOK() is false.
Chris@325 155 */
Chris@325 156 QString getErrorString() const;
Chris@325 157
Chris@325 158 /**
Chris@325 159 * Specify whether any local, cached file should remain on disc
Chris@325 160 * after this FileSource has been destroyed. The default is false
Chris@325 161 * (cached files share their FileSource owners' lifespans).
Chris@325 162 */
Chris@316 163 void setLeaveLocalFile(bool leave);
Chris@208 164
Chris@325 165 /**
Chris@325 166 * Return true if the given filename or URL refers to a remote
Chris@325 167 * URL.
Chris@325 168 */
Chris@325 169 static bool isRemote(QString fileOrUrl);
Chris@210 170
Chris@325 171 /**
Chris@325 172 * Return true if FileSource can handle the retrieval scheme for
Chris@325 173 * the given URL (or if the URL is for a local file).
Chris@325 174 */
Chris@208 175 static bool canHandleScheme(QUrl url);
Chris@208 176
Chris@208 177 signals:
Chris@325 178 /**
Chris@325 179 * Emitted during URL retrieval, when the retrieval progress
Chris@325 180 * notches up to a new percentage.
Chris@325 181 */
Chris@208 182 void progress(int percent);
Chris@325 183
Chris@325 184 /**
Chris@325 185 * Emitted when the file's existence has been tested and/or
Chris@325 186 * response header received. Calls to isAvailable() after this
Chris@325 187 * has been emitted will not block.
Chris@325 188 */
Chris@325 189 void statusAvailable();
Chris@325 190
Chris@325 191 /**
Chris@325 192 * Emitted when the entire file data has been retrieved and the
Chris@325 193 * local file is complete (if no error has occurred).
Chris@325 194 */
Chris@208 195 void ready();
Chris@208 196
Chris@208 197 protected slots:
Chris@208 198 void dataReadProgress(int done, int total);
Chris@214 199 void httpResponseHeaderReceived(const QHttpResponseHeader &resp);
Chris@214 200 void ftpCommandFinished(int, bool);
Chris@208 201 void dataTransferProgress(qint64 done, qint64 total);
Chris@208 202 void done(bool error);
Chris@210 203 void cancelled();
Chris@208 204
Chris@208 205 protected:
Chris@317 206 FileSource &operator=(const FileSource &); // not provided
Chris@316 207
Chris@304 208 QUrl m_url;
Chris@208 209 QFtp *m_ftp;
Chris@208 210 QHttp *m_http;
Chris@208 211 QFile *m_localFile;
Chris@208 212 QString m_localFilename;
Chris@208 213 QString m_errorString;
Chris@315 214 QString m_contentType;
Chris@208 215 bool m_ok;
Chris@210 216 int m_lastStatus;
Chris@316 217 bool m_remote;
Chris@208 218 bool m_done;
Chris@316 219 bool m_leaveLocalFile;
Chris@392 220 ProgressReporter *m_reporter;
Chris@208 221
Chris@304 222 typedef std::map<QUrl, int> RemoteRefCountMap;
Chris@304 223 typedef std::map<QUrl, QString> RemoteLocalMap;
Chris@304 224 static RemoteRefCountMap m_refCountMap;
Chris@304 225 static RemoteLocalMap m_remoteLocalMap;
Chris@304 226 static QMutex m_mapMutex;
Chris@316 227 bool m_refCounted;
Chris@316 228
Chris@357 229 void init();
Chris@316 230 void initHttp();
Chris@316 231 void initFtp();
Chris@304 232
Chris@211 233 void cleanup();
Chris@211 234
Chris@316 235 // Create a local file for m_url. If it already existed, return true.
Chris@316 236 // The local filename is stored in m_localFilename.
Chris@316 237 bool createCacheFile();
Chris@316 238 void deleteCacheFile();
Chris@208 239
Chris@208 240 static QMutex m_fileCreationMutex;
Chris@208 241 static int m_count;
Chris@208 242 };
Chris@208 243
Chris@208 244 #endif