Skip to content

Commit 91f3005

Browse files
committed
[FEATURE] Expression variables relating to QGIS environment
New variables for: - @qgis_os_name: eg 'linux','windows' or 'osx' - @qgis_platform: eg 'desktop' or 'server' - @user_account_name: current user's operating system account name - @user_full_name: current user's name from os account (if available) Sponsored by Andreas Neumann
1 parent 5f3ca88 commit 91f3005

8 files changed

+206
-5
lines changed

python/core/qgsapplication.sip

+25-1
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,33 @@ static void qtgui_UpdatePyArgv(PyObject *argvlist, int argc, char **argv)
228228
//! Returns the path to user's style.
229229
static QString userStyleV2Path();
230230

231-
//! Returns the short name regular exprecience for line edit validator
231+
//! Returns the short name regular expression for line edit validator
232232
static QRegExp shortNameRegExp();
233233

234+
/** Returns the user's operating system login account name.
235+
* @note added in QGIS 2.14
236+
* @see userFullName()
237+
*/
238+
static QString userLoginName();
239+
240+
/** Returns the user's operating system login account full display name.
241+
* @note added in QGIS 2.14
242+
* @see userLoginName()
243+
*/
244+
static QString userFullName();
245+
246+
/** Returns a string name of the operating system QGIS is running on.
247+
* @note added in QGIS 2.14
248+
* @see platform()
249+
*/
250+
static QString osName();
251+
252+
/** Returns the QGIS platform name, eg "desktop" or "server".
253+
* @note added in QGIS 2.14
254+
* @see osName()
255+
*/
256+
static QString platform();
257+
234258
//! Returns the path to user's themes folder
235259
static QString userThemesFolder();
236260

src/core/qgsapplication.cpp

+100-1
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,14 @@
3939

4040
#ifndef Q_OS_WIN
4141
#include <netinet/in.h>
42+
#include <pwd.h>
4243
#else
4344
#include <winsock.h>
45+
#include <windows.h>
46+
#include <Lmcons.h>
47+
#define SECURITY_WIN32
48+
#include <Security.h>
49+
#pragma comment( lib, "Secur32.lib" )
4450
#endif
4551

4652
#include "qgsconfig.h"
@@ -72,6 +78,10 @@ QStringList ABISYM( QgsApplication::mGdalSkipList );
7278
int ABISYM( QgsApplication::mMaxThreads );
7379
QString ABISYM( QgsApplication::mAuthDbDirPath );
7480

81+
QString QgsApplication::sUserName;
82+
QString QgsApplication::sUserFullName;
83+
QString QgsApplication::sPlatformName = "desktop";
84+
7585
const char* QgsApplication::QGIS_ORGANIZATION_NAME = "QGIS";
7686
const char* QgsApplication::QGIS_ORGANIZATION_DOMAIN = "qgis.org";
7787
const char* QgsApplication::QGIS_APPLICATION_NAME = "QGIS2";
@@ -89,9 +99,11 @@ const char* QgsApplication::QGIS_APPLICATION_NAME = "QGIS2";
8999
so that platform-conditional code is minimized and paths are easier
90100
to change due to centralization.
91101
*/
92-
QgsApplication::QgsApplication( int & argc, char ** argv, bool GUIenabled, const QString& customConfigPath )
102+
QgsApplication::QgsApplication( int & argc, char ** argv, bool GUIenabled, const QString& customConfigPath, const QString& platformName )
93103
: QApplication( argc, argv, GUIenabled )
94104
{
105+
sPlatformName = platformName;
106+
95107
init( customConfigPath ); // init can also be called directly by e.g. unit tests that don't inherit QApplication.
96108
}
97109

@@ -722,6 +734,93 @@ QRegExp QgsApplication::shortNameRegExp()
722734
return QRegExp( "^[A-Za-z][A-Za-z0-9\\._-]*" );
723735
}
724736

