Skip to content

Commit 4e5c08e

Browse files
committedMar 9, 2018
[FEATURE] Allow overwriting the project home path
This allows the project home path (which is used by the browser to create the 'Project Home' item) to be set by users for a project, instead of always matching the location where the project is saved. This allows users to set the project home to a folder which contains data and other content, and is especially useful for organisations where qgis projects are not stored in the root folder of a organisational 'project'. Project home paths can also be set to relative paths, in which case they will be relative to the project saved location. The path can be set through the Project Properties dialog, or by right-clicking on the Project Home browser item and selecting 'set project home' Sponsored by SMEC/SJ
1 parent d09a34c commit 4e5c08e

File tree

9 files changed

+377
-70
lines changed

9 files changed

+377
-70
lines changed
 

‎python/core/qgsproject.sip.in

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -442,9 +442,34 @@ Sets the default area measurement units for the project.
442442

443443
QString homePath() const;
444444
%Docstring
445-
Return project's home path
445+
Returns the project's home path. This will either be a manually set home path
446+
(see presetHomePath()) or the path containing the project file itself.
446447

447-
:return: home path of project (or null QString if not set) *
448+
This method always returns the absolute path to the project's home. See
449+
presetHomePath() to retrieve any manual project home path override (e.g.
450+
relative home paths).
451+
452+
.. seealso:: :py:func:`setPresetHomePath`
453+
454+
.. seealso:: :py:func:`presetHomePath`
455+
456+
.. seealso:: :py:func:`homePathChanged`
457+
%End
458+
459+
QString presetHomePath() const;
460+
%Docstring
461+
Returns any manual project home path setting, or an empty string if not set.
462+
463+
This path may be a relative path. See homePath() to retrieve a path which is always
464+
an absolute path.
465+
466+
.. seealso:: :py:func:`homePath`
467+
468+
.. seealso:: :py:func:`setPresetHomePath`
469+
470+
.. seealso:: :py:func:`homePathChanged`
471+
472+
.. versionadded:: 3.2
448473
%End
449474

450475
QgsRelationManager *relationManager() const;
@@ -937,7 +962,13 @@ Emitted when the file name of the project changes
937962

938963
void homePathChanged();
939964
%Docstring
940-
Emitted when the home path of the project changes
965+
Emitted when the home path of the project changes.
966+
967+
.. seealso:: :py:func:`setPresetHomePath`
968+
969+
.. seealso:: :py:func:`homePath`
970+
971+
.. seealso:: :py:func:`presetHomePath`
941972
%End
942973

943974
void snappingConfigChanged( const QgsSnappingConfig &config );
@@ -1170,6 +1201,20 @@ be asked to save changes to the project before closing the current project.
11701201
promoted to public slot in 2.16
11711202
%End
11721203

1204+
void setPresetHomePath( const QString &path );
1205+
%Docstring
1206+
Sets the project's home ``path``. If an empty path is specified than the
1207+
home path will be automatically determined from the project's file path.
1208+
1209+
.. versionadded:: 3.2
1210+
1211+
.. seealso:: :py:func:`presetHomePath`
1212+
1213+
.. seealso:: :py:func:`homePath`
1214+
1215+
.. seealso:: :py:func:`homePathChanged`
1216+
%End
1217+
11731218
};
11741219

11751220

