Mercurial > hg > svcore
comparison base/ResourceFinder.cpp @ 742:c10cb8782576 coreaudio_tests
Merge from branch "default"
author | Chris Cannam |
---|---|
date | Sun, 01 Jul 2012 11:53:00 +0100 |
parents | 66c3f4e060e9 |
children | e802e550a1f2 |
comparison
equal
deleted
inserted
replaced
666:4efa7429cd85 | 742:c10cb8782576 |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 Sonic Visualiser | |
5 An audio file viewer and annotation editor. | |
6 Centre for Digital Music, Queen Mary, University of London. | |
7 | |
8 This program is free software; you can redistribute it and/or | |
9 modify it under the terms of the GNU General Public License as | |
10 published by the Free Software Foundation; either version 2 of the | |
11 License, or (at your option) any later version. See the file | |
12 COPYING included with this distribution for more information. | |
13 */ | |
14 | |
15 /* | |
16 This is a modified version of a source file from the | |
17 Rosegarden MIDI and audio sequencer and notation editor. | |
18 This file copyright 2005-2011 Chris Cannam and the Rosegarden | |
19 development team. | |
20 */ | |
21 | |
22 #include "ResourceFinder.h" | |
23 | |
24 #include <QDir> | |
25 #include <QFileInfo> | |
26 #include <QStringList> | |
27 #include <QProcess> | |
28 #include <QCoreApplication> | |
29 | |
30 #include <cstdlib> | |
31 #include <iostream> | |
32 | |
33 /** | |
34 Resource files may be found in three places: | |
35 | |
36 * Bundled into the application as Qt4 resources. These may be | |
37 opened using Qt classes such as QFile, with "fake" file paths | |
38 starting with a colon. For example ":icons/fileopen.png". | |
39 | |
40 * Installed with the package, or in the user's equivalent home | |
41 directory location. For example, | |
42 | |
43 - on Linux, in /usr/share/<appname> or /usr/local/share/<appname> | |
44 - on Linux, in $HOME/.local/share/<appname> | |
45 | |
46 - on OS/X, in /Library/Application Support/<appname> | |
47 - on OS/X, in $HOME/Library/Application Support/<appname> | |
48 | |
49 - on Windows, in %ProgramFiles%/<company>/<appname> | |
50 - on Windows, in (where?) something from http://msdn.microsoft.com/en-us/library/dd378457%28v=vs.85%29.aspx ? | |
51 | |
52 These locations are searched in reverse order (user-installed | |
53 copies take priority over system-installed copies take priority | |
54 over bundled copies). Also, /usr/local takes priority over /usr. | |
55 */ | |
56 | |
57 QStringList | |
58 ResourceFinder::getSystemResourcePrefixList() | |
59 { | |
60 // returned in order of priority | |
61 | |
62 QStringList list; | |
63 | |
64 #ifdef Q_OS_WIN32 | |
65 char *programFiles = getenv("ProgramFiles"); | |
66 if (programFiles && programFiles[0]) { | |
67 list << QString("%1/%2/%3") | |
68 .arg(programFiles) | |
69 .arg(qApp->organizationName()) | |
70 .arg(qApp->applicationName()); | |
71 } else { | |
72 list << QString("C:/Program Files/%1/%2") | |
73 .arg(qApp->organizationName()) | |
74 .arg(qApp->applicationName()); | |
75 } | |
76 #else | |
77 #ifdef Q_OS_MAC | |
78 list << QString("/Library/Application Support/%1") | |
79 .arg(qApp->applicationName()); | |
80 #else | |
81 list << QString("/usr/local/share/%1") | |
82 .arg(qApp->applicationName()); | |
83 list << QString("/usr/share/%1") | |
84 .arg(qApp->applicationName()); | |
85 #endif | |
86 #endif | |
87 | |
88 return list; | |
89 } | |
90 | |
91 QString | |
92 ResourceFinder::getUserResourcePrefix() | |
93 { | |
94 #ifdef Q_OS_WIN32 | |
95 char *homedrive = getenv("HOMEDRIVE"); | |
96 char *homepath = getenv("HOMEPATH"); | |
97 QString home; | |
98 if (homedrive && homepath) { | |
99 home = QString("%1%2").arg(homedrive).arg(homepath); | |
100 } else { | |
101 home = QDir::home().absolutePath(); | |
102 } | |
103 if (home == "") return ""; | |
104 return QString("%1/.%2").arg(home).arg(qApp->applicationName()); //!!! wrong | |
105 #else | |
106 char *home = getenv("HOME"); | |
107 if (!home || !home[0]) return ""; | |
108 #ifdef Q_OS_MAC | |
109 return QString("%1/Library/Application Support/%2") | |
110 .arg(home) | |
111 .arg(qApp->applicationName()); | |
112 #else | |
113 return QString("%1/.local/share/%2") | |
114 .arg(home) | |
115 .arg(qApp->applicationName()); | |
116 #endif | |
117 #endif | |
118 } | |
119 | |
120 QStringList | |
121 ResourceFinder::getResourcePrefixList() | |
122 { | |
123 // returned in order of priority | |
124 | |
125 QStringList list; | |
126 | |
127 QString user = getUserResourcePrefix(); | |
128 if (user != "") list << user; | |
129 | |
130 list << getSystemResourcePrefixList(); | |
131 | |
132 list << ":"; // bundled resource location | |
133 | |
134 return list; | |
135 } | |
136 | |
137 QString | |
138 ResourceFinder::getResourcePath(QString resourceCat, QString fileName) | |
139 { | |
140 // We don't simply call getResourceDir here, because that returns | |
141 // only the "installed file" location. We also want to search the | |
142 // bundled resources and user-saved files. | |
143 | |
144 QStringList prefixes = getResourcePrefixList(); | |
145 | |
146 if (resourceCat != "") resourceCat = "/" + resourceCat; | |
147 | |
148 for (QStringList::const_iterator i = prefixes.begin(); | |
149 i != prefixes.end(); ++i) { | |
150 | |
151 QString prefix = *i; | |
152 | |
153 SVDEBUG << "ResourceFinder::getResourcePath: Looking up file \"" << fileName << "\" for category \"" << resourceCat << "\" in prefix \"" << prefix << "\"" << endl; | |
154 | |
155 QString path = | |
156 QString("%1%2/%3").arg(prefix).arg(resourceCat).arg(fileName); | |
157 if (QFileInfo(path).exists() && QFileInfo(path).isReadable()) { | |
158 std::cerr << "Found it!" << std::endl; | |
159 return path; | |
160 } | |
161 } | |
162 | |
163 return ""; | |
164 } | |
165 | |
166 QString | |
167 ResourceFinder::getResourceDir(QString resourceCat) | |
168 { | |
169 // Returns only the "installed file" location | |
170 | |
171 QStringList prefixes = getSystemResourcePrefixList(); | |
172 | |
173 if (resourceCat != "") resourceCat = "/" + resourceCat; | |
174 | |
175 for (QStringList::const_iterator i = prefixes.begin(); | |
176 i != prefixes.end(); ++i) { | |
177 | |
178 QString prefix = *i; | |
179 QString path = QString("%1%2").arg(prefix).arg(resourceCat); | |
180 if (QFileInfo(path).exists() && | |
181 QFileInfo(path).isDir() && | |
182 QFileInfo(path).isReadable()) { | |
183 return path; | |
184 } | |
185 } | |
186 | |
187 return ""; | |
188 } | |
189 | |
190 QString | |
191 ResourceFinder::getResourceSavePath(QString resourceCat, QString fileName) | |
192 { | |
193 QString dir = getResourceSaveDir(resourceCat); | |
194 if (dir == "") return ""; | |
195 | |
196 return dir + "/" + fileName; | |
197 } | |
198 | |
199 QString | |
200 ResourceFinder::getResourceSaveDir(QString resourceCat) | |
201 { | |
202 // Returns the "user" location | |
203 | |
204 QString user = getUserResourcePrefix(); | |
205 if (user == "") return ""; | |
206 | |
207 if (resourceCat != "") resourceCat = "/" + resourceCat; | |
208 | |
209 QDir userDir(user); | |
210 if (!userDir.exists()) { | |
211 if (!userDir.mkpath(user)) { | |
212 std::cerr << "ResourceFinder::getResourceSaveDir: ERROR: Failed to create user resource path \"" << user << "\"" << std::endl; | |
213 return ""; | |
214 } | |
215 } | |
216 | |
217 if (resourceCat != "") { | |
218 QString save = QString("%1%2").arg(user).arg(resourceCat); | |
219 QDir saveDir(save); | |
220 if (!saveDir.exists()) { | |
221 if (!userDir.mkpath(save)) { | |
222 std::cerr << "ResourceFinder::getResourceSaveDir: ERROR: Failed to create user resource path \"" << save << "\"" << std::endl; | |
223 return ""; | |
224 } | |
225 } | |
226 return save; | |
227 } else { | |
228 return user; | |
229 } | |
230 } | |
231 | |
232 QStringList | |
233 ResourceFinder::getResourceFiles(QString resourceCat, QString fileExt) | |
234 { | |
235 QStringList results; | |
236 QStringList prefixes = getResourcePrefixList(); | |
237 | |
238 QStringList filters; | |
239 filters << QString("*.%1").arg(fileExt); | |
240 | |
241 for (QStringList::const_iterator i = prefixes.begin(); | |
242 i != prefixes.end(); ++i) { | |
243 | |
244 QString prefix = *i; | |
245 QString path; | |
246 | |
247 if (resourceCat != "") { | |
248 path = QString("%1/%2").arg(prefix).arg(resourceCat); | |
249 } else { | |
250 path = prefix; | |
251 } | |
252 | |
253 QDir dir(path); | |
254 if (!dir.exists()) continue; | |
255 | |
256 dir.setNameFilters(filters); | |
257 QStringList entries = dir.entryList | |
258 (QDir::Files | QDir::Readable, QDir::Name); | |
259 | |
260 for (QStringList::const_iterator j = entries.begin(); | |
261 j != entries.end(); ++j) { | |
262 results << QString("%1/%2").arg(path).arg(*j); | |
263 } | |
264 } | |
265 | |
266 return results; | |
267 } | |
268 | |
269 bool | |
270 ResourceFinder::unbundleResource(QString resourceCat, QString fileName) | |
271 { | |
272 QString path = getResourcePath(resourceCat, fileName); | |
273 | |
274 if (!path.startsWith(':')) return true; | |
275 | |
276 // This is the lowest-priority alternative path for this | |
277 // resource, so we know that there must be no installed copy. | |
278 // Install one to the user location. | |
279 SVDEBUG << "ResourceFinder::unbundleResource: File " << fileName << " is bundled, un-bundling it" << endl; | |
280 QString target = getResourceSavePath(resourceCat, fileName); | |
281 QFile file(path); | |
282 if (!file.copy(target)) { | |
283 std::cerr << "ResourceFinder::unbundleResource: ERROR: Failed to un-bundle resource file \"" << fileName << "\" to user location \"" << target << "\"" << std::endl; | |
284 return false; | |
285 } | |
286 | |
287 QFile chmod(target); | |
288 chmod.setPermissions(QFile::ReadOwner | | |
289 QFile::ReadUser | /* for potential platform-independence */ | |
290 QFile::ReadGroup | | |
291 QFile::ReadOther | | |
292 QFile::WriteOwner| | |
293 QFile::WriteUser); /* for potential platform-independence */ | |
294 | |
295 return true; | |
296 } | |
297 |