737+
QString QgsApplication::userLoginName()
738+
{
739+
if ( !sUserName.isEmpty() )
740+
return sUserName;
741+
742+
#ifdef Q_OS_WIN
743+
TCHAR name [ UNLEN + 1 ];
744+
DWORD size = UNLEN + 1;
745+
746+
if ( GetUserName(( TCHAR* )name, &size ) )
747+
{
748+
sUserName = QString( name );
749+
}
750+
751+
#else
752+
QProcess process;
753+
754+
process.start( "whoami" );
755+
process.waitForFinished();
756+
sUserName = process.readAllStandardOutput().trimmed();
757+
#endif
758+
759+
if ( !sUserName.isEmpty() )
760+
return sUserName;
761+
762+
//backup plan - use environment variables
763+
sUserName = qgetenv( "USER" );
764+
if ( !sUserName.isEmpty() )
765+
return sUserName;
766+
767+
//last resort
768+
sUserName = qgetenv( "USERNAME" );
769+
return sUserName;
770+
}
771+
772+
QString QgsApplication::userFullName()
773+
{
774+
if ( !sUserFullName.isEmpty() )
775+
return sUserFullName;
776+
777+
#ifdef Q_OS_WIN
778+
TCHAR name [ UNLEN + 1 ];
779+
DWORD size = UNLEN + 1;
780+
781+
//note - this only works for accounts connected to domain
782+
if ( GetUserNameEx( NameDisplay, ( TCHAR* )name, &size ) )
783+
{
784+
sUserFullName = QString( name );
785+
}
786+
787+
//fall back to login name
788+
if ( sUserFullName.isEmpty() )
789+
sUserFullName = userLoginName();
790+
#else
791+
struct passwd *p = getpwuid( getuid() );
792+
793+
if ( p )
794+
{
795+
QString gecosName = QString( p->pw_gecos );
796+
sUserFullName = gecosName.left( gecosName.indexOf( ',', 0 ) );
797+
}
798+
799+
#endif
800+
801+
return sUserFullName;
802+
}
803+
804+
QString QgsApplication::osName()
805+
{
806+
#if defined(Q_OS_ANDROID)
807+
return QLatin1String( "android" );
808+
#elif defined(Q_OS_MAC)
809+
return QLatin1String( "osx" );
810+
#elif defined(Q_OS_WIN)
811+
return QLatin1String( "windows" );
812+
#elif defined(Q_OS_LINUX)
813+
return QLatin1String( "linux" );
814+
#else
815+
return QLatin1String( "unknown" );
816+
#endif
817+
}
818+
819+
QString QgsApplication::platform()
820+
{
821+
return sPlatformName;
822+
}
823+
725824
QString QgsApplication::userThemesFolder()
726825
{
727826
return qgisSettingsDirPath() + QLatin1String( "/themes" );

src/core/qgsapplication.h

+30-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class CORE_EXPORT QgsApplication : public QApplication
3838
static const char* QGIS_ORGANIZATION_NAME;
3939
static const char* QGIS_ORGANIZATION_DOMAIN;
4040
static const char* QGIS_APPLICATION_NAME;
41-
QgsApplication( int & argc, char ** argv, bool GUIenabled, const QString& customConfigPath = QString() );
41+
QgsApplication( int & argc, char ** argv, bool GUIenabled, const QString& customConfigPath = QString(), const QString& platformName = "desktop" );
4242
virtual ~QgsApplication();
4343

4444
/** This method initialises paths etc for QGIS. Called by the ctor or call it manually
@@ -190,9 +190,33 @@ class CORE_EXPORT QgsApplication : public QApplication
190190
//! Returns the path to user's style.
191191
static QString userStyleV2Path();
192192

193-
//! Returns the short name regular exprecience for line edit validator
193+
//! Returns the short name regular expression for line edit validator
194194
static QRegExp shortNameRegExp();
195195

196+
/** Returns the user's operating system login account name.
197+
* @note added in QGIS 2.14
198+
* @see userFullName()
199+
*/
200+
static QString userLoginName();
201+
202+
/** Returns the user's operating system login account full display name.
203+
* @note added in QGIS 2.14
204+
* @see userLoginName()
205+
*/
206+
static QString userFullName();
207+
208+
/** Returns a string name of the operating system QGIS is running on.
209+
* @note added in QGIS 2.14
210+
* @see platform()
211+
*/
212+
static QString osName();
213+
214+
/** Returns the QGIS platform name, eg "desktop" or "server".
215+
* @note added in QGIS 2.14
216+
* @see osName()
217+
*/
218+
static QString platform();
219+
196220
//! Returns the path to user's themes folder
197221
static QString userThemesFolder();
198222

@@ -378,6 +402,10 @@ class CORE_EXPORT QgsApplication : public QApplication
378402
/**
379403
* @note added in 2.12 */
380404
static QString ABISYM( mAuthDbDirPath );
405+
406+
static QString sUserName;
407+
static QString sUserFullName;
408+
static QString sPlatformName;
381409
};
382410