‎src/app/qgsprojectproperties.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,41 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas *mapCanvas, QWidget *pa
204204
mAutoTransaction->setChecked( QgsProject::instance()->autoTransaction() );
205205
title( QgsProject::instance()->title() );
206206
mProjectFileLineEdit->setText( QDir::toNativeSeparators( QgsProject::instance()->fileName() ) );
207+
mProjectHomeLineEdit->setShowClearButton( true );
208+
mProjectHomeLineEdit->setText( QDir::toNativeSeparators( QgsProject::instance()->presetHomePath() ) );
209+
connect( mButtonSetProjectHome, &QToolButton::clicked, this, [ = ]
210+
{
211+
auto getAbsoluteHome = [this]()->QString
212+
{
213+
QString currentHome = QDir::fromNativeSeparators( mProjectHomeLineEdit->text() );
214+
if ( !currentHome.isEmpty() )
215+
{
216+
QFileInfo homeInfo( currentHome );
217+
if ( !homeInfo.isRelative() )
218+
return currentHome;
219+
}
220+
221+
QFileInfo pfi( QgsProject::instance()->fileName() );
222+
if ( !pfi.exists() )
223+
return QDir::homePath();
224+
225+
if ( !currentHome.isEmpty() )
226+
{
227+
// path is relative to project file
228+
return QDir::cleanPath( pfi.path() + '/' + currentHome );
229+
}
230+
else
231+
{
232+
return pfi.canonicalPath();
233+
}
234+
};
235+
236+
QString newDir = QFileDialog::getExistingDirectory( this, tr( "Select Project Home Path" ), getAbsoluteHome() );
237+
if ( ! newDir.isNull() )
238+
{
239+
mProjectHomeLineEdit->setText( QDir::toNativeSeparators( newDir ) );
240+
}
241+
} );
207242

208243
connect( mButtonOpenProjectFolder, &QToolButton::clicked, this, [ = ]
209244
{
@@ -833,6 +868,7 @@ void QgsProjectProperties::apply()
833868

834869
// Set the project title
835870
QgsProject::instance()->setTitle( title() );
871+
QgsProject::instance()->setPresetHomePath( QDir::fromNativeSeparators( mProjectHomeLineEdit->text() ) );
836872
QgsProject::instance()->setAutoTransaction( mAutoTransaction->isChecked() );
837873
QgsProject::instance()->setEvaluateDefaultValues( mEvaluateDefaultValues->isChecked() );
838874
QgsProject::instance()->setTrustLayerMetadata( mTrustProjectCheckBox->isChecked() );

‎src/core/qgsbrowsermodel.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,8 @@ void QgsBrowserModel::initialize()
177177
if ( ! mInitialized )
178178
{
179179
connect( QgsProject::instance(), &QgsProject::readProject, this, &QgsBrowserModel::updateProjectHome );
180-
connect( QgsProject::instance(), &QgsProject::writeProject, this, &QgsBrowserModel::updateProjectHome );
180+
connect( QgsProject::instance(), &QgsProject::projectSaved, this, &QgsBrowserModel::updateProjectHome );
181+
connect( QgsProject::instance(), &QgsProject::homePathChanged, this, &QgsBrowserModel::updateProjectHome );
181182
addRootItems();
182183
mInitialized = true;
183184
}

‎src/core/qgsdataitem.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <QVector>
2929
#include <QStyle>
3030
#include <QDesktopServices>
31+
#include <QFileDialog>
3132

3233
#include "qgis.h"
3334
#include "qgsdataitem.h"
@@ -40,6 +41,7 @@
4041
#include "qgsconfig.h"
4142
#include "qgssettings.h"
4243
#include "qgsanimatedicon.h"
44+
#include "qgsproject.h"
4345

4446
// use GDAL VSI mechanism
4547
#define CPL_SUPRESS_CPLUSPLUS //#spellok
@@ -1614,6 +1616,28 @@ QVariant QgsProjectHomeItem::sortKey() const
16141616
return QStringLiteral( " 1" );
16151617
}
16161618

1619+
QList<QAction *> QgsProjectHomeItem::actions( QWidget *parent )
1620+
{
1621+
QList<QAction *> lst = QgsDirectoryItem::actions( parent );
1622+
QAction *separator = new QAction( parent );
1623+
separator->setSeparator( true );
1624+
lst.append( separator );
1625+
1626+
QAction *setHome = new QAction( tr( "Set Project Home…" ), parent );
1627+
connect( setHome, &QAction::triggered, this, [ = ]
1628+
{
1629+
QString oldHome = QgsProject::instance()->homePath();
1630+
QString newPath = QFileDialog::getExistingDirectory( parent, tr( "Select Project Home Directory" ), oldHome );
1631+
if ( !newPath.isEmpty() )
1632+
{
1633+
QgsProject::instance()->setPresetHomePath( newPath );
1634+
}
1635+
} );
1636+
lst << setHome;
1637+
1638+
return lst;
1639+
}
1640+
16171641
QgsFavoriteItem::QgsFavoriteItem( QgsFavoritesItem *parent, const QString &name, const QString &dirPath, const QString &path )
16181642
: QgsDirectoryItem( parent, name, dirPath, path )
16191643
, mFavorites( parent )

‎src/core/qgsdataitem.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,9 @@ class CORE_EXPORT QgsProjectHomeItem : public QgsDirectoryItem
745745
QIcon icon() override;
746746
QVariant sortKey() const override;
747747

748+
QList<QAction *> actions( QWidget *parent ) override;
749+
750+
748751
};
749752

