annotate base/ResourceFinder.cpp @ 718:f3fd2988fc9b

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