QGIS API Documentation  3.21.0-Master (5b68dc587e)
qgsuserprofilemanager.cpp
Go to the documentation of this file.
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 QgsUserProfileManager::QgsUserProfileManager( const QString &rootLocation, QObject *parent )
30  : QObject( parent )
31 {
33 }
34 
35 QString QgsUserProfileManager::resolveProfilesFolder( const QString &basePath )
36 {
37  return basePath + QDir::separator() + "profiles";
38 }
39 
40 QgsUserProfile *QgsUserProfileManager::getProfile( const QString &defaultProfile, bool createNew, bool initSettings )
41 {
42  const QString profileName = defaultProfile.isEmpty() ? defaultProfileName() : defaultProfile;
43 
44  if ( createNew && !profileExists( defaultProfile ) )
45  {
46  createUserProfile( profileName );
47  }
48 
49  QgsUserProfile *profile = profileForName( profileName );
50  if ( initSettings )
51  profile->initSettings();
52 
53  return profile;
54 }
55 
56 void QgsUserProfileManager::setRootLocation( const QString &rootProfileLocation )
57 {
58  mRootProfilePath = rootProfileLocation;
59 
60  //updates (or removes) profile file watcher for new root location
61  setNewProfileNotificationEnabled( mWatchProfiles );
62 
63  mSettings.reset( new QSettings( settingsFile(), QSettings::IniFormat ) );
64 }
65 
67 {
68  mWatchProfiles = enabled;
69  if ( mWatchProfiles && !mRootProfilePath.isEmpty() && QDir( mRootProfilePath ).exists() )
70  {
71  mWatcher.reset( new QFileSystemWatcher() );
72  mWatcher->addPath( mRootProfilePath );
73  connect( mWatcher.get(), &QFileSystemWatcher::directoryChanged, this, [this]
74  {
75  emit profilesChanged();
76  } );
77  }
78  else
79  {
80  mWatcher.reset();
81  }
82 }
83 
85 {
86  return static_cast< bool >( mWatcher.get() );
87 }
88 
90 {
91  return !mRootProfilePath.isEmpty();
92 }
93 
95 {
96  const 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  const QgsSettings globalSettings;
102  if ( !mSettings->contains( QStringLiteral( "/core/defaultProfile" ) ) || globalSettings.value( QStringLiteral( "overrideLocalProfile" ), false, QgsSettings::Core ).toBool() )
103  {
104  return globalSettings.value( QStringLiteral( "defaultProfile" ), defaultName, QgsSettings::Core ).toString();
105  }
106  return mSettings->value( QStringLiteral( "/core/defaultProfile" ), defaultName ).toString();
107 }
108 
110 {
111  mSettings->setValue( QStringLiteral( "/core/defaultProfile" ), name );
112  mSettings->sync();
113 }
114 
116 {
117  setDefaultProfileName( userProfile()->name() );
118 }
119 
121 {
122  return QDir( mRootProfilePath ).entryList( QDir::Dirs | QDir::NoDotAndDotDot );
123 }
124 
125 bool QgsUserProfileManager::profileExists( const QString &name ) const
126 {
127  return allProfiles().contains( name );
128 }
129 
131 {
132  const QString profilePath = mRootProfilePath + QDir::separator() + name;
133  return new QgsUserProfile( profilePath );
134 }
135 
137 {
138  QgsError error;
139 
140  // TODO Replace with safe folder name
141 
142  const QDir folder( mRootProfilePath + QDir::separator() + name );
143  if ( !folder.exists() )
144  {
145  QDir().mkpath( folder.absolutePath() );
146  }
147 
148  QFile qgisPrivateDbFile( folder.absolutePath() + QDir::separator() + "qgis.db" );
149 
150  // first we look for ~/.qgis/qgis.db
151  if ( !qgisPrivateDbFile.exists() )
152  {
153  // if it doesn't exist we copy it from the global resources dir
154  const QString qgisMasterDbFileName = QgsApplication::qgisMasterDatabaseFilePath();
155  QFile masterFile( qgisMasterDbFileName );
156 
157  //now copy the master file into the users .qgis dir
158  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  const QFile::Permissions perms = QFile( qgisPrivateDbFile.fileName() ).permissions();
163  if ( !( perms & QFile::WriteOwner ) )
164  {
165  if ( !qgisPrivateDbFile.setPermissions( perms | QFile::WriteOwner ) )
166  {
167  error.append( tr( "Can not make '%1' user writable" ).arg( qgisPrivateDbFile.fileName() ) );
168  }
169  }
170  }
171 
172  if ( error.isEmpty() )
173  {
174  emit profilesChanged();
175  }
176 
177  return error;
178 }
179 
181 {
182  QgsError error;
183  QDir folder( mRootProfilePath + QDir::separator() + name );
184 
185  // This might have to be changed to something better.
186  const bool deleted = folder.removeRecursively();
187  if ( !deleted )
188  {
189  error.append( ( tr( "Unable to fully delete user profile folder" ) ) );
190  }
191  else
192  {
193  emit profilesChanged();
194  }
195  return error;
196 }
197 
198 QString QgsUserProfileManager::settingsFile() const
199 {
200  return mRootProfilePath + QDir::separator() + "profiles.ini";
201 }
202 
204 {
205  return mUserProfile.get();
206 }
207 
208 void QgsUserProfileManager::loadUserProfile( const QString &name )
209 {
210 #if QT_CONFIG(process)
211  const QString path = QDir::toNativeSeparators( QCoreApplication::applicationFilePath() );
212  QStringList arguments;
213  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  arguments.removeFirst();
218  arguments << QStringLiteral( "--profile" ) << name;
219  QgsDebugMsg( QStringLiteral( "Starting instance from %1 with %2" ).arg( path ).arg( arguments.join( " " ) ) );
220  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 }
226 
227 void QgsUserProfileManager::setActiveUserProfile( const QString &profile )
228 {
229  if ( ! mUserProfile.get() )
230  {
231  mUserProfile.reset( profileForName( profile ) );
232  }
233 }
static QString qgisMasterDatabaseFilePath()
Returns the path to the master qgis.db file.
QgsError is container for error messages (report).
Definition: qgserror.h:81
bool isEmpty() const
Test if any error is set.
Definition: qgserror.h:111
void append(const QString &message, const QString &tag)
Append new error message.
Definition: qgserror.cpp:39
QgsUserProfile * getProfile(const QString &defaultProfile="default", bool createNew=true, bool initSettings=true)
Returns the profile from the given root profile location.
void setRootLocation(const QString &rootProfileLocation)
Set the root profile location for the profile manager.
QgsError createUserProfile(const QString &name)
Create a user profile given by the name.
void setActiveUserProfile(const QString &profile)
Sets the active profile in the manager.
bool profileExists(const QString &name) const
Check if a profile exists.
QgsUserProfile * userProfile()
The currently active user profile.
void setDefaultProfileName(const QString &name)
Sets the default profile name.
QString rootLocation()
Returns the path to the root profiles location.
void setDefaultFromActive()
Set the default profile name from the current active profile.
QStringList allProfiles() const
Returns a list of all found profile names.
bool rootLocationIsSet() const
Check if the root location has been set for the manager.
QgsError deleteProfile(const QString &name)
Deletes a profile from the root profiles folder.
static QString resolveProfilesFolder(const QString &basePath=QString())
Resolves the profiles folder for the given path.
void setNewProfileNotificationEnabled(bool enabled)
Sets whether the manager should watch for the creation of new user profiles and emit the profilesChan...
QString defaultProfileName() const
Returns the name of the default profile that has been set in .default.
QgsUserProfileManager(const QString &rootLocation=QString(), QObject *parent=nullptr)
User profile manager used to manage user profiles for the instance of QGIS.
void profilesChanged()
Emitted when the list of profiles is changed.
QgsUserProfile * profileForName(const QString &name) const
Returns the profile found for a given name.
void loadUserProfile(const QString &name)
Starts a new instance of QGIS for the given profile.
bool isNewProfileNotificationEnabled() const
Returns whether the manager is watching for the creation of new user profiles and emitting the profil...
User profile contains information about the user profile folders on the machine.
void initSettings() const
Init the settings from the user folder.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38