Skip to content

Commit c11df1a

Browse files
committed
[FEATURE] Duplicate map layer(s)
- Action available in Layer menu and legend contextual menu - Layer style copy/pasted to duplicate - Memory and plugin layers skipped - Add sip binding to action in app interface
1 parent 42104d7 commit c11df1a

File tree

8 files changed

+102
-0
lines changed

8 files changed

+102
-0
lines changed

python/gui/qgisinterface.sip

+2
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,8 @@ class QgisInterface : QObject
364364
virtual QAction *actionLayerSaveAs() = 0;
365365
virtual QAction *actionLayerSelectionSaveAs() = 0;
366366
virtual QAction *actionRemoveLayer() = 0;
367+
/** @note added in 2.0 */
368+
virtual QAction *actionDuplicateLayer() = 0;
367369
virtual QAction *actionLayerProperties() = 0;
368370
virtual QAction *actionLayerSeparator2() = 0 /Deprecated/;
369371
virtual QAction *actionAddToOverview() = 0;

src/app/legend/qgslegendlayer.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,9 @@ void QgsLegendLayer::addToPopupMenu( QMenu& theMenu )
430430
// remove from canvas
431431
theMenu.addAction( QgsApplication::getThemeIcon( "/mActionRemoveLayer.png" ), tr( "&Remove" ), QgisApp::instance(), SLOT( removeLayer() ) );
432432

433+
// duplicate layer
434+
theMenu.addAction( QgsApplication::getThemeIcon( "/mActionAddMap.png" ), tr( "&Duplicate" ), QgisApp::instance(), SLOT( duplicateLayers() ) );
435+
433436
// set layer crs
434437
theMenu.addAction( QgsApplication::getThemeIcon( "/mActionSetCRS.png" ), tr( "&Set Layer CRS" ), QgisApp::instance(), SLOT( setLayerCRS() ) );
435438

src/app/qgisapp.cpp

+74
Original file line numberDiff line numberDiff line change
@@ -961,6 +961,7 @@ void QgisApp::createActions()
961961
connect( mActionLayerSaveAs, SIGNAL( triggered() ), this, SLOT( saveAsFile() ) );
962962
connect( mActionLayerSelectionSaveAs, SIGNAL( triggered() ), this, SLOT( saveSelectionAsVectorFile() ) );
963963
connect( mActionRemoveLayer, SIGNAL( triggered() ), this, SLOT( removeLayer() ) );
964+
connect( mActionDuplicateLayer, SIGNAL( triggered() ), this, SLOT( duplicateLayers() ) );
964965
connect( mActionSetLayerCRS, SIGNAL( triggered() ), this, SLOT( setLayerCRS() ) );
965966
connect( mActionSetProjectCRSFromLayer, SIGNAL( triggered() ), this, SLOT( setProjectCRSFromLayer() ) );
966967
connect( mActionLayerProperties, SIGNAL( triggered() ), this, SLOT( layerProperties() ) );
@@ -1630,6 +1631,7 @@ void QgisApp::setTheme( QString theThemeName )
16301631
mActionAddMssqlLayer->setIcon( QgsApplication::getThemeIcon( "/mActionAddMssqlLayer.png" ) );
16311632
#endif
16321633
mActionRemoveLayer->setIcon( QgsApplication::getThemeIcon( "/mActionRemoveLayer.png" ) );
1634+
mActionDuplicateLayer->setIcon( QgsApplication::getThemeIcon( "/mActionAddMap.png" ) );
16331635
mActionSetLayerCRS->setIcon( QgsApplication::getThemeIcon( "/mActionSetLayerCRS.png" ) );
16341636
mActionSetProjectCRSFromLayer->setIcon( QgsApplication::getThemeIcon( "/mActionSetProjectCRSFromLayer.png" ) );
16351637
mActionNewVectorLayer->setIcon( QgsApplication::getThemeIcon( "/mActionNewVectorLayer.png" ) );
@@ -5341,6 +5343,77 @@ void QgisApp::removeLayer()
53415343
mMapCanvas->refresh();
53425344
}
53435345

