Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Allow adding multiple layers to legend at once
  • Loading branch information
nyalldawson committed Nov 7, 2017
1 parent 27c3eb9 commit 057a20c
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 22 deletions.
9 changes: 9 additions & 0 deletions python/core/qgsmaplayermodel.sip
Expand Up @@ -97,9 +97,18 @@ returns if the items can be checked or not
QModelIndex indexFromLayer( QgsMapLayer *layer ) const;
%Docstring
indexFromLayer returns the model index for a given layer
.. seealso:: layerFromIndex()
:rtype: QModelIndex
%End

QgsMapLayer *layerFromIndex( const QModelIndex &index ) const;
%Docstring
Returns the map layer corresponding to the specified ``index``.
.. versionadded:: 3.0
.. seealso:: indexFromLayer()
:rtype: QgsMapLayer
%End

void setAdditionalItems( const QStringList &items );
%Docstring
Sets a list of additional (non map layer) items to include at the end of the model.
Expand Down
2 changes: 2 additions & 0 deletions src/app/CMakeLists.txt
Expand Up @@ -180,6 +180,7 @@ SET(QGIS_APP_SRCS
layout/qgslayoutitemslistview.cpp
layout/qgslayoutappmenuprovider.cpp
layout/qgslayoutlabelwidget.cpp
layout/qgslayoutlegendlayersdialog.cpp
layout/qgslayoutlegendwidget.cpp
layout/qgslayoutmapwidget.cpp
layout/qgslayoutmapgridwidget.cpp
Expand Down Expand Up @@ -385,6 +386,7 @@ SET (QGIS_APP_MOC_HDRS
layout/qgslayoutitemslistview.h
layout/qgslayoutlabelwidget.h
layout/qgslayoutlegendwidget.h
layout/qgslayoutlegendlayersdialog.h
layout/qgslayoutmapwidget.h
layout/qgslayoutmapgridwidget.h
layout/qgslayoutpagepropertieswidget.h
Expand Down
53 changes: 53 additions & 0 deletions src/app/layout/qgslayoutlegendlayersdialog.cpp
@@ -0,0 +1,53 @@
/***************************************************************************
qgslayoutlegendlayersdialog.cpp
-------------------------------
begin : October 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgslayoutlegendlayersdialog.h"

#include <QStandardItem>
#include "qgsmaplayer.h"
#include "qgsmaplayermodel.h"
#include "qgssettings.h"

QgsLayoutLegendLayersDialog::QgsLayoutLegendLayersDialog( QWidget *parent )
: QDialog( parent )
{
setupUi( this );
QgsSettings settings;
restoreGeometry( settings.value( QStringLiteral( "Windows/LayoutLegendLayers/geometry" ) ).toByteArray() );

mModel = new QgsMapLayerModel( listMapLayers );
listMapLayers->setModel( mModel );
QModelIndex firstLayer = mModel->index( 0, 0 );
listMapLayers->selectionModel()->select( firstLayer, QItemSelectionModel::Select );
}

QgsLayoutLegendLayersDialog::~QgsLayoutLegendLayersDialog()
{
QgsSettings settings;
settings.setValue( QStringLiteral( "Windows/LayoutLegendLayers/geometry" ), saveGeometry() );
}

QList< QgsMapLayer *> QgsLayoutLegendLayersDialog::selectedLayers() const
{
QList< QgsMapLayer * > layers;

const QModelIndexList selection = listMapLayers->selectionModel()->selectedIndexes();
for ( const QModelIndex &index : selection )
{
QgsMapLayer *layer = mModel->layerFromIndex( index );
if ( layer )
layers << layer;
}
return layers;
}
43 changes: 43 additions & 0 deletions src/app/layout/qgslayoutlegendlayersdialog.h
@@ -0,0 +1,43 @@
/***************************************************************************
qgslayoutlegendlayersdialog.h
-----------------------------
begin : October 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSLAYOUTLEGENDLAYERSDIALOG_H
#define QGSLAYOUTLEGENDLAYERSDIALOG_H

#include "ui_qgslayoutlegendlayersdialogbase.h"

class QgsMapLayer;
class QgsMapLayerModel;

/**
* \ingroup app
* A dialog to add new layers to the legend.
* */
class QgsLayoutLegendLayersDialog: public QDialog, private Ui::QgsLayoutLegendLayersDialogBase
{
Q_OBJECT

public:
QgsLayoutLegendLayersDialog( QWidget *parent = nullptr );
~QgsLayoutLegendLayersDialog();

QList< QgsMapLayer * > selectedLayers() const;

private:
QgsLayoutLegendLayersDialog() = delete;

QgsMapLayerModel *mModel = nullptr;
};

#endif //QGSLAYOUTLEGENDLAYERSDIALOG_H
34 changes: 12 additions & 22 deletions src/app/layout/qgslayoutlegendwidget.cpp
Expand Up @@ -17,7 +17,7 @@

#include "qgslayoutlegendwidget.h"
#include "qgslayoutitemlegend.h"
#include "qgscomposerlegendlayersdialog.h"
#include "qgslayoutlegendlayersdialog.h"
#include "qgslayoutitemwidget.h"
#include "qgslayoutitemmap.h"
#include "qgslayout.h"
Expand Down Expand Up @@ -693,27 +693,19 @@ void QgsLayoutLegendWidget::mAddToolButton_clicked()
return;
}

QgisApp *app = QgisApp::instance();
if ( !app )
QgsLayoutLegendLayersDialog addDialog( this );
if ( addDialog.exec() == QDialog::Accepted )
{
return;
}

QgsMapCanvas *canvas = app->mapCanvas();
if ( canvas )
{
QList<QgsMapLayer *> layers = canvas->layers();

QgsComposerLegendLayersDialog addDialog( layers, this );
if ( addDialog.exec() == QDialog::Accepted )
const QList<QgsMapLayer *> layers = addDialog.selectedLayers();
if ( !layers.empty() )
{
QgsMapLayer *layer = addDialog.selectedLayer();
if ( layer )
mLegend->beginCommand( QStringLiteral( "Add Legend Item(s)" ) );
for ( QgsMapLayer *layer : layers )
{
mLegend->beginCommand( QStringLiteral( "Add Legend Item" ) );
mLegend->model()->rootGroup()->addLayer( layer );
mLegend->endCommand();
}
mLegend->updateLegend();
mLegend->endCommand();
}
}
}
Expand Down Expand Up @@ -770,8 +762,7 @@ void QgsLayoutLegendWidget::mRemoveToolButton_clicked()
mLegend->model()->removeRow( index.row(), index.parent() );
}

