File indexing completed on 2024-03-24 03:52:26
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2004-2007 Torsten Rahn <tackat@kde.org> 0004 // SPDX-FileCopyrightText: 2007 Inge Wallin <ingwa@kde.org> 0005 // 0006 0007 0008 #include "MarbleDirs.h" 0009 #include "MarbleDebug.h" 0010 0011 #include <QFile> 0012 #include <QString> 0013 #include <QStringList> 0014 #include <QCoreApplication> 0015 0016 #include <cstdlib> 0017 0018 #include <QStandardPaths> 0019 0020 #ifdef Q_OS_WIN 0021 //for getting appdata path 0022 //mingw-w64 Internet Explorer 5.01 0023 #define _WIN32_IE 0x0501 0024 #include <shlobj.h> 0025 #endif 0026 0027 #ifdef Q_OS_MACX 0028 //for getting app bundle path 0029 #include <ApplicationServices/ApplicationServices.h> 0030 #endif 0031 0032 #include <config-marble.h> 0033 0034 using namespace Marble; 0035 0036 namespace 0037 { 0038 QString runTimeMarbleDataPath; 0039 0040 QString runTimeMarblePluginPath; 0041 } 0042 0043 MarbleDirs::MarbleDirs() 0044 : d( nullptr ) 0045 { 0046 } 0047 0048 0049 QString MarbleDirs::path( const QString& relativePath ) 0050 { 0051 QString localpath = localPath() + QLatin1Char('/') + relativePath; // local path 0052 QString systempath = systemPath() + QLatin1Char('/') + relativePath; // system path 0053 0054 0055 QString fullpath = systempath; 0056 if ( QFile::exists( localpath ) ) { 0057 fullpath = localpath; 0058 } 0059 return QDir( fullpath ).canonicalPath(); 0060 } 0061 0062 0063 QString MarbleDirs::pluginPath( const QString& relativePath ) 0064 { 0065 const QString localpath = pluginLocalPath() + QDir::separator() + relativePath; // local path 0066 const QString systempath = pluginSystemPath() + QDir::separator() + relativePath; // system path 0067 0068 0069 QString fullpath = systempath; 0070 if ( QFile::exists( localpath ) ) { 0071 fullpath = localpath; 0072 } 0073 0074 return QDir( fullpath ).canonicalPath(); 0075 } 0076 0077 QStringList MarbleDirs::entryList( const QString& relativePath, QDir::Filters filters ) 0078 { 0079 QStringList filesLocal = QDir(MarbleDirs::localPath() + QLatin1Char('/') + relativePath).entryList(filters); 0080 QStringList filesSystem = QDir(MarbleDirs::systemPath() + QLatin1Char('/') + relativePath).entryList(filters); 0081 QStringList allFiles( filesLocal ); 0082 allFiles << filesSystem; 0083 0084 // remove duplicate entries 0085 allFiles.sort(); 0086 for ( int i = 1; i < allFiles.size(); ++i ) { 0087 if ( allFiles.at(i) == allFiles.at( i - 1 ) ) { 0088 allFiles.removeAt(i); 0089 --i; 0090 } 0091 } 0092 0093 return allFiles; 0094 } 0095 0096 QStringList MarbleDirs::pluginEntryList( const QString& relativePath, QDir::Filters filters ) 0097 { 0098 QStringList allFiles = QDir(MarbleDirs::pluginLocalPath() + QLatin1Char('/') + relativePath).entryList(filters); 0099 auto const pluginSystemPath = MarbleDirs::pluginSystemPath(); 0100 if (!pluginSystemPath.isEmpty()) { 0101 allFiles << QDir(pluginSystemPath + QLatin1Char('/') + relativePath).entryList(filters); 0102 } 0103 0104 // remove duplicate entries 0105 allFiles.sort(); 0106 for ( int i = 1; i < allFiles.size(); ++i ) { 0107 if ( allFiles.at(i) == allFiles.at( i - 1 ) ) { 0108 allFiles.removeAt(i); 0109 --i; 0110 } 0111 } 0112 0113 return allFiles; 0114 } 0115 0116 QString MarbleDirs::systemPath() 0117 { 0118 if (!runTimeMarbleDataPath.isEmpty()) { 0119 return runTimeMarbleDataPath; 0120 } 0121 0122 QString systempath; 0123 0124 #ifdef MARBLE_DATA_PATH 0125 //MARBLE_DATA_PATH is a compiler define set by cmake 0126 QString compileTimeMarbleDataPath(MARBLE_DATA_PATH); 0127 0128 if(QDir(compileTimeMarbleDataPath).exists()) 0129 return compileTimeMarbleDataPath; 0130 #endif // MARBLE_DATA_PATH 0131 0132 0133 #ifdef Q_OS_WIN 0134 return QCoreApplication::applicationDirPath() + QDir::separator() + QLatin1String("data"); 0135 #endif 0136 0137 #ifdef Q_OS_MACX 0138 // 0139 // On OSX lets try to find any file first in the bundle 0140 // before branching out to home and sys dirs 0141 // 0142 CFURLRef myBundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle()); 0143 CFStringRef myMacPath = CFURLCopyFileSystemPath(myBundleRef, kCFURLPOSIXPathStyle); 0144 const char *mypPathPtr = CFStringGetCStringPtr(myMacPath,CFStringGetSystemEncoding()); 0145 CFRelease(myBundleRef); 0146 QString myPath(mypPathPtr); 0147 CFRelease(myMacPath); 0148 //do some magick so that we can still find data dir if 0149 //marble was not built as a bundle 0150 if (myPath.contains(QLatin1String(".app"))) { //its a bundle! 0151 systempath = myPath + QLatin1String("/Contents/Resources/data"); 0152 } 0153 0154 if ( QFile::exists( systempath ) ){ 0155 return systempath; 0156 } 0157 #endif // mac bundle 0158 0159 #ifdef Q_OS_ANDROID 0160 systempath = "assets:/data"; 0161 return systempath; 0162 #endif 0163 0164 // This is the preferred fallback location if no marbleDataPath is set. 0165 systempath = QDir( QCoreApplication::applicationDirPath() + QLatin1String( "/data" ) ).canonicalPath(); 0166 0167 if ( QFile::exists( systempath ) ){ 0168 return systempath; 0169 } 0170 0171 // This fallback location is for compatibility with KDE installations. 0172 return QDir( QCoreApplication::applicationDirPath() 0173 + QLatin1String( "/../share/apps/marble/data" ) 0174 ).canonicalPath(); 0175 } 0176 0177 QString MarbleDirs::pluginSystemPath() 0178 { 0179 if (!runTimeMarblePluginPath.isEmpty()) { 0180 return runTimeMarblePluginPath; 0181 } 0182 0183 QString systempath; 0184 0185 #ifdef MARBLE_PLUGIN_PATH 0186 //MARBLE_PLUGIN_PATH is a compiler define set by cmake 0187 QString compileTimeMarblePluginPath(MARBLE_PLUGIN_PATH); 0188 0189 if(QDir(compileTimeMarblePluginPath).exists()) 0190 return compileTimeMarblePluginPath; 0191 #endif // MARBLE_PLUGIN_PATH 0192 0193 #ifdef Q_OS_MACX 0194 // 0195 // On OSX lets try to find any file first in the bundle 0196 // before branching out to home and sys dirs 0197 // 0198 CFURLRef myBundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle()); 0199 CFStringRef myMacPath = CFURLCopyFileSystemPath(myBundleRef, kCFURLPOSIXPathStyle); 0200 const char *mypPathPtr = CFStringGetCStringPtr(myMacPath,CFStringGetSystemEncoding()); 0201 CFRelease(myBundleRef); 0202 CFRelease(myMacPath); 0203 QString myPath(mypPathPtr); 0204 //do some magick so that we can still find data dir if 0205 //marble was not built as a bundle 0206 if (myPath.contains(QLatin1String(".app"))) { //its a bundle! 0207 systempath = myPath + QLatin1String("/Contents/Resources/plugins"); 0208 } 0209 0210 if ( QFile::exists( systempath ) ){ 0211 return systempath; 0212 } 0213 #endif // mac bundle 0214 0215 #ifdef Q_OS_WIN 0216 return QCoreApplication::applicationDirPath() + QDir::separator() + QLatin1String("plugins"); 0217 #endif 0218 0219 #ifdef Q_OS_ANDROID 0220 return "assets:/plugins"; 0221 #endif 0222 0223 // This is the preferred fallback location if no marblePluginPath is set. 0224 systempath = QDir( QCoreApplication::applicationDirPath() + QLatin1String( "/plugins" ) ).canonicalPath(); 0225 0226 if ( QFile::exists( systempath ) ){ 0227 return systempath; 0228 } 0229 0230 // This ultimate fallback location is for compatibility with KDE installations. 0231 return QDir( QCoreApplication::applicationDirPath() 0232 + QLatin1String( "/../lib/kde4/plugins/marble" ) 0233 ).canonicalPath(); 0234 } 0235 0236 QString MarbleDirs::localPath() 0237 { 0238 #ifndef Q_OS_WIN 0239 QString dataHome = getenv( "XDG_DATA_HOME" ); 0240 if( dataHome.isEmpty() ) 0241 dataHome = QDir::homePath() + QLatin1String("/.local/share"); 0242 0243 return dataHome + QLatin1String("/marble"); // local path 0244 #else 0245 return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/.marble/data"); 0246 #endif 0247 } 0248 0249 QStringList MarbleDirs::oldLocalPaths() 0250 { 0251 QStringList possibleOldPaths; 0252 0253 #ifndef Q_OS_WIN 0254 const QString oldDefault = QDir::homePath() + QLatin1String("/.marble/data"); 0255 possibleOldPaths.append( oldDefault ); 0256 0257 const QString xdgDefault = QDir::homePath() + QLatin1String("/.local/share/marble"); 0258 possibleOldPaths.append( xdgDefault ); 0259 0260 QString xdg = getenv( "XDG_DATA_HOME" ); 0261 xdg += QLatin1String("/marble/"); 0262 possibleOldPaths.append( xdg ); 0263 #endif 0264 0265 #ifdef Q_OS_WIN 0266 HWND hwnd = 0; 0267 WCHAR *appdata_path = new WCHAR[MAX_PATH + 1]; 0268 0269 SHGetSpecialFolderPathW(hwnd, appdata_path, CSIDL_APPDATA, 0); 0270 QString appdata = QString::fromUtf16(reinterpret_cast<ushort*>(appdata_path)); 0271 delete[] appdata_path; 0272 possibleOldPaths << QString(QDir::fromNativeSeparators(appdata) + QLatin1String("/.marble/data")); // local path 0273 #endif 0274 0275 QString currentLocalPath = QDir( MarbleDirs::localPath() ).canonicalPath(); 0276 QStringList oldPaths; 0277 for( const QString& possibleOldPath: possibleOldPaths ) { 0278 if( !QDir().exists( possibleOldPath ) ) { 0279 continue; 0280 } 0281 0282 QString canonicalPossibleOldPath = QDir( possibleOldPath ).canonicalPath(); 0283 if( canonicalPossibleOldPath == currentLocalPath ) { 0284 continue; 0285 } 0286 0287 oldPaths.append( canonicalPossibleOldPath ); 0288 } 0289 0290 return oldPaths; 0291 } 0292 0293 QString MarbleDirs::pluginLocalPath() 0294 { 0295 #ifndef Q_OS_WIN 0296 return QDir::homePath() + QLatin1String("/.marble/plugins"); // local path 0297 #else 0298 return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/.marble/plugins"); 0299 #endif 0300 } 0301 0302 QString MarbleDirs::marbleDataPath() 0303 { 0304 return runTimeMarbleDataPath; 0305 } 0306 0307 QString MarbleDirs::marblePluginPath() 0308 { 0309 return runTimeMarblePluginPath; 0310 } 0311 0312 void MarbleDirs::setMarbleDataPath( const QString& adaptedPath ) 0313 { 0314 if ( !QDir::root().exists( adaptedPath ) ) 0315 { 0316 qWarning() << QString( "Invalid MarbleDataPath \"%1\". Using \"%2\" instead." ).arg( adaptedPath, systemPath() ); 0317 return; 0318 } 0319 0320 runTimeMarbleDataPath = adaptedPath; 0321 } 0322 0323 void MarbleDirs::setMarblePluginPath( const QString& adaptedPath ) 0324 { 0325 if ( !QDir::root().exists( adaptedPath ) ) 0326 { 0327 qWarning() << QString( "Invalid MarblePluginPath \"%1\". Using \"%2\" instead." ).arg( adaptedPath, pluginSystemPath() ); 0328 return; 0329 } 0330 0331 runTimeMarblePluginPath = adaptedPath; 0332 } 0333 0334 0335 void MarbleDirs::debug() 0336 { 0337 mDebug() << "=== MarbleDirs: ==="; 0338 mDebug() << "Local Path:" << localPath(); 0339 mDebug() << "Plugin Local Path:" << pluginLocalPath(); 0340 mDebug() << ""; 0341 mDebug() << "Marble Data Path (Run Time) :" << runTimeMarbleDataPath; 0342 mDebug() << "Marble Data Path (Compile Time):" << QString(MARBLE_DATA_PATH); 0343 mDebug() << ""; 0344 mDebug() << "Marble Plugin Path (Run Time) :" << runTimeMarblePluginPath; 0345 mDebug() << "Marble Plugin Path (Compile Time):" << QString(MARBLE_PLUGIN_PATH); 0346 mDebug() << ""; 0347 mDebug() << "System Path:" << systemPath(); 0348 mDebug() << "Plugin System Path:" << pluginSystemPath(); 0349 mDebug() << "==================="; 0350 }