Skip to content

Commit

Permalink
Use the new UsersCannotToggleEditing property to refine situations
Browse files Browse the repository at this point in the history
when various actions and editing dependant states should be
reflected in qgis app

We don't want annotation layers (which are always editable) to
make things like the "cancel edits for all layers" action
to become enabled.
  • Loading branch information
nyalldawson committed Aug 18, 2021
1 parent 3b2e640 commit 1925277
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 15 deletions.
8 changes: 6 additions & 2 deletions python/core/auto_generated/layertree/qgslayertreeutils.sip.in
Expand Up @@ -45,10 +45,14 @@ Convert Qt.CheckState to QString
Convert QString to Qt.CheckState
%End

static bool layersEditable( const QList<QgsLayerTreeLayer *> &layerNodes );
static bool layersEditable( const QList<QgsLayerTreeLayer *> &layerNodes, bool ignoreLayersWhichCannotBeToggled = false );
%Docstring
Returns ``True`` if any of the layers is editable
Returns ``True`` if any of the specified layers is editable.

The ``ignoreLayersWhichCannotBeToggled`` argument can be used to control whether layers which cannot have their
edit states toggled by users should be ignored or not (since QGIS 3.22).
%End

static bool layersModified( const QList<QgsLayerTreeLayer *> &layerNodes );
%Docstring
Returns ``True`` if any of the layers is modified
Expand Down
15 changes: 7 additions & 8 deletions src/app/qgisapp.cpp
Expand Up @@ -11468,7 +11468,7 @@ void QgisApp::saveAllEdits( bool verifyAction )
return;
}

const auto layers = editableLayers( true );
const auto layers = editableLayers( true, true );
for ( QgsMapLayer *layer : layers )
{
saveEdits( layer, true, false );
Expand Down Expand Up @@ -11496,7 +11496,7 @@ void QgisApp::rollbackAllEdits( bool verifyAction )
return;
}

const auto layers = editableLayers( true );
const auto layers = editableLayers( true, true );
for ( QgsMapLayer *layer : layers )
{
cancelEdits( layer, true, false );
Expand Down Expand Up @@ -11524,7 +11524,7 @@ void QgisApp::cancelAllEdits( bool verifyAction )
return;
}

const auto layers = editableLayers();
const auto layers = editableLayers( false, true );
for ( QgsMapLayer *layer : layers )
{
cancelEdits( layer, false, false );
Expand Down Expand Up @@ -11595,16 +11595,16 @@ void QgisApp::updateLayerModifiedActions()
mActionRollbackEdits->setEnabled( QgsLayerTreeUtils::layersModified( selectedLayerNodes ) );
mActionCancelEdits->setEnabled( QgsLayerTreeUtils::layersEditable( selectedLayerNodes ) );

bool hasEditLayers = !editableLayers().isEmpty();
bool hasEditLayers = !editableLayers( false, true ).isEmpty();
mActionAllEdits->setEnabled( hasEditLayers );
mActionCancelAllEdits->setEnabled( hasEditLayers );

bool hasModifiedLayers = !editableLayers( true ).isEmpty();
bool hasModifiedLayers = !editableLayers( true, true ).isEmpty();
mActionSaveAllEdits->setEnabled( hasModifiedLayers );
mActionRollbackAllEdits->setEnabled( hasModifiedLayers );
}

QList<QgsMapLayer *> QgisApp::editableLayers( bool modified ) const
QList<QgsMapLayer *> QgisApp::editableLayers( bool modified, bool ignoreLayersWhichCannotBeToggled ) const
{
QList<QgsMapLayer *> editLayers;
// use legend layers (instead of registry) so QList mirrors its order
Expand All @@ -11615,7 +11615,7 @@ QList<QgsMapLayer *> QgisApp::editableLayers( bool modified ) const
if ( !layer )
continue;

if ( layer->isEditable() && ( !modified || layer->isModified() ) )
if ( layer->isEditable() && ( !modified || layer->isModified() ) && ( !ignoreLayersWhichCannotBeToggled || !( layer->properties() & Qgis::MapLayerProperty::UsersCannotToggleEditing ) ) )
editLayers << layer;
}
return editLayers;
Expand Down Expand Up @@ -15723,7 +15723,6 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer )
updateUndoActions();
break;
}

}

refreshFeatureActions();
Expand Down
2 changes: 1 addition & 1 deletion src/app/qgisapp.h
Expand Up @@ -706,7 +706,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
* \param modified whether to return only layers that have been modified
* \returns list of layers in legend order, or empty list
*/
QList<QgsMapLayer *> editableLayers( bool modified = false ) const;
QList<QgsMapLayer *> editableLayers( bool modified = false, bool ignoreLayersWhichCannotBeToggled = false ) const;

//! emit initializationCompleted signal
void completeInitialization();
Expand Down
4 changes: 2 additions & 2 deletions src/core/layertree/qgslayertreeutils.cpp
Expand Up @@ -261,7 +261,7 @@ static void _readOldLegendLayer( const QDomElement &layerElem, QgsLayerTreeGroup
parent->addChildNode( layerNode );
}

