mirror of
				https://github.com/qgis/QGIS.git
				synced 2025-11-04 00:04:25 -05:00 
			
		
		
		
	[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
This commit is contained in:
		
							parent
							
								
									42104d7f3d
								
							
						
					
					
						commit
						c11df1aa79
					
				@ -364,6 +364,8 @@ class QgisInterface : QObject
 | 
			
		||||
    virtual QAction *actionLayerSaveAs() = 0;
 | 
			
		||||
    virtual QAction *actionLayerSelectionSaveAs() = 0;
 | 
			
		||||
    virtual QAction *actionRemoveLayer() = 0;
 | 
			
		||||
    /** @note added in 2.0 */
 | 
			
		||||
    virtual QAction *actionDuplicateLayer() = 0;
 | 
			
		||||
    virtual QAction *actionLayerProperties() = 0;
 | 
			
		||||
    virtual QAction *actionLayerSeparator2() = 0 /Deprecated/;
 | 
			
		||||
    virtual QAction *actionAddToOverview() = 0;
 | 
			
		||||
 | 
			
		||||
@ -430,6 +430,9 @@ void QgsLegendLayer::addToPopupMenu( QMenu& theMenu )
 | 
			
		||||
  // remove from canvas
 | 
			
		||||
  theMenu.addAction( QgsApplication::getThemeIcon( "/mActionRemoveLayer.png" ), tr( "&Remove" ), QgisApp::instance(), SLOT( removeLayer() ) );
 | 
			
		||||
 | 
			
		||||
  // duplicate layer
 | 
			
		||||
  theMenu.addAction( QgsApplication::getThemeIcon( "/mActionAddMap.png" ), tr( "&Duplicate" ), QgisApp::instance(), SLOT( duplicateLayers() ) );
 | 
			
		||||
 | 
			
		||||
  // set layer crs
 | 
			
		||||
  theMenu.addAction( QgsApplication::getThemeIcon( "/mActionSetCRS.png" ), tr( "&Set Layer CRS" ), QgisApp::instance(), SLOT( setLayerCRS() ) );
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -961,6 +961,7 @@ void QgisApp::createActions()
 | 
			
		||||
  connect( mActionLayerSaveAs, SIGNAL( triggered() ), this, SLOT( saveAsFile() ) );
 | 
			
		||||
  connect( mActionLayerSelectionSaveAs, SIGNAL( triggered() ), this, SLOT( saveSelectionAsVectorFile() ) );
 | 
			
		||||
  connect( mActionRemoveLayer, SIGNAL( triggered() ), this, SLOT( removeLayer() ) );
 | 
			
		||||
  connect( mActionDuplicateLayer, SIGNAL( triggered() ), this, SLOT( duplicateLayers() ) );
 | 
			
		||||
  connect( mActionSetLayerCRS, SIGNAL( triggered() ), this, SLOT( setLayerCRS() ) );
 | 
			
		||||
  connect( mActionSetProjectCRSFromLayer, SIGNAL( triggered() ), this, SLOT( setProjectCRSFromLayer() ) );
 | 
			
		||||
  connect( mActionLayerProperties, SIGNAL( triggered() ), this, SLOT( layerProperties() ) );
 | 
			
		||||
@ -1630,6 +1631,7 @@ void QgisApp::setTheme( QString theThemeName )
 | 
			
		||||
  mActionAddMssqlLayer->setIcon( QgsApplication::getThemeIcon( "/mActionAddMssqlLayer.png" ) );
 | 
			
		||||
#endif
 | 
			
		||||
  mActionRemoveLayer->setIcon( QgsApplication::getThemeIcon( "/mActionRemoveLayer.png" ) );
 | 
			
		||||
  mActionDuplicateLayer->setIcon( QgsApplication::getThemeIcon( "/mActionAddMap.png" ) );
 | 
			
		||||
  mActionSetLayerCRS->setIcon( QgsApplication::getThemeIcon( "/mActionSetLayerCRS.png" ) );
 | 
			
		||||
  mActionSetProjectCRSFromLayer->setIcon( QgsApplication::getThemeIcon( "/mActionSetProjectCRSFromLayer.png" ) );
 | 
			
		||||
  mActionNewVectorLayer->setIcon( QgsApplication::getThemeIcon( "/mActionNewVectorLayer.png" ) );
 | 
			
		||||
@ -5341,6 +5343,77 @@ void QgisApp::removeLayer()
 | 
			
		||||
  mMapCanvas->refresh();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QgisApp::duplicateLayers( QList<QgsMapLayer *> lyrList )
 | 
			
		||||
{
 | 
			
		||||
  if ( mMapCanvas && mMapCanvas->isDrawing() )
 | 
			
		||||
  {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ( !mMapLegend )
 | 
			
		||||
  {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  QList<QgsMapLayer *> selectedLyrs = lyrList.empty() ? mMapLegend->selectedLayers() : lyrList;
 | 
			
		||||
  if ( selectedLyrs.empty() )
 | 
			
		||||
  {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  mMapCanvas->freeze();
 | 
			
		||||
  QgsMapLayer *dupLayer;
 | 
			
		||||
  foreach ( QgsMapLayer * selectedLyr, selectedLyrs )
 | 
			
		||||
  {
 | 
			
		||||
    dupLayer = 0;
 | 
			
		||||
    QString layerDupName = selectedLyr->name() + " " + tr( "copy" );
 | 
			
		||||
 | 
			
		||||
    // duplicate the layer's basic parameters
 | 
			
		||||
 | 
			
		||||
    QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer*>( selectedLyr );
 | 
			
		||||
    // TODO: check for other layer types that won't duplicate correctly
 | 
			
		||||
    // currently memory and plugin layers are skipped
 | 
			
		||||
    if ( vlayer && vlayer->storageType() != "Memory storage" )
 | 
			
		||||
    {
 | 
			
		||||
      dupLayer = new QgsVectorLayer( vlayer->source(), layerDupName, vlayer->providerType() );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ( !dupLayer )
 | 
			
		||||
    {
 | 
			
		||||
      QgsRasterLayer *rlayer = qobject_cast<QgsRasterLayer*>( selectedLyr );
 | 
			
		||||
      if ( rlayer )
 | 
			
		||||
      {
 | 
			
		||||
        dupLayer = new QgsRasterLayer( rlayer->source(), layerDupName );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ( dupLayer && !dupLayer->isValid() )
 | 
			
		||||
    {
 | 
			
		||||
      QgsDebugMsg( "Duplicated layer was invalid" );
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ( !dupLayer )
 | 
			
		||||
    {
 | 
			
		||||
      QMessageBox::information( this,
 | 
			
		||||
                                tr( "Unsupported Layer" ),
 | 
			
		||||
                                tr( "%1\n\nDuplication of layer type is unsupported." ).arg( selectedLyr->name() ) );
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // add layer to project and layer registry
 | 
			
		||||
    addMapLayer( dupLayer );
 | 
			
		||||
 | 
			
		||||
    // duplicate the layer style
 | 
			
		||||
    copyStyle( selectedLyr );
 | 
			
		||||
    pasteStyle( dupLayer );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  dupLayer = 0;
 | 
			
		||||
  mMapCanvas->freeze( false );
 | 
			
		||||
  mMapCanvas->refresh();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QgisApp::setLayerCRS()
 | 
			
		||||
{
 | 
			
		||||
  if ( mMapCanvas && mMapCanvas->isDrawing() )
 | 
			
		||||
@ -6833,6 +6906,7 @@ void QgisApp::selectionChanged( QgsMapLayer *layer )
 | 
			
		||||
void QgisApp::legendLayerSelectionChanged( void )
 | 
			
		||||
{
 | 
			
		||||
  mActionRemoveLayer->setEnabled( mMapLegend && mMapLegend->selectedLayers().size() > 0 );
 | 
			
		||||
  mActionDuplicateLayer->setEnabled( mMapLegend && mMapLegend->selectedLayers().size() > 0 );
 | 
			
		||||
  mActionSetLayerCRS->setEnabled( mMapLegend && mMapLegend->selectedLayers().size() > 0 );
 | 
			
		||||
  mActionSetProjectCRSFromLayer->setEnabled( mMapLegend && mMapLegend->selectedLayers().size() == 1 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -290,6 +290,8 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
 | 
			
		||||
    QAction *actionLayerSaveAs() { return mActionLayerSaveAs; }
 | 
			
		||||
    QAction *actionLayerSelectionSaveAs() { return mActionLayerSelectionSaveAs; }
 | 
			
		||||
    QAction *actionRemoveLayer() { return mActionRemoveLayer; }
 | 
			
		||||
    /** @note added in 2.0 */
 | 
			
		||||
    QAction *actionDuplicateLayer() { return mActionDuplicateLayer; }
 | 
			
		||||
    QAction *actionSetLayerCRS() { return mActionSetLayerCRS; }
 | 
			
		||||
    QAction *actionSetProjectCRSFromLayer() { return mActionSetProjectCRSFromLayer; }
 | 
			
		||||
    QAction *actionLayerProperties() { return mActionLayerProperties; }
 | 
			
		||||
@ -543,6 +545,9 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
 | 
			
		||||
    void userCenter();
 | 
			
		||||
    //! Remove a layer from the map and legend
 | 
			
		||||
    void removeLayer();
 | 
			
		||||
    /** Duplicate map layer(s) in legend
 | 
			
		||||
     * @note added in 2.0 */
 | 
			
		||||
    void duplicateLayers( const QList<QgsMapLayer *> lyrList = QList<QgsMapLayer *>() );
 | 
			
		||||
    //! Set CRS of a layer
 | 
			
		||||
    void setLayerCRS();
 | 
			
		||||
    //! Assign layer CRS to project
 | 
			
		||||
 | 
			
		||||
@ -465,6 +465,7 @@ QAction *QgisAppInterface::actionToggleEditing() { return qgis->actionToggleEdit
 | 
			
		||||
QAction *QgisAppInterface::actionLayerSaveAs() { return qgis->actionLayerSaveAs(); }
 | 
			
		||||
QAction *QgisAppInterface::actionLayerSelectionSaveAs() { return qgis->actionLayerSelectionSaveAs(); }
 | 
			
		||||
QAction *QgisAppInterface::actionRemoveLayer() { return qgis->actionRemoveLayer(); }
 | 
			
		||||
QAction *QgisAppInterface::actionDuplicateLayer() { return qgis->actionDuplicateLayer(); }
 | 
			
		||||
QAction *QgisAppInterface::actionLayerProperties() { return qgis->actionLayerProperties(); }
 | 
			
		||||
QAction *QgisAppInterface::actionLayerSeparator2() { return 0; }
 | 
			
		||||
QAction *QgisAppInterface::actionAddToOverview() { return qgis->actionAddToOverview(); }
 | 
			
		||||
 | 
			
		||||
@ -313,6 +313,8 @@ class QgisAppInterface : public QgisInterface
 | 
			
		||||
    virtual QAction *actionLayerSaveAs();
 | 
			
		||||
    virtual QAction *actionLayerSelectionSaveAs();
 | 
			
		||||
    virtual QAction *actionRemoveLayer();
 | 
			
		||||
    /** @note added in 2.0 */
 | 
			
		||||
    virtual QAction *actionDuplicateLayer();
 | 
			
		||||
    virtual QAction *actionLayerProperties();
 | 
			
		||||
    virtual QAction *actionLayerSeparator2();
 | 
			
		||||
    virtual QAction *actionAddToOverview();
 | 
			
		||||
 | 
			
		||||
@ -466,6 +466,8 @@ class GUI_EXPORT QgisInterface : public QObject
 | 
			
		||||
    virtual QAction *actionLayerSaveAs() = 0;
 | 
			
		||||
    virtual QAction *actionLayerSelectionSaveAs() = 0;
 | 
			
		||||
    virtual QAction *actionRemoveLayer() = 0;
 | 
			
		||||
    /** @note added in 2.0 */
 | 
			
		||||
    virtual QAction *actionDuplicateLayer() = 0;
 | 
			
		||||
    virtual QAction *actionLayerProperties() = 0;
 | 
			
		||||
#ifndef Q_MOC_RUN
 | 
			
		||||
    Q_DECL_DEPRECATED
 | 
			
		||||
 | 
			
		||||
@ -168,6 +168,7 @@
 | 
			
		||||
    <addaction name="mActionLayerSaveAs"/>
 | 
			
		||||
    <addaction name="mActionLayerSelectionSaveAs"/>
 | 
			
		||||
    <addaction name="mActionRemoveLayer"/>
 | 
			
		||||
    <addaction name="mActionDuplicateLayer"/>
 | 
			
		||||
    <addaction name="mActionSetLayerCRS"/>
 | 
			
		||||
    <addaction name="mActionSetProjectCRSFromLayer"/>
 | 
			
		||||
    <addaction name="mActionLayerProperties"/>
 | 
			
		||||
@ -1821,6 +1822,18 @@ Acts on currently active editable layer</string>
 | 
			
		||||
    <string>Html Annotation</string>
 | 
			
		||||
   </property>
 | 
			
		||||
  </action>
 | 
			
		||||
  <action name="mActionDuplicateLayer">
 | 
			
		||||
   <property name="icon">
 | 
			
		||||
    <iconset resource="../../images/images.qrc">
 | 
			
		||||
     <normaloff>:/images/themes/default/mActionAddMap.png</normaloff>:/images/themes/default/mActionAddMap.png</iconset>
 | 
			
		||||
   </property>
 | 
			
		||||
   <property name="text">
 | 
			
		||||
    <string>Duplicate Layer(s)</string>
 | 
			
		||||
   </property>
 | 
			
		||||
   <property name="toolTip">
 | 
			
		||||
    <string>Duplicate Layer(s)</string>
 | 
			
		||||
   </property>
 | 
			
		||||
  </action>
 | 
			
		||||
 </widget>
 | 
			
		||||
 <resources>
 | 
			
		||||
  <include location="../../images/images.qrc"/>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user