383411
#endif

src/core/qgsexpression.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -4432,6 +4432,10 @@ void QgsExpression::initVariableHelp()
44324432
gVariableHelpTexts.insert( "qgis_version", QCoreApplication::translate( "variable_help", "Current QGIS version string." ) );
44334433
gVariableHelpTexts.insert( "qgis_version_no", QCoreApplication::translate( "variable_help", "Current QGIS version number." ) );
44344434
gVariableHelpTexts.insert( "qgis_release_name", QCoreApplication::translate( "variable_help", "Current QGIS release name." ) );
4435+
gVariableHelpTexts.insert( "qgis_os_name", QCoreApplication::translate( "variable_help", "Operating system name, eg 'windows', 'linux' or 'osx'." ) );
4436+
gVariableHelpTexts.insert( "qgis_platform", QCoreApplication::translate( "variable_help", "QGIS platform, eg 'desktop' or 'server'." ) );
4437+
gVariableHelpTexts.insert( "user_account_name", QCoreApplication::translate( "variable_help", "Current user's operating system account name." ) );
4438+
gVariableHelpTexts.insert( "user_full_name", QCoreApplication::translate( "variable_help", "Current user's operating system user name (if available)." ) );
44354439

44364440
//project variables
44374441
gVariableHelpTexts.insert( "project_title", QCoreApplication::translate( "variable_help", "Title of current project." ) );

src/core/qgsexpressioncontext.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "qgscomposition.h"
2626
#include "qgscomposeritem.h"
2727
#include "qgsatlascomposition.h"
28+
#include "qgsapplication.h"
2829
#include <QSettings>
2930
#include <QDir>
3031

@@ -465,6 +466,10 @@ QgsExpressionContextScope* QgsExpressionContextUtils::globalScope()
465466
scope->addVariable( QgsExpressionContextScope::StaticVariable( "qgis_version", QGis::QGIS_VERSION, true ) );
466467
scope->addVariable( QgsExpressionContextScope::StaticVariable( "qgis_version_no", QGis::QGIS_VERSION_INT, true ) );
467468
scope->addVariable( QgsExpressionContextScope::StaticVariable( "qgis_release_name", QGis::QGIS_RELEASE_NAME, true ) );
469+
scope->addVariable( QgsExpressionContextScope::StaticVariable( "qgis_platform", QgsApplication::platform(), true ) );
470+
scope->addVariable( QgsExpressionContextScope::StaticVariable( "qgis_os_name", QgsApplication::osName(), true ) );
471+
scope->addVariable( QgsExpressionContextScope::StaticVariable( "user_account_name", QgsApplication::userLoginName(), true ) );
472+
scope->addVariable( QgsExpressionContextScope::StaticVariable( "user_full_name", QgsApplication::userFullName(), true ) );
468473

469474
return scope;
470475
}

src/server/qgsserver.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ bool QgsServer::init( int & argc, char ** argv )
330330
QSettings::setPath( QSettings::IniFormat, QSettings::UserScope, optionsPath );
331331
}
332332