bool QgsLayerTreeUtils::layersEditable( const QList<QgsLayerTreeLayer *> &layerNodes )
bool QgsLayerTreeUtils::layersEditable( const QList<QgsLayerTreeLayer *> &layerNodes, bool ignoreLayersWhichCannotBeToggled )
{
const auto constLayerNodes = layerNodes;
for ( QgsLayerTreeLayer *layerNode : constLayerNodes )
Expand All @@ -270,7 +270,7 @@ bool QgsLayerTreeUtils::layersEditable( const QList<QgsLayerTreeLayer *> &layerN
if ( !layer )
continue;

if ( layer->isEditable() )
if ( layer->isEditable() && ( !ignoreLayersWhichCannotBeToggled || !( layer->properties() & Qgis::MapLayerProperty::UsersCannotToggleEditing ) ) )
return true;
}
return false;
Expand Down
10 changes: 8 additions & 2 deletions src/core/layertree/qgslayertreeutils.h
Expand Up @@ -53,8 +53,14 @@ class CORE_EXPORT QgsLayerTreeUtils
//! Convert QString to Qt::CheckState
static Qt::CheckState checkStateFromXml( const QString &txt );

//! Returns TRUE if any of the layers is editable
static bool layersEditable( const QList<QgsLayerTreeLayer *> &layerNodes );
/**
* Returns TRUE if any of the specified layers is editable.
*
* The \a ignoreLayersWhichCannotBeToggled argument can be used to control whether layers which cannot have their
* edit states toggled by users should be ignored or not (since QGIS 3.22).
*/
static bool layersEditable( const QList<QgsLayerTreeLayer *> &layerNodes, bool ignoreLayersWhichCannotBeToggled = false );

//! Returns TRUE if any of the layers is modified
static bool layersModified( const QList<QgsLayerTreeLayer *> &layerNodes );

Expand Down
36 changes: 36 additions & 0 deletions tests/src/core/testqgslayertree.cpp
Expand Up @@ -30,6 +30,7 @@
#include <qgssettings.h>
#include "qgslegendsettings.h"
#include "qgsmarkersymbol.h"
#include "qgsannotationlayer.h"
#include <QSignalSpy>

class TestQgsLayerTree : public QObject
Expand Down Expand Up @@ -62,6 +63,7 @@ class TestQgsLayerTree : public QObject
void testSymbolText();
void testNodeDepth();
void testRasterSymbolNode();
void testLayersEditable();

private:

Expand Down Expand Up @@ -900,5 +902,39 @@ void TestQgsLayerTree::testRasterSymbolNode()
QCOMPARE( static_cast< int >( rasterNode2.flags() ), static_cast< int >( Qt::ItemIsEnabled | Qt::ItemIsUserCheckable ) );
}

void TestQgsLayerTree::testLayersEditable()
{
QgsProject project;

QgsVectorLayer *vl1 = new QgsVectorLayer( QStringLiteral( "Point?field=col1:integer" ), QStringLiteral( "vl1" ), QStringLiteral( "memory" ) );
QgsVectorLayer *vl2 = new QgsVectorLayer( QStringLiteral( "Point?field=col1:integer" ), QStringLiteral( "vl1" ), QStringLiteral( "memory" ) );
QgsAnnotationLayer *al = new QgsAnnotationLayer( QStringLiteral( "al" ), QgsAnnotationLayer::LayerOptions( project.transformContext() ) );

project.addMapLayer( vl1 );
project.addMapLayer( vl2 );
project.addMapLayer( al );

QgsLayerTree root;
QgsLayerTreeLayer *nodeVl1 = root.addLayer( vl1 );
QgsLayerTreeGroup *nodeGrp = root.addGroup( QStringLiteral( "grp" ) );
QgsLayerTreeLayer *nodeVl2 = nodeGrp->addLayer( vl2 );
QgsLayerTreeLayer *nodeAl = nodeGrp->addLayer( al );
QVERIFY( !QgsLayerTreeUtils::layersEditable( {} ) );
QVERIFY( !QgsLayerTreeUtils::layersEditable( {nodeVl1, nodeVl2} ) );
vl1->startEditing();
QVERIFY( QgsLayerTreeUtils::layersEditable( {nodeVl1} ) );
QVERIFY( QgsLayerTreeUtils::layersEditable( {nodeVl1, nodeVl2} ) );
QVERIFY( QgsLayerTreeUtils::layersEditable( {nodeVl2, nodeVl1 } ) );

QVERIFY( QgsLayerTreeUtils::layersEditable( {nodeAl} ) );
QVERIFY( QgsLayerTreeUtils::layersEditable( {nodeAl, nodeVl1} ) );
QVERIFY( QgsLayerTreeUtils::layersEditable( {nodeAl, nodeVl2} ) );

// ignore layers which can't be toggled (the annotation layer)
QVERIFY( !QgsLayerTreeUtils::layersEditable( {nodeAl}, true ) );
QVERIFY( QgsLayerTreeUtils::layersEditable( {nodeAl, nodeVl1}, true ) );
QVERIFY( !QgsLayerTreeUtils::layersEditable( {nodeAl, nodeVl2}, true ) );
}

QGSTEST_MAIN( TestQgsLayerTree )
#include "testqgslayertree.moc"

0 comments on commit 1925277

Please sign in to comment.