QGIS API Documentation 4.1.0-Master (376402f9aeb)
Loading...
Searching...
No Matches
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
17
18#include <memory>
19
20#include "qgsapplication.h"
21#include "qgslogger.h"
23#include "qgssettingstree.h"
24#include "qgsuserprofile.h"
25
26#include <QDir>
27#include <QFile>
28#include <QProcess>
29#include <QStandardPaths>
30#include <QString>
31#include <QTextStream>
32
33#include "moc_qgsuserprofilemanager.cpp"
34
35using namespace Qt::StringLiterals;
36
38 = new QgsSettingsEntryBool( u"override-local"_s, QgsSettingsTree::sTreeProfile, false, u"If true, QGIS always starts with the profile defined by \"default\", overriding any user-specific selection."_s );
40 = new QgsSettingsEntryString( u"default"_s, QgsSettingsTree::sTreeProfile, u"default"_s, u"Name of the user profile loaded by default on QGIS startup."_s );
41
43 : QObject( parent )
44{
46}
47
48QString QgsUserProfileManager::resolveProfilesFolder( const QString &basePath )
49{
50 return basePath + QDir::separator() + "profiles";
51}
52
53std::unique_ptr< QgsUserProfile > QgsUserProfileManager::getProfile( const QString &defaultProfile, bool createNew, bool initSettings )
54{
55 const QString profileName = defaultProfile.isEmpty() ? defaultProfileName() : defaultProfile;
56
57 if ( createNew && !profileExists( defaultProfile ) )
58 {
59 createUserProfile( profileName );
60 }
61
62 std::unique_ptr< QgsUserProfile > profile = profileForName( profileName );
63 if ( initSettings )
64 profile->initSettings();
65
66 return profile;
67}
68
69void QgsUserProfileManager::setRootLocation( const QString &rootProfileLocation )
70{
71 mRootProfilePath = rootProfileLocation;
72
73 //updates (or removes) profile file watcher for new root location
74 setNewProfileNotificationEnabled( mWatchProfiles );
75
76 mSettings = std::make_unique<QSettings>( settingsFile(), QSettings::IniFormat );
77}
78
80{
81 mWatchProfiles = enabled;
82 if ( mWatchProfiles && !mRootProfilePath.isEmpty() && QDir( mRootProfilePath ).exists() )
83 {
84 mWatcher = std::make_unique<QFileSystemWatcher>();
85 mWatcher->addPath( mRootProfilePath );
86 connect( mWatcher.get(), &QFileSystemWatcher::directoryChanged, this, [this] { emit profilesChanged(); } );
87 }
88 else
89 {
90 mWatcher.reset();
91 }
92}
93
95{
96 return static_cast< bool >( mWatcher.get() );
97}
98
100{
101 return !mRootProfilePath.isEmpty();
102}
103
105{
106 const QString defaultName = u"default"_s;
107 // If the profiles.ini doesn't have the default profile we grab it from
108 // global settings as it might be set by the admin.
109 // If the overrideProfile flag is set then no matter what the profiles.ini says we always take the
110 // global profile.
111 if ( !mSettings->contains( u"/core/defaultProfile"_s ) || settingsOverrideLocalProfile->value() )
112 {
113 return settingsDefaultProfile->value();
114 }
115 return mSettings->value( u"/core/defaultProfile"_s, defaultName ).toString();
116}
117
119{
120 mSettings->setValue( u"/core/defaultProfile"_s, name );
121 mSettings->sync();
122}
123
128
130{
131 return mSettings->value( u"/core/lastProfile"_s, QString() ).toString();
132}
133
135{
136 mSettings->setValue( u"/core/lastProfile"_s, userProfile()->name() );
137 mSettings->sync();
138}
139
141{
142 return static_cast< Qgis::UserProfileSelectionPolicy >( mSettings->value( u"/core/selectionPolicy"_s, 0 ).toInt() );
143}
144
146{
147 mSettings->setValue( u"/core/selectionPolicy"_s, static_cast< int >( policy ) );
148 mSettings->sync();
149}
150
152{
153 return QDir( mRootProfilePath ).entryList( QDir::Dirs | QDir::NoDotAndDotDot );
154}
155
156bool QgsUserProfileManager::profileExists( const QString &name ) const
157{
158 return allProfiles().contains( name );
159}
160
161std::unique_ptr< QgsUserProfile > QgsUserProfileManager::profileForName( const QString &name ) const
162{
163 const QString profilePath = mRootProfilePath + QDir::separator() + name;
164 return std::make_unique< QgsUserProfile >( profilePath );
165}
166
168{
169 QgsError error;
170
171 // TODO Replace with safe folder name
172
173 const QDir folder( mRootProfilePath + QDir::separator() + name );
174 if ( !folder.exists() )
175 {
176 if ( !QDir().mkpath( folder.absolutePath() ) )
177 {
178 error.append( tr( "Cannot write '%1'" ).arg( folder.absolutePath() ) );
179 return error;
180 }
181 }
182
183 QFile qgisPrivateDbFile( folder.absolutePath() + QDir::separator() + "qgis.db" );
184
185 // first we look for ~/.qgis/qgis.db
186 if ( !qgisPrivateDbFile.exists() )
187 {
188 // if it doesn't exist we copy it from the global resources dir
189 const QString qgisMasterDbFileName = QgsApplication::qgisMasterDatabaseFilePath();
190 QFile masterFile( qgisMasterDbFileName );
191
192 //now copy the master file into the users .qgis dir
193 if ( !masterFile.copy( qgisPrivateDbFile.fileName() ) )
194 {
195 error.append( tr( "Could not copy master database to %1" ).arg( qgisPrivateDbFile.fileName() ) );
196 }
197 else
198 {
199 // In some packaging systems, the master can be read-only. Make sure to make
200 // the copy user writable.
201 const QFile::Permissions perms = QFile( qgisPrivateDbFile.fileName() ).permissions();
202 if ( !( perms & QFile::WriteOwner ) )
203 {
204 if ( !qgisPrivateDbFile.setPermissions( perms | QFile::WriteOwner ) )
205 {
206 error.append( tr( "Can not make '%1' user writable" ).arg( qgisPrivateDbFile.fileName() ) );
207 }
208 }
209 }
210 }
211
212 if ( error.isEmpty() )
213 {
214 emit profilesChanged();
215 }
216
217 return error;
218}
219
221{
222 QgsError error;
223 QDir folder( mRootProfilePath + QDir::separator() + name );
224
225 // This might have to be changed to something better.
226 const bool deleted = folder.removeRecursively();
227 if ( !deleted )
228 {
229 error.append( ( tr( "Unable to fully delete user profile folder" ) ) );
230 }
231 else
232 {
233 emit profilesChanged();
234 }
235 return error;
236}
237
238QString QgsUserProfileManager::settingsFile() const
239{
240 return mRootProfilePath + QDir::separator() + "profiles.ini";
241}
242
244{
245 return mSettings.get();
246}
247
249{
250 return mUserProfile.get();
251}
252
253void QgsUserProfileManager::loadUserProfile( const QString &name )
254{
255#if QT_CONFIG( process )
256 const QString path = QDir::toNativeSeparators( QCoreApplication::applicationFilePath() );
257 QStringList arguments;
258 arguments << QCoreApplication::arguments();
259 // The first is the path to the application
260 // on Windows this might not be case so we need to handle that
261 // http://doc.qt.io/qt-5/qcoreapplication.html#arguments
262 arguments.removeFirst();
263 arguments << u"--profile"_s << name;
264 QgsDebugMsgLevel( u"Starting instance from %1 with %2"_s.arg( path ).arg( arguments.join( " " ) ), 2 );
265 QProcess::startDetached( path, arguments, QDir::toNativeSeparators( QCoreApplication::applicationDirPath() ) );
266#else
267 Q_UNUSED( name )
268 Q_ASSERT( "Starting the user profile is not supported on the platform" );
269#endif //QT_CONFIG(process)
270}
271
273{
274 if ( !mUserProfile )
275 {
276 mUserProfile = profileForName( profile );
277 }
278}
UserProfileSelectionPolicy
User profile selection policy.
Definition qgis.h:5948
static QString qgisMasterDatabaseFilePath()
Returns the path to the master qgis.db file.
A container for error messages.
Definition qgserror.h:83
bool isEmpty() const
Test if no error is set.
Definition qgserror.h:111
void append(const QString &message, const QString &tag)
Append new error message.
Definition qgserror.cpp:42
A boolean settings entry.
A string settings entry.
static QgsSettingsTreeNode * sTreeProfile
std::unique_ptr< QgsUserProfile > profileForName(const QString &name) const
Returns the profile found for a given name.
std::unique_ptr< 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.
static const QgsSettingsEntryString * settingsDefaultProfile
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.
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.
QSettings * settings()
Returns the settings for the profile manager.
static QString resolveProfilesFolder(const QString &basePath=QString())
Resolves the profiles folder for the given path.
void setUserProfileSelectionPolicy(Qgis::UserProfileSelectionPolicy policy)
Sets the user profile selection policy.
static const QgsSettingsEntryBool * settingsOverrideLocalProfile
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.
Qgis::UserProfileSelectionPolicy userProfileSelectionPolicy() const
Returns the user profile selection policy.
void profilesChanged()
Emitted when the list of profiles is changed.
QString lastProfileName() const
Returns the name of the most recently closed profile.
void updateLastProfileName()
Updates the last closed profile name.
QString rootLocation() const
Returns the path to the root profiles location.
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.
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63