750753
/**

‎src/core/qgsproject.cpp

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,17 @@ void QgsProject::setDirty( bool b )
417417
emit isDirtyChanged( mDirty );
418418
}
419419

420+
void QgsProject::setPresetHomePath( const QString &path )
421+
{
422+
if ( path == mHomePath )
423+
return;
424+
425+
mHomePath = path;
426+
emit homePathChanged();
427+
428+
setDirty( true );
429+
}
430+
420431
void QgsProject::setFileName( const QString &name )
421432
{
422433
if ( name == mFile.fileName() )
@@ -488,6 +499,7 @@ void QgsProject::clear()
488499
mFile.setFileName( QString() );
489500
mProperties.clearKeys();
490501
mTitle.clear();
502+
mHomePath.clear();
491503
mAutoTransaction = false;
492504
mEvaluateDefaultValues = false;
493505
mDirty = false;
@@ -895,6 +907,19 @@ bool QgsProject::readProjectFile( const QString &filename )
895907
// now get project title
896908
_getTitle( *doc, mTitle );
897909

910+
QDomNodeList homePathNl = doc->elementsByTagName( QStringLiteral( "homePath" ) );
911+
if ( homePathNl.count() > 0 )
912+
{
913+
QDomElement homePathElement = homePathNl.at( 0 ).toElement();
914+
QString homePath = homePathElement.attribute( QStringLiteral( "path" ) );
915+
if ( !homePath.isEmpty() )
916+
setPresetHomePath( homePath );
917+
}
918+
else
919+
{
920+
emit homePathChanged();
921+
}
922+
898923
QgsReadWriteContext context;
899924
context.setPathResolver( pathResolver() );
900925

@@ -1370,6 +1395,10 @@ bool QgsProject::writeProjectFile( const QString &filename )
13701395

13711396
doc->appendChild( qgisNode );
13721397

1398+
QDomElement homePathNode = doc->createElement( QStringLiteral( "homePath" ) );
1399+
homePathNode.setAttribute( QStringLiteral( "path" ), mHomePath );
1400+
qgisNode.appendChild( homePathNode );
1401+
13731402
// title
13741403
QDomElement titleNode = doc->createElement( QStringLiteral( "title" ) );
13751404
qgisNode.appendChild( titleNode );
@@ -2077,11 +2106,31 @@ void QgsProject::setAreaUnits( QgsUnitTypes::AreaUnit unit )
20772106

20782107
QString QgsProject::homePath() const
20792108
{
2109+
if ( !mHomePath.isEmpty() )
2110+
{
2111+
QFileInfo homeInfo( mHomePath );
2112+
if ( !homeInfo.isRelative() )
2113+
return mHomePath;
2114+
}
2115+
20802116
QFileInfo pfi( fileName() );
20812117
if ( !pfi.exists() )
2082-
return QString();
2118+
return mHomePath;
20832119

2084-
return pfi.canonicalPath();
2120+
if ( !mHomePath.isEmpty() )
2121+
{
2122+
// path is relative to project file
2123+
return QDir::cleanPath( pfi.path() + '/' + mHomePath );
2124+
}
2125+
else
2126+
{
2127+
return pfi.canonicalPath();
2128+
}
2129+
}
2130+
2131+
QString QgsProject::presetHomePath() const
2132+
{
2133+
return mHomePath;
20852134
}
20862135

20872136
QgsRelationManager *QgsProject::relationManager() const

‎src/core/qgsproject.h

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
8585
Q_OBJECT
8686
Q_PROPERTY( QStringList nonIdentifiableLayers READ nonIdentifiableLayers WRITE setNonIdentifiableLayers NOTIFY nonIdentifiableLayersChanged )
8787
Q_PROPERTY( QString fileName READ fileName WRITE setFileName NOTIFY fileNameChanged )
88-
Q_PROPERTY( QString homePath READ homePath NOTIFY homePathChanged )
88+
Q_PROPERTY( QString homePath READ homePath WRITE setPresetHomePath NOTIFY homePathChanged )
8989
Q_PROPERTY( QgsCoordinateReferenceSystem crs READ crs WRITE setCrs NOTIFY crsChanged )
9090
Q_PROPERTY( QString ellipsoid READ ellipsoid WRITE setEllipsoid NOTIFY ellipsoidChanged )
9191
Q_PROPERTY( QgsMapThemeCollection *mapThemeCollection READ mapThemeCollection NOTIFY mapThemeCollectionChanged )
@@ -423,10 +423,33 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
423423
void setAreaUnits( QgsUnitTypes::AreaUnit unit );
424424

425425
/**
426-
* Return project's home path
427-
\returns home path of project (or null QString if not set) */
426+
* Returns the project's home path. This will either be a manually set home path
427+
* (see presetHomePath()) or the path containing the project file itself.
428+
*
429+
* This method always returns the absolute path to the project's home. See
430+
* presetHomePath() to retrieve any manual project home path override (e.g.
431+
* relative home paths).
432+
*
433+
* \see setPresetHomePath()
434+
* \see presetHomePath()
435+
* \see homePathChanged()
436+
*/
428437
QString homePath() const;
429438