5346+
void QgisApp::duplicateLayers( QList<QgsMapLayer *> lyrList )
5347+
{
5348+
if ( mMapCanvas && mMapCanvas->isDrawing() )
5349+
{
5350+
return;
5351+
}
5352+
5353+
if ( !mMapLegend )
5354+
{
5355+
return;
5356+
}
5357+
5358+
QList<QgsMapLayer *> selectedLyrs = lyrList.empty() ? mMapLegend->selectedLayers() : lyrList;
5359+
if ( selectedLyrs.empty() )
5360+
{
5361+
return;
5362+
}
5363+
5364+
mMapCanvas->freeze();
5365+
QgsMapLayer *dupLayer;
5366+
foreach ( QgsMapLayer * selectedLyr, selectedLyrs )
5367+
{
5368+
dupLayer = 0;
5369+
QString layerDupName = selectedLyr->name() + " " + tr( "copy" );
5370+
5371+
// duplicate the layer's basic parameters
5372+
5373+
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer*>( selectedLyr );
5374+
// TODO: check for other layer types that won't duplicate correctly
5375+
// currently memory and plugin layers are skipped
5376+
if ( vlayer && vlayer->storageType() != "Memory storage" )
5377+
{
5378+
dupLayer = new QgsVectorLayer( vlayer->source(), layerDupName, vlayer->providerType() );
5379+
}
5380+
5381+
if ( !dupLayer )
5382+
{
5383+
QgsRasterLayer *rlayer = qobject_cast<QgsRasterLayer*>( selectedLyr );
5384+
if ( rlayer )
5385+
{
5386+
dupLayer = new QgsRasterLayer( rlayer->source(), layerDupName );
5387+
}
5388+
}
5389+
5390+
if ( dupLayer && !dupLayer->isValid() )
5391+
{
5392+
QgsDebugMsg( "Duplicated layer was invalid" );
5393+
continue;
5394+
}
5395+
5396+
if ( !dupLayer )
5397+
{
5398+
QMessageBox::information( this,
5399+
tr( "Unsupported Layer" ),
5400+
tr( "%1\n\nDuplication of layer type is unsupported." ).arg( selectedLyr->name() ) );
5401+
continue;
5402+
}
5403+
5404+
// add layer to project and layer registry
5405+
addMapLayer( dupLayer );
5406+
5407+
// duplicate the layer style
5408+
copyStyle( selectedLyr );
5409+
pasteStyle( dupLayer );
5410+
}
5411+
5412+
dupLayer = 0;
5413+
mMapCanvas->freeze( false );
5414+
mMapCanvas->refresh();
5415+
}
5416+
53445417
void QgisApp::setLayerCRS()
53455418
{
53465419
if ( mMapCanvas && mMapCanvas->isDrawing() )
@@ -6833,6 +6906,7 @@ void QgisApp::selectionChanged( QgsMapLayer *layer )
68336906
void QgisApp::legendLayerSelectionChanged( void )
68346907
{
68356908
mActionRemoveLayer->setEnabled( mMapLegend && mMapLegend->selectedLayers().size() > 0 );
6909+
mActionDuplicateLayer->setEnabled( mMapLegend && mMapLegend->selectedLayers().size() > 0 );
68366910
mActionSetLayerCRS->setEnabled( mMapLegend && mMapLegend->selectedLayers().size() > 0 );
68376911
mActionSetProjectCRSFromLayer->setEnabled( mMapLegend && mMapLegend->selectedLayers().size() == 1 );
68386912
}

src/app/qgisapp.h

+5
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,8 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
290290
QAction *actionLayerSaveAs() { return mActionLayerSaveAs; }
291291
QAction *actionLayerSelectionSaveAs() { return mActionLayerSelectionSaveAs; }
292292
QAction *actionRemoveLayer() { return mActionRemoveLayer; }
293+
/** @note added in 2.0 */
294+
QAction *actionDuplicateLayer() { return mActionDuplicateLayer; }
293295
QAction *actionSetLayerCRS() { return mActionSetLayerCRS; }
294296
QAction *actionSetProjectCRSFromLayer() { return mActionSetProjectCRSFromLayer; }
295297
QAction *actionLayerProperties() { return mActionLayerProperties; }
@@ -543,6 +545,9 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
543545
void userCenter();
544546
//! Remove a layer from the map and legend
545547
void removeLayer();
548+
/** Duplicate map layer(s) in legend
549+
* @note added in 2.0 */
550+
void duplicateLayers( const QList<QgsMapLayer *> lyrList = QList<QgsMapLayer *>() );
546551
//! Set CRS of a layer
547552
void setLayerCRS();
548553
//! Assign layer CRS to project

src/app/qgisappinterface.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ QAction *QgisAppInterface::actionToggleEditing() { return qgis->actionToggleEdit
465465
QAction *QgisAppInterface::actionLayerSaveAs() { return qgis->actionLayerSaveAs(); }
466466
QAction *QgisAppInterface::actionLayerSelectionSaveAs() { return qgis->actionLayerSelectionSaveAs(); }
467467
QAction *QgisAppInterface::actionRemoveLayer() { return qgis->actionRemoveLayer(); }
468+
QAction *QgisAppInterface::actionDuplicateLayer() { return qgis->actionDuplicateLayer(); }
468469
QAction *QgisAppInterface::actionLayerProperties() { return qgis->actionLayerProperties(); }
469470
QAction *QgisAppInterface::actionLayerSeparator2() { return 0; }
470471
QAction *QgisAppInterface::actionAddToOverview() { return qgis->actionAddToOverview(); }

src/app/qgisappinterface.h

+2
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,8 @@ class QgisAppInterface : public QgisInterface
313313
virtual QAction *actionLayerSaveAs();
314314
virtual QAction *actionLayerSelectionSaveAs();
315315
virtual QAction *actionRemoveLayer();
316+
/** @note added in 2.0 */
317+
virtual QAction *actionDuplicateLayer();
316318
virtual QAction *actionLayerProperties();
317319
virtual QAction *actionLayerSeparator2();
318320
virtual QAction *actionAddToOverview();

src/gui/qgisinterface.h

+2
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,8 @@ class GUI_EXPORT QgisInterface : public QObject
466466
virtual QAction *actionLayerSaveAs() = 0;
467467
virtual QAction *actionLayerSelectionSaveAs() = 0;
468468
virtual QAction *actionRemoveLayer() = 0;
469+
/** @note added in 2.0 */
470+
virtual QAction *actionDuplicateLayer() = 0;
469471
virtual QAction *actionLayerProperties() = 0;
470472
#ifndef Q_MOC_RUN
471473
Q_DECL_DEPRECATED

src/ui/qgisapp.ui

+13
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@
168168
<addaction name="mActionLayerSaveAs"/>
169169
<addaction name="mActionLayerSelectionSaveAs"/>
170170
<addaction name="mActionRemoveLayer"/>
171+
<addaction name="mActionDuplicateLayer"/>
171172
<addaction name="mActionSetLayerCRS"/>
172173
<addaction name="mActionSetProjectCRSFromLayer"/>
173174
<addaction name="mActionLayerProperties"/>
@@ -1821,6 +1822,18 @@ Acts on currently active editable layer</string>
18211822
<string>Html Annotation</string>
18221823
</property>
18231824
</action>
1825+
<action name="mActionDuplicateLayer">
1826+
<property name="icon">
1827+
<iconset resource="../../images/images.qrc">
1828+
<normaloff>:/images/themes/default/mActionAddMap.png</normaloff>:/images/themes/default/mActionAddMap.png</iconset>
1829+
</property>
1830+
<property name="text">
1831+
<string>Duplicate Layer(s)</string>
1832+
</property>
1833+
<property name="toolTip">
1834+
<string>Duplicate Layer(s)</string>
1835+
</property>
1836+
</action>
18241837
</widget>
18251838
<resources>
18261839
<include location="../../images/images.qrc"/>

0 commit comments

Comments
 (0)