Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsuserprofilemanager.cpp 3 : : -------------------------------------- 4 : : Date : Jul-2017 5 : : Copyright : (C) 2017 by Nathan Woodrow 6 : : Email : woodrow.nathan at gmail dot com 7 : : *************************************************************************** 8 : : * * 9 : : * This program is free software; you can redistribute it and/or modify * 10 : : * it under the terms of the GNU General Public License as published by * 11 : : * the Free Software Foundation; either version 2 of the License, or * 12 : : * (at your option) any later version. * 13 : : * * 14 : : ***************************************************************************/ 15 : : 16 : : #include "qgsuserprofilemanager.h" 17 : : #include "qgsuserprofile.h" 18 : : #include "qgsapplication.h" 19 : : #include "qgslogger.h" 20 : : #include "qgssettings.h" 21 : : 22 : : #include <QFile> 23 : : #include <QDir> 24 : : #include <QTextStream> 25 : : #include <QProcess> 26 : : #include <QStandardPaths> 27 : : 28 : : 29 : 7 : QgsUserProfileManager::QgsUserProfileManager( const QString &rootLocation, QObject *parent ) 30 : 7 : : QObject( parent ) 31 : 14 : { 32 : 7 : setRootLocation( rootLocation ); 33 : 7 : } 34 : : 35 : 7 : QString QgsUserProfileManager::resolveProfilesFolder( const QString &basePath ) 36 : : { 37 : 7 : return basePath + QDir::separator() + "profiles"; 38 : : } 39 : : 40 : 7 : QgsUserProfile *QgsUserProfileManager::getProfile( const QString &defaultProfile, bool createNew, bool initSettings ) 41 : : { 42 : 7 : QString profileName = defaultProfile.isEmpty() ? defaultProfileName() : defaultProfile; 43 : : 44 : 7 : if ( createNew && !profileExists( defaultProfile ) ) 45 : : { 46 : 0 : createUserProfile( profileName ); 47 : 0 : } 48 : : 49 : 7 : QgsUserProfile *profile = profileForName( profileName ); 50 : 7 : if ( initSettings ) 51 : 7 : profile->initSettings(); 52 : : 53 : 7 : return profile; 54 : 7 : } 55 : : 56 : 7 : void QgsUserProfileManager::setRootLocation( const QString &rootProfileLocation ) 57 : : { 58 : 7 : mRootProfilePath = rootProfileLocation; 59 : : 60 : : //updates (or removes) profile file watcher for new root location 61 : 7 : setNewProfileNotificationEnabled( mWatchProfiles ); 62 : : 63 : 7 : mSettings.reset( new QSettings( settingsFile(), QSettings::IniFormat ) ); 64 : 7 : } 65 : : 66 : 7 : void QgsUserProfileManager::setNewProfileNotificationEnabled( bool enabled ) 67 : : { 68 : 7 : mWatchProfiles = enabled; 69 : 7 : if ( mWatchProfiles && !mRootProfilePath.isEmpty() && QDir( mRootProfilePath ).exists() ) 70 : : { 71 : 0 : mWatcher.reset( new QFileSystemWatcher() ); 72 : 0 : mWatcher->addPath( mRootProfilePath ); 73 : 0 : connect( mWatcher.get(), &QFileSystemWatcher::directoryChanged, this, [this] 74 : : { 75 : 0 : emit profilesChanged(); 76 : 0 : } ); 77 : 0 : } 78 : : else 79 : : { 80 : 7 : mWatcher.reset(); 81 : : } 82 : 7 : } 83 : : 84 : 0 : bool QgsUserProfileManager::isNewProfileNotificationEnabled() const 85 : : { 86 : 0 : return static_cast< bool >( mWatcher.get() ); 87 : : } 88 : : 89 : 0 : bool QgsUserProfileManager::rootLocationIsSet() const 90 : : { 91 : 0 : return !mRootProfilePath.isEmpty(); 92 : : } 93 : : 94 : 0 : QString QgsUserProfileManager::defaultProfileName() const 95 : : { 96 : 0 : QString defaultName = QStringLiteral( "default" ); 97 : : // If the profiles.ini doesn't have the default profile we grab it from 98 : : // global settings as it might be set by the admin. 99 : : // If the overrideProfile flag is set then no matter what the profiles.ini says we always take the 100 : : // global profile. 101 : 0 : QgsSettings globalSettings; 102 : 0 : if ( !mSettings->contains( QStringLiteral( "/core/defaultProfile" ) ) || globalSettings.value( QStringLiteral( "overrideLocalProfile" ), false, QgsSettings::Core ).toBool() ) 103 : : { 104 : 0 : return globalSettings.value( QStringLiteral( "defaultProfile" ), defaultName, QgsSettings::Core ).toString(); 105 : : } 106 : 0 : return mSettings->value( QStringLiteral( "/core/defaultProfile" ), defaultName ).toString(); 107 : 0 : } 108 : : 109 : 0 : void QgsUserProfileManager::setDefaultProfileName( const QString &name ) 110 : : { 111 : 0 : mSettings->setValue( QStringLiteral( "/core/defaultProfile" ), name ); 112 : 0 : mSettings->sync(); 113 : 0 : } 114 : : 115 : 0 : void QgsUserProfileManager::setDefaultFromActive() 116 : : { 117 : 0 : setDefaultProfileName( userProfile()->name() ); 118 : 0 : } 119 : : 120 : 7 : QStringList QgsUserProfileManager::allProfiles() const 121 : : { 122 : 7 : return QDir( mRootProfilePath ).entryList( QDir::Dirs | QDir::NoDotAndDotDot ); 123 : 0 : } 124 : : 125 : 7 : bool QgsUserProfileManager::profileExists( const QString &name ) const 126 : : { 127 : 7 : return allProfiles().contains( name ); 128 : 0 : } 129 : : 130 : 7 : QgsUserProfile *QgsUserProfileManager::profileForName( const QString &name ) const 131 : : { 132 : 7 : QString profilePath = mRootProfilePath + QDir::separator() + name; 133 : 7 : return new QgsUserProfile( profilePath ); 134 : 7 : } 135 : : 136 : 0 : QgsError QgsUserProfileManager::createUserProfile( const QString &name ) 137 : : { 138 : 0 : QgsError error; 139 : : 140 : : // TODO Replace with safe folder name 141 : : 142 : 0 : QDir folder( mRootProfilePath + QDir::separator() + name ); 143 : 0 : if ( !folder.exists() ) 144 : : { 145 : 0 : QDir().mkpath( folder.absolutePath() ); 146 : 0 : } 147 : : 148 : 0 : QFile qgisPrivateDbFile( folder.absolutePath() + QDir::separator() + "qgis.db" ); 149 : : 150 : : // first we look for ~/.qgis/qgis.db 151 : 0 : if ( !qgisPrivateDbFile.exists() ) 152 : : { 153 : : // if it doesn't exist we copy it from the global resources dir 154 : 0 : QString qgisMasterDbFileName = QgsApplication::qgisMasterDatabaseFilePath(); 155 : 0 : QFile masterFile( qgisMasterDbFileName ); 156 : : 157 : : //now copy the master file into the users .qgis dir 158 : 0 : masterFile.copy( qgisPrivateDbFile.fileName() ); 159 : : 160 : : // In some packaging systems, the master can be read-only. Make sure to make 161 : : // the copy user writable. 162 : 0 : const QFile::Permissions perms = QFile( qgisPrivateDbFile.fileName() ).permissions(); 163 : 0 : if ( !( perms & QFile::WriteOwner ) ) 164 : : { 165 : 0 : if ( !qgisPrivateDbFile.setPermissions( perms | QFile::WriteOwner ) ) 166 : : { 167 : 0 : error.append( tr( "Can not make '%1' user writable" ).arg( qgisPrivateDbFile.fileName() ) ); 168 : 0 : } 169 : 0 : } 170 : 0 : } 171 : : 172 : 0 : if ( error.isEmpty() ) 173 : : { 174 : 0 : emit profilesChanged(); 175 : 0 : } 176 : : 177 : 0 : return error; 178 : 0 : } 179 : : 180 : 0 : QgsError QgsUserProfileManager::deleteProfile( const QString &name ) 181 : : { 182 : 0 : QgsError error; 183 : 0 : QDir folder( mRootProfilePath + QDir::separator() + name ); 184 : : 185 : : // This might have to be changed to something better. 186 : 0 : bool deleted = folder.removeRecursively(); 187 : 0 : if ( !deleted ) 188 : : { 189 : 0 : error.append( ( tr( "Unable to fully delete user profile folder" ) ) ); 190 : 0 : } 191 : : else 192 : : { 193 : 0 : emit profilesChanged(); 194 : : } 195 : 0 : return error; 196 : 0 : } 197 : : 198 : 7 : QString QgsUserProfileManager::settingsFile() const 199 : : { 200 : 7 : return mRootProfilePath + QDir::separator() + "profiles.ini"; 201 : : } 202 : : 203 : 7 : QgsUserProfile *QgsUserProfileManager::userProfile() 204 : : { 205 : 0 : return mUserProfile.get(); 206 : : } 207 : : 208 : 0 : void QgsUserProfileManager::loadUserProfile( const QString &name ) 209 : : { 210 : : #if QT_CONFIG(process) 211 : 0 : QString path = QDir::toNativeSeparators( QCoreApplication::applicationFilePath() ); 212 : 0 : QStringList arguments; 213 : 0 : arguments << QCoreApplication::arguments(); 214 : : // The first is the path to the application 215 : : // on Windows this might not be case so we need to handle that 216 : : // http://doc.qt.io/qt-5/qcoreapplication.html#arguments 217 : 0 : arguments.removeFirst(); 218 : 0 : arguments << QStringLiteral( "--profile" ) << name; 219 : 0 : QgsDebugMsg( QStringLiteral( "Starting instance from %1 with %2" ).arg( path ).arg( arguments.join( " " ) ) ); 220 : 0 : QProcess::startDetached( path, arguments, QDir::toNativeSeparators( QCoreApplication::applicationDirPath() ) ); 221 : : #else 222 : : Q_UNUSED( name ) 223 : : Q_ASSERT( "Starting the user profile is not supported on the platform" ); 224 : : #endif //QT_CONFIG(process) 225 : 0 : } 226 : : 227 : 0 : void QgsUserProfileManager::setActiveUserProfile( const QString &profile ) 228 : : { 229 : 0 : if ( ! mUserProfile.get() ) 230 : : { 231 : 0 : mUserProfile.reset( profileForName( profile ) ); 232 : 0 : } 233 : 0 : }