mLegend->adjustBoxSize();
mLegend->updateFilterByMap();
mLegend->updateLegend();
mLegend->endCommand();
}

Expand Down Expand Up @@ -824,8 +815,7 @@ void QgsLayoutLegendWidget::resetLayerNodeToDefaults()

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

mLegend->updateFilterByMap();
mLegend->adjustBoxSize();
mLegend->updateLegend();
mLegend->endCommand();
}

Expand Down Expand Up @@ -902,7 +892,7 @@ void QgsLayoutLegendWidget::mAddGroupToolButton_clicked()
{
mLegend->beginCommand( tr( "Add Legend Group" ) );
mLegend->model()->rootGroup()->addGroup( tr( "Group" ) );
mLegend->updateFilterByMap();
mLegend->updateLegend();
mLegend->endCommand();
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/core/qgsmaplayermodel.cpp
Expand Up @@ -101,6 +101,11 @@ QModelIndex QgsMapLayerModel::indexFromLayer( QgsMapLayer *layer ) const
return index( r, 0 );
}

QgsMapLayer *QgsMapLayerModel::layerFromIndex( const QModelIndex &index ) const
{
return static_cast<QgsMapLayer *>( index.internalPointer() );
}

void QgsMapLayerModel::setAdditionalItems( const QStringList &items )
{
if ( items == mAdditionalItems )
Expand Down
8 changes: 8 additions & 0 deletions src/core/qgsmaplayermodel.h
Expand Up @@ -110,9 +110,17 @@ class CORE_EXPORT QgsMapLayerModel : public QAbstractItemModel

/**
* \brief indexFromLayer returns the model index for a given layer
* \see layerFromIndex()
*/
QModelIndex indexFromLayer( QgsMapLayer *layer ) const;

/**
* Returns the map layer corresponding to the specified \a index.
* \since QGIS 3.0
* \see indexFromLayer()
*/
QgsMapLayer *layerFromIndex( const QModelIndex &index ) const;

/**
* Sets a list of additional (non map layer) items to include at the end of the model.
* These may represent additional layers such as layers which are not included in the map
Expand Down
71 changes: 71 additions & 0 deletions src/ui/layout/qgslayoutlegendlayersdialogbase.ui
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsLayoutLegendLayersDialogBase</class>
<widget class="QDialog" name="QgsLayoutLegendLayersDialogBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>252</width>
<height>194</height>
</rect>
</property>
<property name="windowTitle">
<string>Add Layer to Legend</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QListView" name="listMapLayers">
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>QgsLayoutLegendLayersDialogBase</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>QgsLayoutLegendLayersDialogBase</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
6 changes: 6 additions & 0 deletions tests/src/python/test_qgsmaplayermodel.py
Expand Up @@ -63,11 +63,15 @@ def testAddingRemovingLayers(self):
l1 = create_layer('l1')
QgsProject.instance().addMapLayer(l1)
self.assertEqual(m.rowCount(QModelIndex()), 1)
self.assertEqual(m.layerFromIndex(m.index(0, 0)), l1)
l2 = create_layer('l2')
QgsProject.instance().addMapLayer(l2)
self.assertEqual(m.rowCount(QModelIndex()), 2)
self.assertEqual(m.layerFromIndex(m.index(0, 0)), l1)
self.assertEqual(m.layerFromIndex(m.index(1, 0)), l2)
QgsProject.instance().removeMapLayer(l1)
self.assertEqual(m.rowCount(QModelIndex()), 1)
self.assertEqual(m.layerFromIndex(m.index(0, 0)), l2)
QgsProject.instance().removeMapLayer(l2)
self.assertEqual(m.rowCount(QModelIndex()), 0)

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

self.assertEqual(m.indexFromLayer(l1).row(), 0)
self.assertEqual(m.layerFromIndex(m.indexFromLayer(l1)), l1)
self.assertEqual(m.indexFromLayer(l2).row(), 1)
self.assertEqual(m.layerFromIndex(m.indexFromLayer(l2)), l2)
self.assertFalse(m.indexFromLayer(l3).isValid())

m.setAllowEmptyLayer(True)
Expand Down

0 comments on commit 057a20c

Please sign in to comment.