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