333-
mQgsApplication = new QgsApplication( argc, argv, getenv( "DISPLAY" ) );
333+
mQgsApplication = new QgsApplication( argc, argv, getenv( "DISPLAY" ), QString(), "server" );
334334

335335
QCoreApplication::setOrganizationName( QgsApplication::QGIS_ORGANIZATION_NAME );
336336
QCoreApplication::setOrganizationDomain( QgsApplication::QGIS_ORGANIZATION_DOMAIN );

tests/src/core/testqgsapplication.cpp

+33
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ class TestQgsApplication: public QObject
2929
void checkGdalSkip();
3030
void initTestCase();
3131
void cleanupTestCase();
32+
33+
void accountName();
34+
void osName();
35+
void platformName();
36+
3237
private:
3338
QString getQgisPath();
3439
};
@@ -50,6 +55,34 @@ void TestQgsApplication::cleanupTestCase()
5055
QgsApplication::exitQgis();
5156
}
5257

58+
void TestQgsApplication::accountName()
59+
{
60+
QString loginName = QgsApplication::userLoginName();
61+
qDebug() << QString( "Got login name: '%1'" ).arg( loginName );
62+
QVERIFY( !loginName.isEmpty() );
63+
//test cached return works correctly
64+
QCOMPARE( loginName, QgsApplication::userLoginName() );
65+
66+
//can't test contents, as it can be validly empty (eg on Travis). Just testing that we don't crash
67+
QString fullName = QgsApplication::userFullName();
68+
qDebug() << QString( "Got full name: '%1'" ).arg( fullName );
69+
//test cached return works correctly
70+
QCOMPARE( fullName, QgsApplication::userFullName() );
71+
}
72+
73+
void TestQgsApplication::osName()
74+
{
75+
// can't test expected result, so just check for non-empty result
76+
qDebug() << QString( "Got OS name: '%1'" ).arg( QgsApplication::osName() );
77+
QVERIFY( !QgsApplication::osName().isEmpty() );
78+
}
79+
80+
void TestQgsApplication::platformName()
81+
{
82+
// test will always be run under desktop platform
83+
QCOMPARE( QgsApplication::platform(), QString( "desktop" ) );
84+
}
85+
5386
void TestQgsApplication::checkPaths()
5487
{
5588
QString myPath = QgsApplication::authorsFilePath();

tests/src/core/testqgsexpressioncontext.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -488,10 +488,18 @@ void TestQgsExpressionContext::globalScope()
488488
QgsExpression expVersion( "var('qgis_version')" );
489489
QgsExpression expVersionNo( "var('qgis_version_no')" );
490490
QgsExpression expReleaseName( "var('qgis_release_name')" );
491+
QgsExpression expAccountName( "var('user_account_name')" );
492+
QgsExpression expUserFullName( "var('user_full_name')" );
493+
QgsExpression expOsName( "var('qgis_os_name')" );
494+
QgsExpression expPlatform( "var('qgis_platform')" );
491495

492496
QCOMPARE( expVersion.evaluate( &context ).toString(), QString( QGis::QGIS_VERSION ) );
493497
QCOMPARE( expVersionNo.evaluate( &context ).toInt(), QGis::QGIS_VERSION_INT );
494498
QCOMPARE( expReleaseName.evaluate( &context ).toString(), QString( QGis::QGIS_RELEASE_NAME ) );
499+
QCOMPARE( expAccountName.evaluate( &context ).toString(), QgsApplication::userLoginName() );
500+
QCOMPARE( expUserFullName.evaluate( &context ).toString(), QgsApplication::userFullName() );
501+
QCOMPARE( expOsName.evaluate( &context ).toString(), QgsApplication::osName() );
502+
QCOMPARE( expPlatform.evaluate( &context ).toString(), QgsApplication::platform() );
495503

496504
//test setGlobalVariables
497505
QgsStringMap vars;

0 commit comments

Comments
 (0)