439+
/**
440+
* Returns any manual project home path setting, or an empty string if not set.
441+
*
442+
* This path may be a relative path. See homePath() to retrieve a path which is always
443+
* an absolute path.
444+
*
445+
* \see homePath()
446+
* \see setPresetHomePath()
447+
* \see homePathChanged()
448+
*
449+
* \since QGIS 3.2
450+
*/
451+
QString presetHomePath() const;
452+
430453
QgsRelationManager *relationManager() const;
431454

432455
/**
@@ -905,7 +928,12 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
905928
//! Emitted when the file name of the project changes
906929
void fileNameChanged();
907930

908-
//! Emitted when the home path of the project changes
931+
/**
932+
* Emitted when the home path of the project changes.
933+
* \see setPresetHomePath()
934+
* \see homePath()
935+
* \see presetHomePath()
936+
*/
909937
void homePathChanged();
910938

911939
//! emitted whenever the configuration for snapping has changed
@@ -1117,6 +1145,16 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
11171145
*/
11181146
void setDirty( bool b = true );
11191147

1148+
/**
1149+
* Sets the project's home \a path. If an empty path is specified than the
1150+
* home path will be automatically determined from the project's file path.
1151+
* \since QGIS 3.2
1152+
* \see presetHomePath()
1153+
* \see homePath()
1154+
* \see homePathChanged()
1155+
*/
1156+
void setPresetHomePath( const QString &path );
1157+
11201158
private slots:
11211159
void onMapLayersAdded( const QList<QgsMapLayer *> &layers );
11221160
void onMapLayersRemoved( const QList<QgsMapLayer *> &layers );
@@ -1212,6 +1250,12 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
12121250
std::unique_ptr<QgsAuxiliaryStorage> mAuxiliaryStorage;
12131251

12141252
QFile mFile; // current physical project file
1253+
1254+
/**
1255+
* Manual override for project home path - if empty, home path is automatically
1256+
* created based on file name.
1257+
*/
1258+
QString mHomePath;
12151259
mutable QgsProjectPropertyKey mProperties; // property hierarchy, TODO: this shouldn't be mutable
12161260
QString mTitle; // project title
12171261
bool mAutoTransaction = false; // transaction grouped editing

