annotate data/fileio/FileSource.h @ 706:579b2da21e7a

Make FileSource capable of handling resource files. Without this, we failed to open the silent resource file used as a placeholder in templates and thus failed to replace it with the proper file after loading the template -- the consequence was that (although the right audio file ended up being shown as the main model) any derived models were not regenerated
author Chris Cannam
date Fri, 07 Oct 2011 17:04:09 +0100
parents b4a8d8221eaf
children 3b2409646cc0
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@465 16 #ifndef _FILE_SOURCE_H_
Chris@465 17 #define _FILE_SOURCE_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@686 26 #include "base/Debug.h"
Chris@686 27
Chris@208 28 class QFtp;
Chris@208 29 class QHttp;
Chris@208 30 class QFile;
Chris@210 31 class QHttpResponseHeader;
Chris@392 32 class ProgressReporter;
Chris@208 33
Chris@325 34 /**
Chris@325 35 * FileSource is a class used to refer to the contents of a file that
Chris@325 36 * may be either local or at a remote location such as a HTTP URL.
Chris@325 37 *
Chris@325 38 * When a FileSource object is constructed, the file or URL passed to
Chris@325 39 * its constructor is tested for validity, and if it refers to a
Chris@325 40 * remote HTTP or FTP location it is retrieved asynchronously (the Qt
Chris@325 41 * event loop must be running) and cached locally. You can then query
Chris@325 42 * a local path for the file and refer to that as a normal filename.
Chris@325 43 *
Chris@325 44 * Use isAvailable() to test whether the file or remote URL exists,
Chris@325 45 * and isOK() to test for internal validity or transmission errors.
Chris@325 46 * Call waitForStatus() to block until the availability and validity
Chris@325 47 * of the URL have been established so that isAvailable may be called,
Chris@325 48 * and waitForData() to block until the entire file has been cached.
Chris@325 49 *
Chris@325 50 * FileSource handles reference counting for cache files. You can
Chris@325 51 * construct many FileSource objects with the same URL and you will
Chris@325 52 * receive the same cached file for each; it is also reasonable to
Chris@325 53 * pass FileSource objects by value. FileSource only makes sense for
Chris@325 54 * stateless URLs that result in the same data on each request.
Chris@325 55 *
Chris@469 56 * Cached files share a lifetime with their "owning" FileSource
Chris@469 57 * objects; when the last FileSource referring to a given URL is
Chris@469 58 * deleted or goes out of scope, its cached file (if any) is also
Chris@469 59 * removed.
Chris@325 60 */
Chris@317 61 class FileSource : public QObject
Chris@208 62 {
Chris@208 63 Q_OBJECT
Chris@208 64
Chris@208 65 public:
Chris@325 66 /**
Chris@325 67 * Construct a FileSource using the given local file path or URL.
Chris@357 68 * The URL may be raw or encoded.
Chris@357 69 *
Chris@392 70 * If a ProgressReporter is provided, it will be updated with
Chris@392 71 * progress status. Note that the progress() signal will also be
Chris@392 72 * emitted regularly during retrieval, even if no reporter is
Chris@392 73 * supplied here. Caller retains ownership of the reporter object.
Chris@325 74 */
Chris@520 75 FileSource(QString fileOrUrl,
Chris@520 76 ProgressReporter *reporter = 0,
Chris@520 77 QString preferredContentType = "");
Chris@325 78
Chris@325 79 /**
Chris@357 80 * Construct a FileSource using the given remote URL.
Chris@357 81 *
Chris@392 82 * If a ProgressReporter is provided, it will be updated with
Chris@392 83 * progress status. Note that the progress() signal will also be
Chris@392 84 * emitted regularly during retrieval, even if no reporter is
Chris@392 85 * supplied here. Caller retains ownership of the reporter object.
Chris@325 86 */
Chris@469 87 FileSource(QUrl url, ProgressReporter *reporter = 0);
Chris@325 88
Chris@317 89 FileSource(const FileSource &);
Chris@316 90
Chris@317 91 virtual ~FileSource();
Chris@208 92
Chris@325 93 /**
Chris@325 94 * Block on a sub-event-loop until the availability of the file or
Chris@325 95 * remote URL is known.
Chris@325 96 */
Chris@325 97 void waitForStatus();
Chris@325 98
Chris@325 99 /**
Chris@325 100 * Block on a sub-event-loop until the whole of the data has been
Chris@325 101 * retrieved (if it is remote).
Chris@325 102 */
Chris@325 103 void waitForData();
Chris@325 104
Chris@325 105 /**
Chris@325 106 * Return true if the FileSource object is valid and no error
Chris@325 107 * occurred in looking up the file or remote URL. Non-existence
Chris@325 108 * of the file or URL is not an error -- call isAvailable() to
Chris@325 109 * test for that.
Chris@325 110 */
Chris@325 111 bool isOK() const;
Chris@325 112
Chris@325 113 /**
Chris@325 114 * Return true if the file or remote URL exists. This may block
Chris@325 115 * on a sub-event-loop (calling waitForStatus) if the status is
Chris@325 116 * not yet available.
Chris@325 117 */
Chris@210 118 bool isAvailable();
Chris@210 119
Chris@325 120 /**
Chris@325 121 * Return true if the entire file has been retrieved and is
Chris@325 122 * available.
Chris@325 123 */
Chris@325 124 bool isDone() const;
Chris@316 125
Chris@325 126 /**
Chris@706 127 * Return true if this FileSource is referring to a QRC resource.
Chris@706 128 */
Chris@706 129 bool isResource() const;
Chris@706 130
Chris@706 131 /**
Chris@325 132 * Return true if this FileSource is referring to a remote URL.
Chris@325 133 */
Chris@325 134 bool isRemote() const;
Chris@325 135
Chris@325 136 /**
Chris@325 137 * Return the location filename or URL as passed to the
Chris@325 138 * constructor.
Chris@325 139 */
Chris@325 140 QString getLocation() const;
Chris@325 141
Chris@325 142 /**
Chris@325 143 * Return the name of the local file this FileSource refers to.
Chris@325 144 * This is the filename that should be used when reading normally
Chris@325 145 * from the FileSource. If the filename passed to the constructor
Chris@325 146 * was a local file, this will return the same filename; otherwise
Chris@325 147 * this will be the name of the temporary cache file owned by the
Chris@325 148 * FileSource.
Chris@325 149 */
Chris@325 150 QString getLocalFilename() const;
Chris@325 151
Chris@325 152 /**
Chris@678 153 * Return the base name, i.e. the final path element (including
Chris@678 154 * extension, if any) of the location.
Chris@678 155 */
Chris@678 156 QString getBasename() const;
Chris@678 157
Chris@678 158 /**
Chris@325 159 * Return the MIME content type of this file, if known.
Chris@325 160 */
Chris@325 161 QString getContentType() const;
Chris@325 162
Chris@325 163 /**
Chris@325 164 * Return the file extension for this file, if any.
Chris@325 165 */
Chris@325 166 QString getExtension() const;
Chris@325 167
Chris@325 168 /**
Chris@325 169 * Return an error message, if isOK() is false.
Chris@325 170 */
Chris@325 171 QString getErrorString() const;
Chris@325 172
Chris@325 173 /**
Chris@325 174 * Specify whether any local, cached file should remain on disc
Chris@325 175 * after this FileSource has been destroyed. The default is false
Chris@469 176 * (cached files share their FileSource owners' lifespans).
Chris@325 177 */
Chris@316 178 void setLeaveLocalFile(bool leave);
Chris@208 179
Chris@325 180 /**
Chris@325 181 * Return true if the given filename or URL refers to a remote
Chris@325 182 * URL.
Chris@325 183 */
Chris@325 184 static bool isRemote(QString fileOrUrl);
Chris@210 185
Chris@325 186 /**
Chris@325 187 * Return true if FileSource can handle the retrieval scheme for
Chris@325 188 * the given URL (or if the URL is for a local file).
Chris@325 189 */
Chris@208 190 static bool canHandleScheme(QUrl url);
Chris@208 191
Chris@208 192 signals:
Chris@325 193 /**
Chris@325 194 * Emitted during URL retrieval, when the retrieval progress
Chris@325 195 * notches up to a new percentage.
Chris@325 196 */
Chris@208 197 void progress(int percent);
Chris@325 198
Chris@325 199 /**
Chris@325 200 * Emitted when the file's existence has been tested and/or
Chris@325 201 * response header received. Calls to isAvailable() after this
Chris@325 202 * has been emitted will not block.
Chris@325 203 */
Chris@325 204 void statusAvailable();
Chris@325 205
Chris@325 206 /**
Chris@325 207 * Emitted when the entire file data has been retrieved and the
Chris@325 208 * local file is complete (if no error has occurred).
Chris@325 209 */
Chris@208 210 void ready();
Chris@208 211
Chris@208 212 protected slots:
Chris@208 213 void dataReadProgress(int done, int total);
Chris@214 214 void httpResponseHeaderReceived(const QHttpResponseHeader &resp);
Chris@214 215 void ftpCommandFinished(int, bool);
Chris@208 216 void dataTransferProgress(qint64 done, qint64 total);
Chris@208 217 void done(bool error);
Chris@210 218 void cancelled();
Chris@208 219
Chris@208 220 protected:
Chris@317 221 FileSource &operator=(const FileSource &); // not provided
Chris@316 222
Chris@304 223 QUrl m_url;
Chris@208 224 QFtp *m_ftp;
Chris@208 225 QHttp *m_http;
Chris@208 226 QFile *m_localFile;
Chris@208 227 QString m_localFilename;
Chris@208 228 QString m_errorString;
Chris@315 229 QString m_contentType;
Chris@520 230 QString m_preferredContentType;
Chris@208 231 bool m_ok;
Chris@210 232 int m_lastStatus;
Chris@706 233 bool m_resource;
Chris@316 234 bool m_remote;
Chris@208 235 bool m_done;
Chris@316 236 bool m_leaveLocalFile;
Chris@392 237 ProgressReporter *m_reporter;
Chris@208 238
Chris@304 239 typedef std::map<QUrl, int> RemoteRefCountMap;
Chris@304 240 typedef std::map<QUrl, QString> RemoteLocalMap;
Chris@304 241 static RemoteRefCountMap m_refCountMap;
Chris@304 242 static RemoteLocalMap m_remoteLocalMap;
Chris@304 243 static QMutex m_mapMutex;
Chris@316 244 bool m_refCounted;
Chris@316 245
Chris@357 246 void init();
Chris@316 247 void initHttp();
Chris@316 248 void initFtp();
Chris@304 249
Chris@211 250 void cleanup();
Chris@211 251
Chris@316 252 // Create a local file for m_url. If it already existed, return true.
Chris@316 253 // The local filename is stored in m_localFilename.
Chris@316 254 bool createCacheFile();
Chris@316 255 void deleteCacheFile();
Chris@208 256
Chris@208 257 static QMutex m_fileCreationMutex;
Chris@208 258 static int m_count;
Chris@208 259 };
Chris@208 260
Chris@208 261 #endif