Skip to content

Commit 057a20c

Browse files
committedNov 7, 2017
Allow adding multiple layers to legend at once
1 parent 27c3eb9 commit 057a20c

File tree

9 files changed

+209
-22
lines changed

9 files changed

+209
-22
lines changed
 

‎python/core/qgsmaplayermodel.sip

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,18 @@ returns if the items can be checked or not
9797
QModelIndex indexFromLayer( QgsMapLayer *layer ) const;
9898
%Docstring
9999
indexFromLayer returns the model index for a given layer
100+
.. seealso:: layerFromIndex()
100101
:rtype: QModelIndex
101102
%End
102103

104+
QgsMapLayer *layerFromIndex( const QModelIndex &index ) const;
105+
%Docstring
106+
Returns the map layer corresponding to the specified ``index``.
107+
.. versionadded:: 3.0
108+
.. seealso:: indexFromLayer()
109+
:rtype: QgsMapLayer
110+
%End
111+
103112
void setAdditionalItems( const QStringList &items );
104113
%Docstring
105114
Sets a list of additional (non map layer) items to include at the end of the model.

‎src/app/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ SET(QGIS_APP_SRCS
180180
layout/qgslayoutitemslistview.cpp
181181
layout/qgslayoutappmenuprovider.cpp
182182
layout/qgslayoutlabelwidget.cpp
183+
layout/qgslayoutlegendlayersdialog.cpp
183184
layout/qgslayoutlegendwidget.cpp
184185
layout/qgslayoutmapwidget.cpp
185186
layout/qgslayoutmapgridwidget.cpp
@@ -385,6 +386,7 @@ SET (QGIS_APP_MOC_HDRS
385386
layout/qgslayoutitemslistview.h
386387
layout/qgslayoutlabelwidget.h
387388
layout/qgslayoutlegendwidget.h
389+
layout/qgslayoutlegendlayersdialog.h
388390
layout/qgslayoutmapwidget.h
389391
layout/qgslayoutmapgridwidget.h
390392
layout/qgslayoutpagepropertieswidget.h
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/***************************************************************************
2+
qgslayoutlegendlayersdialog.cpp
3+
-------------------------------
4+
begin : October 2017
5+
copyright : (C) 2017 by Nyall Dawson
6+
email : nyall dot dawson 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+
#include "qgslayoutlegendlayersdialog.h"
16+
17+
#include <QStandardItem>
18+
#include "qgsmaplayer.h"
19+
#include "qgsmaplayermodel.h"
20+
#include "qgssettings.h"
21+
22+
QgsLayoutLegendLayersDialog::QgsLayoutLegendLayersDialog( QWidget *parent )
23+
: QDialog( parent )
24+
{
25+
setupUi( this );
26+
QgsSettings settings;
27+
restoreGeometry( settings.value( QStringLiteral( "Windows/LayoutLegendLayers/geometry" ) ).toByteArray() );
28+
29+
mModel = new QgsMapLayerModel( listMapLayers );
30+
listMapLayers->setModel( mModel );
31+
QModelIndex firstLayer = mModel->index( 0, 0 );
32+
listMapLayers->selectionModel()->select( firstLayer, QItemSelectionModel::Select );
33+
}
34+
35+
QgsLayoutLegendLayersDialog::~QgsLayoutLegendLayersDialog()
36+
{
37+
QgsSettings settings;
38+
settings.setValue( QStringLiteral( "Windows/LayoutLegendLayers/geometry" ), saveGeometry() );
39+
}
40+
41+
QList< QgsMapLayer *> QgsLayoutLegendLayersDialog::selectedLayers() const
42+
{
43+
QList< QgsMapLayer * > layers;
44+
45+
const QModelIndexList selection = listMapLayers->selectionModel()->selectedIndexes();
46+
for ( const QModelIndex &index : selection )
47+
{
48+
QgsMapLayer *layer = mModel->layerFromIndex( index );
49+
if ( layer )
50+
layers << layer;
51+
}
52+
return layers;
53+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/***************************************************************************
2+
qgslayoutlegendlayersdialog.h
3+
-----------------------------
4+
begin : October 2017
5+
copyright : (C) 2017 by Nyall Dawson
6+
email : nyall dot dawson 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+
#ifndef QGSLAYOUTLEGENDLAYERSDIALOG_H
16+
#define QGSLAYOUTLEGENDLAYERSDIALOG_H
17+
18+
#include "ui_qgslayoutlegendlayersdialogbase.h"
19+
20+
class QgsMapLayer;
21+
class QgsMapLayerModel;
22+
23+
/**
24+
* \ingroup app
25+
* A dialog to add new layers to the legend.
26+
* */
27+
class QgsLayoutLegendLayersDialog: public QDialog, private Ui::QgsLayoutLegendLayersDialogBase
28+
{
29+
Q_OBJECT
30+
31+
public:
32+
QgsLayoutLegendLayersDialog( QWidget *parent = nullptr );
33+
~QgsLayoutLegendLayersDialog();
34+
35+
QList< QgsMapLayer * > selectedLayers() const;
36+
37+
private:
38+
QgsLayoutLegendLayersDialog() = delete;
39+
40+
QgsMapLayerModel *mModel = nullptr;
41+
};
42+
43+
#endif //QGSLAYOUTLEGENDLAYERSDIALOG_H

‎src/app/layout/qgslayoutlegendwidget.cpp

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
#include "qgslayoutlegendwidget.h"
1919
#include "qgslayoutitemlegend.h"
20-
#include "qgscomposerlegendlayersdialog.h"
20+
#include "qgslayoutlegendlayersdialog.h"
2121
#include "qgslayoutitemwidget.h"
2222
#include "qgslayoutitemmap.h"
2323
#include "qgslayout.h"
@@ -693,27 +693,19 @@ void QgsLayoutLegendWidget::mAddToolButton_clicked()
693693
return;
694694
}
695695

696-
QgisApp *app = QgisApp::instance();
697-
if ( !app )
696+
QgsLayoutLegendLayersDialog addDialog( this );
697+
if ( addDialog.exec() == QDialog::Accepted )
698698
{
699-
return;
700-
}
701-
702-
QgsMapCanvas *canvas = app->mapCanvas();
703-
if ( canvas )
704-
{
705-
QList<QgsMapLayer *> layers = canvas->layers();
706-
707-
QgsComposerLegendLayersDialog addDialog( layers, this );
708-
if ( addDialog.exec() == QDialog::Accepted )
699+
const QList<QgsMapLayer *> layers = addDialog.selectedLayers();
700+
if ( !layers.empty() )
709701
{
710-
QgsMapLayer *layer = addDialog.selectedLayer();
711-
if ( layer )
702+
mLegend->beginCommand( QStringLiteral( "Add Legend Item(s)" ) );
703+
for ( QgsMapLayer *layer : layers )
712704
{
713-
mLegend->beginCommand( QStringLiteral( "Add Legend Item" ) );
714705
mLegend->model()->rootGroup()->addLayer( layer );
715-
mLegend->endCommand();
716706
}
707+
mLegend->updateLegend();
708+
mLegend->endCommand();
717709
}
718710
}
719711
}
@@ -770,8 +762,7 @@ void QgsLayoutLegendWidget::mRemoveToolButton_clicked()
770762
mLegend->model()->removeRow( index.row(), index.parent() );
771763
}
772764