‎src/ui/qgsprojectpropertiesbase.ui

Lines changed: 108 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -284,11 +284,27 @@
284284
<property name="title">
285285
<string>General settings</string>
286286
</property>
287-
<property name="syncGroup">
287+
<property name="syncGroup" stdset="0">
288288
<string notr="true">projgeneral</string>
289289
</property>
290290
<layout class="QGridLayout" name="gridLayout_26">
291-
<item row="3" column="0">
291+
<item row="1" column="0">
292+
<widget class="QLabel" name="label_30">
293+
<property name="sizePolicy">
294+
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
295+
<horstretch>0</horstretch>
296+
<verstretch>0</verstretch>
297+
</sizepolicy>
298+
</property>
299+
<property name="text">
300+
<string>Project home</string>
301+
</property>
302+
<property name="buddy">
303+
<cstring>titleEdit</cstring>
304+
</property>
305+
</widget>
306+
</item>
307+
<item row="4" column="0">
292308
<widget class="QLabel" name="label_3">
293309
<property name="sizePolicy">
294310
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
@@ -304,7 +320,7 @@
304320
</property>
305321
</widget>
306322
</item>
307-
<item row="3" column="1">
323+
<item row="4" column="1">
308324
<widget class="QComboBox" name="cbxAbsolutePath">
309325
<item>
310326
<property name="text">
@@ -318,65 +334,19 @@
318334
</item>
319335
</widget>
320336
</item>
321-
<item row="0" column="0">
322-
<widget class="QLabel" name="label_4">
337+
<item row="3" column="0">
338+
<widget class="QLabel" name="textLabel1">
323339
<property name="sizePolicy">
324340
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
325341
<horstretch>0</horstretch>
326342
<verstretch>0</verstretch>
327343
</sizepolicy>
328344
</property>
329345
<property name="text">
330-
<string>Project file</string>
346+
<string>Selection color</string>
331347
</property>
332348
<property name="buddy">
333-
<cstring>titleEdit</cstring>
334-
</property>
335-
</widget>
336-
</item>
337-
<item row="1" column="0">
338-
<widget class="QLabel" name="label_2">
339-
<property name="sizePolicy">
340-
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
341-
<horstretch>0</horstretch>
342-
<verstretch>0</verstretch>
343-
</sizepolicy>
344-
</property>
345-
<property name="text">
346-
<string>Project title</string>
347-
</property>
348-
</widget>
349-
</item>
350-
<item row="3" column="2" colspan="2">
351-
<spacer>
352-
<property name="orientation">
353-
<enum>Qt::Horizontal</enum>
354-
</property>
355-
<property name="sizeHint" stdset="0">
356-
<size>
357-
<width>40</width>
358-
<height>20</height>
359-
</size>
360-
</property>
361-
</spacer>
362-
</item>
363-
<item row="4" column="0" colspan="4">
364-
<widget class="QCheckBox" name="mMapTileRenderingCheckBox">
365-
<property name="toolTip">
366-
<string>Checking this setting avoids visible edge artifacts when rendering this project as separate map tiles. Rendering performance will be degraded.</string>
367-
</property>
368-
<property name="text">
369-
<string>Avoid artifacts when project is rendered as map tiles (degrades performance)</string>
370-
</property>
371-
</widget>
372-
</item>
373-
<item row="1" column="1" colspan="3">
374-
<widget class="QLineEdit" name="titleEdit">
375-
<property name="toolTip">
376-
<string>Descriptive project name</string>
377-
</property>
378-
<property name="text">
379-
<string>Default project title</string>
349+
<cstring>pbnSelectionColor</cstring>
380350
</property>
381351
</widget>
382352
</item>
@@ -408,23 +378,56 @@
408378
</item>
409379
</layout>
410380
</item>
411-
<item row="2" column="0">
412-
<widget class="QLabel" name="textLabel1">
381+
<item row="5" column="0" colspan="4">
382+
<widget class="QCheckBox" name="mMapTileRenderingCheckBox">
383+
<property name="toolTip">
384+
<string>Checking this setting avoids visible edge artifacts when rendering this project as separate map tiles. Rendering performance will be degraded.</string>
385+
</property>
386+
<property name="text">
387+
<string>Avoid artifacts when project is rendered as map tiles (degrades performance)</string>
388+
</property>
389+
</widget>
390+
</item>
391+
<item row="0" column="0">
392+
<widget class="QLabel" name="label_4">
413393
<property name="sizePolicy">
414394
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
415395
<horstretch>0</horstretch>
416396
<verstretch>0</verstretch>
417397
</sizepolicy>
418398
</property>
419399
<property name="text">
420-
<string>Selection color</string>
400+
<string>Project file</string>
421401
</property>
422402
<property name="buddy">
423-
<cstring>pbnSelectionColor</cstring>
403+
<cstring>titleEdit</cstring>
424404
</property>
425405
</widget>
426406
</item>
427407
<item row="2" column="1" colspan="3">
408+
<widget class="QLineEdit" name="titleEdit">
409+
<property name="toolTip">
410+
<string>Descriptive project name</string>
411+
</property>
412+
<property name="text">
413+
<string>Default project title</string>
414+
</property>
415+
</widget>
416+
</item>
417+
<item row="2" column="0">
418+
<widget class="QLabel" name="label_2">
419+
<property name="sizePolicy">
420+
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
421+
<horstretch>0</horstretch>
422+
<verstretch>0</verstretch>
423+
</sizepolicy>
424+
</property>
425+
<property name="text">
426+
<string>Project title</string>
427+
</property>
428+
</widget>
429+
</item>
430+
<item row="3" column="1" colspan="3">
428431
<layout class="QHBoxLayout" name="horizontalLayout_5">
429432
<item>
430433
<widget class="QgsColorButton" name="pbnSelectionColor">
@@ -495,6 +498,49 @@
495498
</item>
496499
</layout>
497500
</item>
501+
<item row="4" column="2" colspan="2">
502+
<spacer>
503+
<property name="orientation">
504+
<enum>Qt::Horizontal</enum>
505+
</property>
506+
<property name="sizeHint" stdset="0">
507+
<size>
508+
<width>40</width>
509+
<height>20</height>
510+
</size>
511+
</property>
512+
</spacer>
513+
</item>
514+
<item row="1" column="1" colspan="3">
515+
<layout class="QHBoxLayout" name="horizontalLayout_14">
516+
<item>
517+
<widget class="QgsFilterLineEdit" name="mProjectHomeLineEdit">
518+
<property name="toolTip">
519+
<string>Project home path. Leave blank to use the current project file location.</string>
520+
</property>
521+
<property name="readOnly">
522+
<bool>false</bool>
523+
</property>
524+
<property name="clearButtonEnabled">
525+
<bool>false</bool>
526+
</property>
527+
</widget>
528+
</item>
529+
<item>
530+
<widget class="QToolButton" name="mButtonSetProjectHome">
531+
<property name="toolTip">
532+
<string>Set the project home path</string>
533+
</property>
534+
<property name="text">
535+
<string>…</string>
536+
</property>
537+
<property name="autoRaise">
538+
<bool>false</bool>
539+
</property>
540+
</widget>
541+
</item>
542+
</layout>
543+
</item>
498544
</layout>
499545
</widget>
500546
</item>
@@ -503,7 +549,7 @@
503549
<property name="title">
504550
<string>Measurements</string>
505551
</property>
506-
<property name="syncGroup">
552+
<property name="syncGroup" stdset="0">
507553
<string notr="true">projgeneral</string>
508554
</property>
509555
<layout class="QGridLayout" name="gridLayoutMeasureTool">
@@ -572,7 +618,7 @@
572618
<property name="title">
573619
<string>Coordinate display</string>
574620
</property>
575-
<property name="syncGroup">
621+
<property name="syncGroup" stdset="0">
576622
<string notr="true">projgeneral</string>
577623
</property>
578624
<layout class="QGridLayout" name="gridLayout_18">
@@ -662,7 +708,7 @@
662708
<property name="checked">
663709
<bool>false</bool>
664710
</property>
665-
<property name="syncGroup">
711+
<property name="syncGroup" stdset="0">
666712
<string notr="true">projgeneral</string>
667713
</property>
668714
<layout class="QGridLayout" name="gridLayout_7">
@@ -2710,6 +2756,8 @@
27102756
<tabstop>scrollArea_2</tabstop>
27112757
<tabstop>mProjectFileLineEdit</tabstop>
27122758
<tabstop>mButtonOpenProjectFolder</tabstop>
2759+
<tabstop>mProjectHomeLineEdit</tabstop>
2760+
<tabstop>mButtonSetProjectHome</tabstop>
27132761
<tabstop>titleEdit</tabstop>
27142762
<tabstop>pbnSelectionColor</tabstop>
27152763
<tabstop>pbnCanvasColor</tabstop>

