Skip to content

Commit 6b120a8

Browse files
committedNov 1, 2016
Fix display of diagram legend entries (fixes #15448)
To make the implementation saner, the legend node that may be embedded within parent layer node is kept separately from activeNodes. (cherry picked from commit b385ebd)
1 parent 47109d1 commit 6b120a8

File tree

7 files changed

+83
-55
lines changed

7 files changed

+83
-55
lines changed
 

‎python/core/layertree/qgslayertreemodel.sip

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,15 +92,21 @@ class QgsLayerTreeModel : QAbstractItemModel
9292
QModelIndex legendNode2index( QgsLayerTreeModelLegendNode* legendNode );
9393

9494
//! Return filtered list of active legend nodes attached to a particular layer node
95+
//! (by default it returns also legend node embedded in parent layer node (if any) unless skipNodeEmbeddedInParent is true)
9596
//! @note added in 2.6
97+
//! @note skipNodeEmbeddedInParent added in 2.18
9698
//! @see layerOriginalLegendNodes()
97-
QList<QgsLayerTreeModelLegendNode*> layerLegendNodes( QgsLayerTreeLayer* nodeLayer );
99+
QList<QgsLayerTreeModelLegendNode*> layerLegendNodes( QgsLayerTreeLayer* nodeLayer, bool skipNodeEmbeddedInParent = false );
98100

99101
//! Return original (unfiltered) list of legend nodes attached to a particular layer node
100102
//! @note added in 2.14
101103
//! @see layerLegendNodes()
102104
QList<QgsLayerTreeModelLegendNode*> layerOriginalLegendNodes( QgsLayerTreeLayer* nodeLayer );
103105

106+
//! Return legend node that may be embbeded in parent (i.e. its icon will be used for layer's icon).
107+
//! @note added in 2.18
108+
QgsLayerTreeModelLegendNode* legendNodeEmbeddedInParent( QgsLayerTreeLayer* nodeLayer ) const;
109+
104110
/** Searches through the layer tree to find a legend node with a matching layer ID
105111
* and rule key.
106112
* @param layerId map layer ID
@@ -233,8 +239,6 @@ class QgsLayerTreeModel : QAbstractItemModel
233239
QVariant legendNodeData( QgsLayerTreeModelLegendNode* node, int role ) const;
234240
Qt::ItemFlags legendNodeFlags( QgsLayerTreeModelLegendNode* node ) const;
235241
bool legendEmbeddedInParent( QgsLayerTreeLayer* nodeLayer ) const;
236-
/** Return legend node that may be embbeded in parent (i.e. its icon will be used for layer's icon). */
237-
QgsLayerTreeModelLegendNode* legendNodeEmbeddedInParent( QgsLayerTreeLayer* nodeLayer ) const;
238242
QIcon legendIconEmbeddedInParent( QgsLayerTreeLayer* nodeLayer ) const;
239243
void legendCleanup();
240244
void legendInvalidateMapBasedData();

‎src/app/composer/qgscomposerlegendwidget.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,9 +1006,8 @@ void QgsComposerLegendWidget::on_mItemTreeView_doubleClicked( const QModelIndex
10061006
currentNode->setCustomProperty( QStringLiteral( "legend/title-label" ), newText );
10071007

10081008
// force update of label of the legend node with embedded icon (a bit clumsy i know)
1009-
QList<QgsLayerTreeModelLegendNode*> nodes = model->layerLegendNodes( QgsLayerTree::toLayer( currentNode ) );
1010-
if ( nodes.count() == 1 && nodes[0]->isEmbeddedInParent() )
1011-
nodes[0]->setUserLabel( QString() );
1009+
if ( QgsLayerTreeModelLegendNode* embeddedNode = model->legendNodeEmbeddedInParent( QgsLayerTree::toLayer( currentNode ) ) )
1010+
embeddedNode->setUserLabel( QString() );
10121011
}
10131012
else if ( legendNode )
10141013
{

‎src/app/qgsmapthemes.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ void QgsMapThemes::addPerLayerCheckedLegendSymbols( QgsMapThemeCollection::MapTh
6868
bool hasCheckableItems = false;
6969
bool someItemsUnchecked = false;
7070
QSet<QString> checkedItems;
71-
Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, model->layerLegendNodes( nodeLayer ) )
71+
Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, model->layerLegendNodes( nodeLayer, true ) )
7272
{
7373
if ( legendNode->flags() & Qt::ItemIsUserCheckable )
7474
{
@@ -217,7 +217,7 @@ void QgsMapThemes::applyStateToLayerTreeGroup( QgsLayerTreeGroup* parent, const
217217
{
218218
const QSet<QString>& checkedNodes = rec.perLayerCheckedLegendSymbols().value( nodeLayer->layerId() );
219219
// some nodes are not checked
220-
Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, model->layerLegendNodes( nodeLayer ) )
220+
Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, model->layerLegendNodes( nodeLayer, true ) )
221221
{
222222
Qt::CheckState shouldHaveState = checkedNodes.contains( legendNode->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString() ) ? Qt::Checked : Qt::Unchecked;
223223
if (( legendNode->flags() & Qt::ItemIsUserCheckable ) &&
@@ -228,7 +228,7 @@ void QgsMapThemes::applyStateToLayerTreeGroup( QgsLayerTreeGroup* parent, const
228228
else
229229
{
230230
// all nodes should be checked
231-
Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, model->layerLegendNodes( nodeLayer ) )
231+
Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, model->layerLegendNodes( nodeLayer, true ) )
232232
{
233233
if (( legendNode->flags() & Qt::ItemIsUserCheckable ) &&
234234
legendNode->data( Qt::CheckStateRole ).toInt() != Qt::Checked )

‎src/core/layertree/qgslayertreemodel.cpp

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,30 +1196,45 @@ void QgsLayerTreeModel::addLegendToLayer( QgsLayerTreeLayer* nodeL )
11961196

11971197
QList<QgsLayerTreeModelLegendNode*> filteredLstNew = filterLegendNodes( lstNew );
11981198

1199-
bool hasOnlyEmbedded = filteredLstNew.count() == 1 && filteredLstNew[0]->isEmbeddedInParent();
1200-
12011199
Q_FOREACH ( QgsLayerTreeModelLegendNode* n, lstNew )
12021200
{
12031201
n->setParent( this );
12041202
connect( n, SIGNAL( dataChanged() ), this, SLOT( legendNodeDataChanged() ) );
12051203
}
12061204

1207-
LayerLegendData data;
1208-
data.originalNodes = lstNew;
1209-
data.activeNodes = filteredLstNew;
1210-
data.tree = nullptr;
1205+
// See if we have an embedded node - if we do, we will not use it among active nodes.
1206+
// Legend node embedded in parent does not have to be the first one,
1207+
// there can be also nodes generated for embedded widgets
1208+
QgsLayerTreeModelLegendNode* embeddedNode = nullptr;
1209+
Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, filteredLstNew )
1210+
{
1211+
if ( legendNode->isEmbeddedInParent() )
1212+
{
1213+
embeddedNode = legendNode;
1214+
filteredLstNew.removeOne( legendNode );
1215+
break;
1216+
}
1217+
}
1218+
1219+
LayerLegendTree* legendTree = nullptr;
12111220

12121221
// maybe the legend nodes form a tree - try to create a tree structure from the list
12131222
if ( testFlag( ShowLegendAsTree ) )
1214-
tryBuildLegendTree( data );
1223+
legendTree = tryBuildLegendTree( filteredLstNew );
12151224

1216-
int count = data.tree ? data.tree->children[nullptr].count() : filteredLstNew.count();
1225+
int count = legendTree ? legendTree->children[nullptr].count() : filteredLstNew.count();
12171226

1218-
if ( ! hasOnlyEmbedded ) beginInsertRows( node2index( nodeL ), 0, count - 1 );
1227+
if ( !filteredLstNew.isEmpty() ) beginInsertRows( node2index( nodeL ), 0, count - 1 );
1228+
1229+
LayerLegendData data;
1230+
data.originalNodes = lstNew;
1231+
data.activeNodes = filteredLstNew;
1232+
data.embeddedNodeInParent = embeddedNode;
1233+
data.tree = legendTree;
12191234

12201235
mLegend[nodeL] = data;
12211236

1222-
if ( ! hasOnlyEmbedded ) endInsertRows();
1237+
if ( !filteredLstNew.isEmpty() ) endInsertRows();
12231238

12241239
if ( hasStyleOverride )
12251240
ml->styleManager()->restoreOverrideStyle();
@@ -1230,11 +1245,11 @@ void QgsLayerTreeModel::addLegendToLayer( QgsLayerTreeLayer* nodeL )
12301245
}
12311246

12321247

1233-
void QgsLayerTreeModel::tryBuildLegendTree( LayerLegendData& data )
1248+
QgsLayerTreeModel::LayerLegendTree* QgsLayerTreeModel::tryBuildLegendTree( const QList<QgsLayerTreeModelLegendNode*>& nodes )
12341249
{
12351250
// first check whether there are any legend nodes that are not top-level
12361251
bool hasParentKeys = false;
1237-
Q_FOREACH ( QgsLayerTreeModelLegendNode* n, data.activeNodes )
1252+
Q_FOREACH ( QgsLayerTreeModelLegendNode* n, nodes )
12381253
{
12391254
if ( !n->data( QgsLayerTreeModelLegendNode::ParentRuleKeyRole ).toString().isEmpty() )
12401255
{
@@ -1243,30 +1258,31 @@ void QgsLayerTreeModel::tryBuildLegendTree( LayerLegendData& data )
12431258
}
12441259
}
12451260
if ( !hasParentKeys )
1246-
return; // all legend nodes are top-level => stick with list representation
1261+
return nullptr; // all legend nodes are top-level => stick with list representation
12471262

12481263
// make mapping from rules to nodes and do some sanity checks
12491264
QHash<QString, QgsLayerTreeModelLegendNode*> rule2node;
12501265
rule2node[QString()] = nullptr;
1251-
Q_FOREACH ( QgsLayerTreeModelLegendNode* n, data.activeNodes )
1266+
Q_FOREACH ( QgsLayerTreeModelLegendNode* n, nodes )
12521267
{
12531268
QString ruleKey = n->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString();
12541269
if ( ruleKey.isEmpty() ) // in tree all nodes must have key
1255-
return;
1270+
return nullptr;
12561271
if ( rule2node.contains( ruleKey ) ) // and they must be unique
1257-
return;
1272+
return nullptr;
12581273
rule2node[ruleKey] = n;
12591274
}
12601275

12611276
// create the tree structure
1262-
data.tree = new LayerLegendTree;
1263-
Q_FOREACH ( QgsLayerTreeModelLegendNode* n, data.activeNodes )
1277+
LayerLegendTree* tree = new LayerLegendTree;
1278+
Q_FOREACH ( QgsLayerTreeModelLegendNode* n, nodes )
12641279
{
12651280
QString parentRuleKey = n->data( QgsLayerTreeModelLegendNode::ParentRuleKeyRole ).toString();
12661281
QgsLayerTreeModelLegendNode* parent = rule2node.value( parentRuleKey, nullptr );
1267-
data.tree->parents[n] = parent;
1268-
data.tree->children[parent] << n;
1282+
tree->parents[n] = parent;
1283+
tree->children[parent] << n;
12691284
}
1285+
return tree;
12701286
}
12711287

12721288
QgsRenderContext* QgsLayerTreeModel::createTemporaryRenderContext() const
@@ -1316,6 +1332,7 @@ QModelIndex QgsLayerTreeModel::legendNode2index( QgsLayerTreeModelLegendNode* le
13161332
int row = data.activeNodes.indexOf( legendNode );
13171333
if ( row < 0 ) // legend node may be filtered (exists within the list of original nodes, but not in active nodes)
13181334
return QModelIndex();
1335+
13191336
return index( row, 0, parentIndex );
13201337
}
13211338

@@ -1340,10 +1357,6 @@ int QgsLayerTreeModel::legendRootRowCount( QgsLayerTreeLayer* nL ) const
13401357
return data.tree->children[nullptr].count();
13411358

13421359
int count = data.activeNodes.count();
1343-
1344-
if ( legendEmbeddedInParent( nL ) )
1345-
count--; // one item less -- it is embedded in parent
1346-
13471360
return count;
13481361
}
13491362

@@ -1408,35 +1421,34 @@ Qt::ItemFlags QgsLayerTreeModel::legendNodeFlags( QgsLayerTreeModelLegendNode* n
14081421

14091422
bool QgsLayerTreeModel::legendEmbeddedInParent( QgsLayerTreeLayer* nodeLayer ) const
14101423
{
1411-
return legendNodeEmbeddedInParent( nodeLayer );
1424+
return mLegend[nodeLayer].embeddedNodeInParent != nullptr;
14121425
}
14131426

14141427
QgsLayerTreeModelLegendNode* QgsLayerTreeModel::legendNodeEmbeddedInParent( QgsLayerTreeLayer* nodeLayer ) const
14151428
{
1416-
// legend node embedded in parent does not have to be the first one...
1417-
// there could be extra legend nodes generated for embedded widgets
1418-
const LayerLegendData& data = mLegend[nodeLayer];
1419-
Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, data.activeNodes )
1420-
{
1421-
if ( legendNode->isEmbeddedInParent() )
1422-
return legendNode;
1423-
}
1424-
return nullptr;
1429+
return mLegend[nodeLayer].embeddedNodeInParent;
14251430
}
14261431

14271432

14281433
QIcon QgsLayerTreeModel::legendIconEmbeddedInParent( QgsLayerTreeLayer* nodeLayer ) const
14291434
{
1430-
QgsLayerTreeModelLegendNode* legendNode = legendNodeEmbeddedInParent( nodeLayer );
1435+
QgsLayerTreeModelLegendNode* legendNode = mLegend[nodeLayer].embeddedNodeInParent;
14311436
if ( !legendNode )
14321437
return QIcon();
14331438
return QIcon( qvariant_cast<QPixmap>( legendNode->data( Qt::DecorationRole ) ) );
14341439
}
14351440

14361441

1437-
QList<QgsLayerTreeModelLegendNode*> QgsLayerTreeModel::layerLegendNodes( QgsLayerTreeLayer* nodeLayer )
1442+
QList<QgsLayerTreeModelLegendNode*> QgsLayerTreeModel::layerLegendNodes( QgsLayerTreeLayer* nodeLayer, bool skipNodeEmbeddedInParent )
14381443
{
1439-
return mLegend.value( nodeLayer ).activeNodes;
1444+
if ( !mLegend.contains( nodeLayer ) )
1445+
return QList<QgsLayerTreeModelLegendNode*>();
1446+
1447+
const LayerLegendData& data = mLegend[nodeLayer];
1448+
QList<QgsLayerTreeModelLegendNode*> lst( data.activeNodes );
1449+
if ( !skipNodeEmbeddedInParent && data.embeddedNodeInParent )
1450+
lst.prepend( data.embeddedNodeInParent );
1451+
return lst;
14401452
}
14411453

14421454
QList<QgsLayerTreeModelLegendNode*> QgsLayerTreeModel::layerOriginalLegendNodes( QgsLayerTreeLayer* nodeLayer )

‎src/core/layertree/qgslayertreemodel.h

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,15 +118,21 @@ class CORE_EXPORT QgsLayerTreeModel : public QAbstractItemModel
118118
QModelIndex legendNode2index( QgsLayerTreeModelLegendNode* legendNode );
119119

120120
//! Return filtered list of active legend nodes attached to a particular layer node
121+
//! (by default it returns also legend node embedded in parent layer node (if any) unless skipNodeEmbeddedInParent is true)
121122
//! @note added in 2.6
123+
//! @note skipNodeEmbeddedInParent added in 2.18
122124
//! @see layerOriginalLegendNodes()
123-
QList<QgsLayerTreeModelLegendNode*> layerLegendNodes( QgsLayerTreeLayer* nodeLayer );
125+
QList<QgsLayerTreeModelLegendNode*> layerLegendNodes( QgsLayerTreeLayer* nodeLayer, bool skipNodeEmbeddedInParent = false );
124126

125127
//! Return original (unfiltered) list of legend nodes attached to a particular layer node
126128
//! @note added in 2.14
127129
//! @see layerLegendNodes()
128130
QList<QgsLayerTreeModelLegendNode*> layerOriginalLegendNodes( QgsLayerTreeLayer* nodeLayer );
129131

132+
//! Return legend node that may be embbeded in parent (i.e. its icon will be used for layer's icon).
133+
//! @note added in 2.18
134+
QgsLayerTreeModelLegendNode* legendNodeEmbeddedInParent( QgsLayerTreeLayer* nodeLayer ) const;
135+
130136
/** Searches through the layer tree to find a legend node with a matching layer ID
131137
* and rule key.
132138
* @param layerId map layer ID
@@ -259,8 +265,6 @@ class CORE_EXPORT QgsLayerTreeModel : public QAbstractItemModel
259265
QVariant legendNodeData( QgsLayerTreeModelLegendNode* node, int role ) const;
260266
Qt::ItemFlags legendNodeFlags( QgsLayerTreeModelLegendNode* node ) const;
261267
bool legendEmbeddedInParent( QgsLayerTreeLayer* nodeLayer ) const;
262-
//! Return legend node that may be embbeded in parent (i.e. its icon will be used for layer's icon).
263-
QgsLayerTreeModelLegendNode* legendNodeEmbeddedInParent( QgsLayerTreeLayer* nodeLayer ) const;
264268
QIcon legendIconEmbeddedInParent( QgsLayerTreeLayer* nodeLayer ) const;
265269
void legendCleanup();
266270
void legendInvalidateMapBasedData();
@@ -293,9 +297,19 @@ class CORE_EXPORT QgsLayerTreeModel : public QAbstractItemModel
293297
//! @note not available in Python bindings
294298
struct LayerLegendData
295299
{
300+
LayerLegendData()
301+
: embeddedNodeInParent( nullptr )
302+
, tree( nullptr )
303+
{
304+
}
305+
296306
//! Active legend nodes. May have been filtered.
297307
//! Owner of legend nodes is still originalNodes !
298308
QList<QgsLayerTreeModelLegendNode*> activeNodes;
309+
//! A legend node that is not displayed separately, its icon is instead
310+
//! shown within the layer node's item.
311+
//! May be null. if non-null, node is owned by originalNodes !
312+
QgsLayerTreeModelLegendNode* embeddedNodeInParent;
299313
//! Data structure for storage of legend nodes.
300314
//! These are nodes as received from QgsMapLayerLegend
301315
QList<QgsLayerTreeModelLegendNode*> originalNodes;
@@ -304,7 +318,7 @@ class CORE_EXPORT QgsLayerTreeModel : public QAbstractItemModel
304318
};
305319

306320
//! @note not available in Python bindings
307-
void tryBuildLegendTree( LayerLegendData& data );
321+
LayerLegendTree* tryBuildLegendTree( const QList<QgsLayerTreeModelLegendNode*>& nodes );
308322

309323
//! Overrides of map layers' styles: key = layer ID, value = style XML.
310324
//! This allows to show legend that is different from the current style of layers

‎src/core/qgslegendrenderer.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -593,8 +593,7 @@ QgsComposerLegendStyle::Style QgsLegendRenderer::nodeLegendStyle( QgsLayerTreeNo
593593
return QgsComposerLegendStyle::Group;
594594
else if ( QgsLayerTree::isLayer( node ) )
595595
{
596-
QList<QgsLayerTreeModelLegendNode*> legendNodes = model->layerLegendNodes( QgsLayerTree::toLayer( node ) );
597-
if ( legendNodes.count() == 1 && legendNodes[0]->isEmbeddedInParent() )
596+
if ( model->legendNodeEmbeddedInParent( QgsLayerTree::toLayer( node ) ) )
598597
return QgsComposerLegendStyle::Hidden;
599598
return QgsComposerLegendStyle::Subgroup;
600599
}

‎src/gui/layertree/qgslayertreeview.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ void QgsLayerTreeView::modelRowsInserted( const QModelIndex& index, int start, i
138138
if ( QgsMapLayer* layer = nodeLayer->layer() )
139139
{
140140
int widgetsCount = layer->customProperty( QStringLiteral( "embeddedWidgets/count" ), 0 ).toInt();
141-
QList<QgsLayerTreeModelLegendNode*> legendNodes = layerTreeModel()->layerLegendNodes( nodeLayer );
141+
QList<QgsLayerTreeModelLegendNode*> legendNodes = layerTreeModel()->layerLegendNodes( nodeLayer, true );
142142
for ( int i = 0; i < widgetsCount; ++i )
143143
{
144144
QString providerId = layer->customProperty( QStringLiteral( "embeddedWidgets/%1/id" ).arg( i ) ).toString();
@@ -159,7 +159,7 @@ void QgsLayerTreeView::modelRowsInserted( const QModelIndex& index, int start, i
159159
if ( expandedNodeKeys.isEmpty() )
160160
return;
161161

162-
Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, layerTreeModel()->layerLegendNodes( QgsLayerTree::toLayer( parentNode ) ) )
162+
Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, layerTreeModel()->layerLegendNodes( QgsLayerTree::toLayer( parentNode ), true ) )
163163
{
164164
QString ruleKey = legendNode->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString();
165165
if ( expandedNodeKeys.contains( ruleKey ) )
@@ -345,7 +345,7 @@ static void _expandAllLegendNodes( QgsLayerTreeLayer* nodeLayer, bool expanded,
345345
QStringList lst;
346346
if ( expanded )
347347
{
348-
Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, model->layerLegendNodes( nodeLayer ) )
348+
Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, model->layerLegendNodes( nodeLayer, true ) )
349349
{
350350
QString parentKey = legendNode->data( QgsLayerTreeModelLegendNode::ParentRuleKeyRole ).toString();
351351
if ( !parentKey.isEmpty() && !lst.contains( parentKey ) )

0 commit comments

Comments
 (0)
Please sign in to comment.