773-
mLegend->adjustBoxSize();
774-
mLegend->updateFilterByMap();
765+
mLegend->updateLegend();
775766
mLegend->endCommand();
776767
}
777768

@@ -824,8 +815,7 @@ void QgsLayoutLegendWidget::resetLayerNodeToDefaults()
824815

825816
mItemTreeView->layerTreeModel()->refreshLayerLegend( nodeLayer );
826817

827-
mLegend->updateFilterByMap();
828-
mLegend->adjustBoxSize();
818+
mLegend->updateLegend();
829819
mLegend->endCommand();
830820
}
831821

@@ -902,7 +892,7 @@ void QgsLayoutLegendWidget::mAddGroupToolButton_clicked()
902892
{
903893
mLegend->beginCommand( tr( "Add Legend Group" ) );
904894
mLegend->model()->rootGroup()->addGroup( tr( "Group" ) );
905-
mLegend->updateFilterByMap();
895+
mLegend->updateLegend();
906896
mLegend->endCommand();
907897
}
908898
}

‎src/core/qgsmaplayermodel.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ QModelIndex QgsMapLayerModel::indexFromLayer( QgsMapLayer *layer ) const
101101
return index( r, 0 );
102102
}
103103

104+
QgsMapLayer *QgsMapLayerModel::layerFromIndex( const QModelIndex &index ) const
105+
{
106+
return static_cast<QgsMapLayer *>( index.internalPointer() );
107+
}
108+
104109
void QgsMapLayerModel::setAdditionalItems( const QStringList &items )
105110
{
106111
if ( items == mAdditionalItems )

‎src/core/qgsmaplayermodel.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,17 @@ class CORE_EXPORT QgsMapLayerModel : public QAbstractItemModel
110110

111111
/**
112112
* \brief indexFromLayer returns the model index for a given layer
113+
* \see layerFromIndex()
113114
*/
114115
QModelIndex indexFromLayer( QgsMapLayer *layer ) const;
115116

117+
/**
118+
* Returns the map layer corresponding to the specified \a index.
119+
* \since QGIS 3.0
120+
* \see indexFromLayer()
121+
*/
122+
QgsMapLayer *layerFromIndex( const QModelIndex &index ) const;
123+
116124
/**
117125
* Sets a list of additional (non map layer) items to include at the end of the model.
118126
* These may represent additional layers such as layers which are not included in the map
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ui version="4.0">
3+
<class>QgsLayoutLegendLayersDialogBase</class>
4+
<widget class="QDialog" name="QgsLayoutLegendLayersDialogBase">
5+
<property name="geometry">
6+
<rect>
7+
<x>0</x>
8+
<y>0</y>
9+
<width>252</width>
10+
<height>194</height>
11+
</rect>
12+
</property>
13+
<property name="windowTitle">
14+
<string>Add Layer to Legend</string>
15+
</property>
16+
<layout class="QGridLayout" name="gridLayout">
17+
<item row="1" column="0">
18+
<widget class="QDialogButtonBox" name="buttonBox">
19+
<property name="orientation">
20+
<enum>Qt::Horizontal</enum>
21+
</property>
22+
<property name="standardButtons">
23+
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
24+
</property>
25+
</widget>
26+
</item>
27+
<item row="0" column="0">
28+
<widget class="QListView" name="listMapLayers">
29+
<property name="selectionMode">
30+
<enum>QAbstractItemView::ExtendedSelection</enum>
31+
</property>
32+
</widget>
33+
</item>
34+
</layout>
35+
</widget>
36+
<resources/>
37+
<connections>
38+
<connection>
39+
<sender>buttonBox</sender>
40+
<signal>accepted()</signal>
41+
<receiver>QgsLayoutLegendLayersDialogBase</receiver>
42+
<slot>accept()</slot>
43+
<hints>
44+
<hint type="sourcelabel">
45+
<x>248</x>
46+
<y>254</y>
47+
</hint>
48+
<hint type="destinationlabel">
49+
<x>157</x>
50+
<y>274</y>
51+
</hint>
52+
</hints>
53+
</connection>
54+
<connection>
55+
<sender>buttonBox</sender>
56+
<signal>rejected()</signal>
57+
<receiver>QgsLayoutLegendLayersDialogBase</receiver>
58+
<slot>reject()</slot>
59+
<hints>
60+
<hint type="sourcelabel">
61+
<x>316</x>
62+
<y>260</y>
63+
</hint>
64+
<hint type="destinationlabel">
65+
<x>286</x>
66+
<y>274</y>
67+
</hint>
68+
</hints>
69+
</connection>
70+
</connections>
71+
</ui>

‎tests/src/python/test_qgsmaplayermodel.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,15 @@ def testAddingRemovingLayers(self):
6363
l1 = create_layer('l1')
6464
QgsProject.instance().addMapLayer(l1)
6565
self.assertEqual(m.rowCount(QModelIndex()), 1)
66+
self.assertEqual(m.layerFromIndex(m.index(0, 0)), l1)
6667
l2 = create_layer('l2')
6768
QgsProject.instance().addMapLayer(l2)
6869
self.assertEqual(m.rowCount(QModelIndex()), 2)
70+
self.assertEqual(m.layerFromIndex(m.index(0, 0)), l1)
71+
self.assertEqual(m.layerFromIndex(m.index(1, 0)), l2)
6972
QgsProject.instance().removeMapLayer(l1)
7073
self.assertEqual(m.rowCount(QModelIndex()), 1)
74+
self.assertEqual(m.layerFromIndex(m.index(0, 0)), l2)
7175
QgsProject.instance().removeMapLayer(l2)
7276
self.assertEqual(m.rowCount(QModelIndex()), 0)
7377

@@ -162,7 +166,9 @@ def testIndexFromLayer(self):
162166
l3 = create_layer('l3') # not in registry
163167

164168
self.assertEqual(m.indexFromLayer(l1).row(), 0)
169+
self.assertEqual(m.layerFromIndex(m.indexFromLayer(l1)), l1)
165170
self.assertEqual(m.indexFromLayer(l2).row(), 1)
171+
self.assertEqual(m.layerFromIndex(m.indexFromLayer(l2)), l2)
166172
self.assertFalse(m.indexFromLayer(l3).isValid())
167173

168174
m.setAllowEmptyLayer(True)

0 commit comments

Comments
 (0)
Please sign in to comment.