‎tests/src/python/test_qgsproject.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,63 @@ def testSymbolicLinkInProjectPath(self):
857857
self.assertTrue('source="./points.shp"' in content)
858858
self.assertTrue('source="./landsat_4326.tif"' in content)
859859

860+
def testHomePath(self):
861+
p = QgsProject()
862+
path_changed_spy = QSignalSpy(p.homePathChanged)
863+
self.assertFalse(p.homePath())
864+
self.assertFalse(p.presetHomePath())
865+
866+
# simulate save file
867+
tmp_dir = QTemporaryDir()
868+
tmp_file = "{}/project.qgs".format(tmp_dir.path())
869+
with open(tmp_file, 'w') as f:
870+
pass
871+
p.setFileName(tmp_file)
872+
873+
# home path should be file path
874+
self.assertEqual(p.homePath(), tmp_dir.path())
875+
self.assertFalse(p.presetHomePath())
876+
self.assertEqual(len(path_changed_spy), 1)
877+
878+
# manually override home path
879+
p.setPresetHomePath('/tmp/my_path')
880+
self.assertEqual(p.homePath(), '/tmp/my_path')
881+
self.assertEqual(p.presetHomePath(), '/tmp/my_path')
882+
self.assertEqual(len(path_changed_spy), 2)
883+
884+
# no extra signal if path is unchanged
885+
p.setPresetHomePath('/tmp/my_path')
886+
self.assertEqual(p.homePath(), '/tmp/my_path')
887+
self.assertEqual(p.presetHomePath(), '/tmp/my_path')
888+
self.assertEqual(len(path_changed_spy), 2)
889+
890+
# setting file name should not affect home path is manually set
891+
tmp_file_2 = "{}/project/project2.qgs".format(tmp_dir.path())
892+
os.mkdir(tmp_dir.path() + '/project')
893+
with open(tmp_file_2, 'w') as f:
894+
pass
895+
p.setFileName(tmp_file_2)
896+
self.assertEqual(p.homePath(), '/tmp/my_path')
897+
self.assertEqual(p.presetHomePath(), '/tmp/my_path')
898+
self.assertEqual(len(path_changed_spy), 2)
899+
900+
# clear manual path
901+
p.setPresetHomePath('')
902+
self.assertEqual(p.homePath(), tmp_dir.path() + '/project')
903+
self.assertFalse(p.presetHomePath())
904+
self.assertEqual(len(path_changed_spy), 3)
905+
906+
# relative path
907+
p.setPresetHomePath('../home')
908+
self.assertEqual(p.homePath(), tmp_dir.path() + '/home')
909+
self.assertEqual(p.presetHomePath(), '../home')
910+
self.assertEqual(len(path_changed_spy), 4)
911+
912+
# relative path, no filename
913+
p.setFileName('')
914+
self.assertEqual(p.homePath(), '../home')
915+
self.assertEqual(p.presetHomePath(), '../home')
916+
860917

861918
if __name__ == '__main__':
862919
unittest.main()

0 commit comments

Comments
 (0)
Please sign in to comment.