Skip to content

Commit

Permalink
Merge pull request #33950 from DelazJ/renameMapTheme
Browse files Browse the repository at this point in the history
[feature] Allow renaming of the current map theme
  • Loading branch information
m-kuhn committed Apr 23, 2020
2 parents f7cc8a2 + 9fc5985 commit 5d45b71
Show file tree
Hide file tree
Showing 14 changed files with 144 additions and 4 deletions.
19 changes: 17 additions & 2 deletions python/core/auto_generated/qgsmapthemecollection.sip.in
Expand Up @@ -186,14 +186,22 @@ Updates a map theme within the collection.

void removeMapTheme( const QString &name );
%Docstring
Remove an existing map theme from collection.
Removes an existing map theme from collection.

.. versionadded:: 3.0
%End

bool renameMapTheme( const QString &name, const QString &newName );
%Docstring
Renames the existing map theme called ``name`` to ``newName``.
Returns ``True`` if the rename was successful, or ``False`` if it failed (e.g. due to a duplicate name for ``newName``).

.. versionadded:: 3.14
%End

void clear();
%Docstring
Remove all map themes from the collection.
Removes all map themes from the collection.
%End

QStringList mapThemes() const;
Expand Down Expand Up @@ -324,6 +332,13 @@ Emitted when map themes within the collection are changed.
Emitted when a map theme changes definition.

.. versionadded:: 3.0
%End

void mapThemeRenamed( const QString &name, const QString &newName );
%Docstring
Emitted when a map theme within the collection is renamed.

.. versionadded:: 3.14
%End

void projectChanged();
Expand Down
9 changes: 9 additions & 0 deletions src/app/3d/qgs3dmapcanvasdockwidget.cpp
Expand Up @@ -104,6 +104,7 @@ Qgs3DMapCanvasDockWidget::Qgs3DMapCanvasDockWidget( QWidget *parent )
// Map Theme Menu
mMapThemeMenu = new QMenu();
connect( mMapThemeMenu, &QMenu::aboutToShow, this, &Qgs3DMapCanvasDockWidget::mapThemeMenuAboutToShow );
connect( QgsProject::instance()->mapThemeCollection(), &QgsMapThemeCollection::mapThemeRenamed, this, &Qgs3DMapCanvasDockWidget::currentMapThemeRenamed );

mBtnMapThemes = new QToolButton();
mBtnMapThemes->setAutoRaise( true );
Expand Down Expand Up @@ -345,3 +346,11 @@ void Qgs3DMapCanvasDockWidget::mapThemeMenuAboutToShow()
}
mMapThemeMenu->addActions( mMapThemeMenuPresetActions );
}

void Qgs3DMapCanvasDockWidget::currentMapThemeRenamed( const QString &theme, const QString &newTheme )
{
if ( theme == mCanvas->map()->terrainMapTheme() )
{
mCanvas->map()->setTerrainMapTheme( newTheme );
}
}
2 changes: 2 additions & 0 deletions src/app/3d/qgs3dmapcanvasdockwidget.h
Expand Up @@ -65,6 +65,8 @@ class APP_EXPORT Qgs3DMapCanvasDockWidget : public QgsDockWidget
void onMainCanvasColorChanged();
void onTotalPendingJobsCountChanged();
void mapThemeMenuAboutToShow();
//! Renames the active map theme called \a theme to \a newTheme
void currentMapThemeRenamed( const QString &theme, const QString &newTheme );

private:
Qgs3DMapCanvas *mCanvas = nullptr;
Expand Down
10 changes: 10 additions & 0 deletions src/app/qgsmapcanvasdockwidget.cpp
Expand Up @@ -227,6 +227,8 @@ QgsMapCanvasDockWidget::QgsMapCanvasDockWidget( const QString &name, QWidget *pa
if ( mSyncExtentRadio->isChecked() )
syncViewCenter( mMainCanvas );
} );

connect( QgsProject::instance()->mapThemeCollection(), &QgsMapThemeCollection::mapThemeRenamed, this, &QgsMapCanvasDockWidget::currentMapThemeRenamed );
}

void QgsMapCanvasDockWidget::setMainCanvas( QgsMapCanvas *canvas )
Expand Down Expand Up @@ -441,6 +443,14 @@ void QgsMapCanvasDockWidget::menuAboutToShow()
mMenu->addActions( mMenuPresetActions );
}

void QgsMapCanvasDockWidget::currentMapThemeRenamed( const QString &theme, const QString &newTheme )
{
if ( theme == mMapCanvas->theme() )
{
mMapCanvas->setTheme( newTheme );
}
}

void QgsMapCanvasDockWidget::settingsMenuAboutToShow()
{
whileBlocking( mActionShowAnnotations )->setChecked( mMapCanvas->annotationsVisible() );
Expand Down
2 changes: 2 additions & 0 deletions src/app/qgsmapcanvasdockwidget.h
Expand Up @@ -157,6 +157,8 @@ class APP_EXPORT QgsMapCanvasDockWidget : public QgsDockWidget, private Ui::QgsM
void mapExtentChanged();
void mapCrsChanged();
void menuAboutToShow();
//! Renames the active map theme called \a theme to \a newTheme
void currentMapThemeRenamed( const QString &theme, const QString &newTheme );
void settingsMenuAboutToShow();
void syncMarker( const QgsPointXY &p );
void mapScaleChanged();
Expand Down
28 changes: 28 additions & 0 deletions src/app/qgsmapthemes.cpp
Expand Up @@ -49,6 +49,7 @@ QgsMapThemes::QgsMapThemes()

mReplaceMenu = new QMenu( tr( "Replace Theme" ) );
mMenu->addMenu( mReplaceMenu );
mActionRenameCurrentPreset = mMenu->addAction( tr( "Rename Current Theme…" ), this, &QgsMapThemes::renameCurrentPreset );
mActionAddPreset = mMenu->addAction( tr( "Add Theme…" ), this, [ = ] { addPreset(); } );
mMenuSeparator = mMenu->addSeparator();

Expand Down Expand Up @@ -140,6 +141,32 @@ void QgsMapThemes::applyState( const QString &presetName )
QgsProject::instance()->mapThemeCollection()->applyTheme( presetName, root, model );
}

void QgsMapThemes::renameCurrentPreset()
{
QgsMapThemeCollection::MapThemeRecord mapTheme = currentState();
QStringList existingNames = QgsProject::instance()->mapThemeCollection()->mapThemes();

for ( QAction *actionPreset : qgis::as_const( mMenuPresetActions ) )
{
if ( actionPreset->isChecked() )
{
QgsNewNameDialog dlg(
tr( "theme" ),
tr( "%1" ).arg( actionPreset->text() ),
QStringList(), existingNames, QRegExp(), Qt::CaseInsensitive, mMenu );

dlg.setWindowTitle( tr( "Rename Map Theme" ) );
dlg.setHintString( tr( "Enter the new name of the map theme" ) );
dlg.setOverwriteEnabled( false );
dlg.setConflictingNameWarning( tr( "A theme with this name already exists." ) );
if ( dlg.exec() != QDialog::Accepted || dlg.name().isEmpty() )
return;

QgsProject::instance()->mapThemeCollection()->renameMapTheme( actionPreset->text(), dlg.name() );
}
}
}

void QgsMapThemes::removeCurrentPreset()
{
for ( QAction *actionPreset : qgis::as_const( mMenuPresetActions ) )
Expand Down Expand Up @@ -189,4 +216,5 @@ void QgsMapThemes::menuAboutToShow()

mActionAddPreset->setEnabled( !hasCurrent );
mActionRemoveCurrentPreset->setEnabled( hasCurrent );
mActionRenameCurrentPreset->setEnabled( hasCurrent );
}
4 changes: 4 additions & 0 deletions src/app/qgsmapthemes.h
Expand Up @@ -65,6 +65,9 @@ class APP_EXPORT QgsMapThemes : public QObject
//! Handles removal of current preset from the project's collection
void removeCurrentPreset();

//! Handles renaming of the current map theme
void renameCurrentPreset();

//! Handles creation of preset menu
void menuAboutToShow();

Expand All @@ -91,6 +94,7 @@ class APP_EXPORT QgsMapThemes : public QObject
QAction *mMenuSeparator = nullptr;
QAction *mActionAddPreset = nullptr;
QAction *mActionRemoveCurrentPreset = nullptr;
QAction *mActionRenameCurrentPreset = nullptr;
QList<QAction *> mMenuPresetActions;
QList<QAction *> mMenuReplaceActions;
};
Expand Down
9 changes: 9 additions & 0 deletions src/core/layout/qgslayoutitemmap.cpp
Expand Up @@ -1825,6 +1825,14 @@ void QgsLayoutItemMap::mapThemeChanged( const QString &theme )
mCachedLayerStyleOverridesPresetName.clear(); // force cache regeneration at next redraw
}

void QgsLayoutItemMap::currentMapThemeRenamed( const QString &theme, const QString &newTheme )
{
if ( theme == mFollowVisibilityPresetName )
{
mFollowVisibilityPresetName = newTheme;
}
}

void QgsLayoutItemMap::connectUpdateSlot()
{
//connect signal from layer registry to update in case of new or deleted layers
Expand Down Expand Up @@ -1867,6 +1875,7 @@ void QgsLayoutItemMap::connectUpdateSlot()
} );

connect( project->mapThemeCollection(), &QgsMapThemeCollection::mapThemeChanged, this, &QgsLayoutItemMap::mapThemeChanged );
connect( project->mapThemeCollection(), &QgsMapThemeCollection::mapThemeRenamed, this, &QgsLayoutItemMap::currentMapThemeRenamed );
}

QTransform QgsLayoutItemMap::layoutToMapCoordsTransform() const
Expand Down
3 changes: 3 additions & 0 deletions src/core/layout/qgslayoutitemmap.h
Expand Up @@ -637,6 +637,9 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem, public QgsTemporalRan

void mapThemeChanged( const QString &theme );

//! Renames the active map theme called \a theme to \a newTheme
void currentMapThemeRenamed( const QString &theme, const QString &newTheme );

//! Create cache image
void recreateCachedImageInBackground();

Expand Down
13 changes: 13 additions & 0 deletions src/core/qgsmapthemecollection.cpp
Expand Up @@ -281,6 +281,19 @@ void QgsMapThemeCollection::update( const QString &name, const MapThemeRecord &s
emit mapThemesChanged();
}

bool QgsMapThemeCollection::renameMapTheme( const QString &name, const QString &newName )
{
if ( !mMapThemes.contains( name ) || mMapThemes.contains( newName ) )
return false;

const MapThemeRecord state = mMapThemes[name];
const MapThemeRecord newState = state;
insert( newName, newState );
emit mapThemeRenamed( name, newName );
removeMapTheme( name );
return true;
}

void QgsMapThemeCollection::removeMapTheme( const QString &name )
{
if ( !mMapThemes.contains( name ) )
Expand Down
17 changes: 15 additions & 2 deletions src/core/qgsmapthemecollection.h
Expand Up @@ -257,12 +257,19 @@ class CORE_EXPORT QgsMapThemeCollection : public QObject
void update( const QString &name, const QgsMapThemeCollection::MapThemeRecord &state );

/**
* Remove an existing map theme from collection.
* Removes an existing map theme from collection.
* \since QGIS 3.0
*/
void removeMapTheme( const QString &name );

//! Remove all map themes from the collection.
/**
* Renames the existing map theme called \a name to \a newName.
* Returns TRUE if the rename was successful, or FALSE if it failed (e.g. due to a duplicate name for \a newName).
* \since QGIS 3.14
*/
bool renameMapTheme( const QString &name, const QString &newName );

//! Removes all map themes from the collection.
void clear();

/**
Expand Down Expand Up @@ -373,6 +380,12 @@ class CORE_EXPORT QgsMapThemeCollection : public QObject
*/
void mapThemeChanged( const QString &theme );

/**
* Emitted when a map theme within the collection is renamed.
* \since QGIS 3.14
*/
void mapThemeRenamed( const QString &name, const QString &newName );

/**
* Emitted when the project changes
*
Expand Down
12 changes: 12 additions & 0 deletions src/gui/qgsmapcanvas.cpp
Expand Up @@ -138,6 +138,7 @@ QgsMapCanvas::QgsMapCanvas( QWidget *parent )
this, &QgsMapCanvas::writeProject );

connect( QgsProject::instance()->mapThemeCollection(), &QgsMapThemeCollection::mapThemeChanged, this, &QgsMapCanvas::mapThemeChanged );
connect( QgsProject::instance()->mapThemeCollection(), &QgsMapThemeCollection::mapThemeRenamed, this, &QgsMapCanvas::mapThemeRenamed );
connect( QgsProject::instance()->mapThemeCollection(), &QgsMapThemeCollection::mapThemesChanged, this, &QgsMapCanvas::projectThemesChanged );

mSettings.setFlag( QgsMapSettings::DrawEditingInfo );
Expand Down Expand Up @@ -615,6 +616,17 @@ void QgsMapCanvas::mapThemeChanged( const QString &theme )
}
}

void QgsMapCanvas::mapThemeRenamed( const QString &theme, const QString &newTheme )
{
if ( mTheme.isEmpty() || theme != mTheme )
{
return;
}

setTheme( newTheme );
refresh();
}

void QgsMapCanvas::rendererJobFinished()
{
QgsDebugMsgLevel( QStringLiteral( "CANVAS finish! %1" ).arg( !mJobCanceled ), 2 );
Expand Down
2 changes: 2 additions & 0 deletions src/gui/qgsmapcanvas.h
Expand Up @@ -835,6 +835,8 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
void refreshMap();

void mapThemeChanged( const QString &theme );
//! Renames the active map theme called \a theme to \a newTheme
void mapThemeRenamed( const QString &theme, const QString &newTheme );

signals:

Expand Down
18 changes: 18 additions & 0 deletions tests/src/python/test_qgsmapcanvas.py
Expand Up @@ -331,6 +331,24 @@ def testMapTheme(self):
# should be different - we should now render project layers
self.assertFalse(self.canvasImageCheck('theme4', 'theme4', canvas))

# set canvas to theme1
canvas.setTheme('theme1')
canvas.refresh()
canvas.waitWhileRendering()
self.assertEqual(canvas.theme(), 'theme1')
themeLayers = theme1.layerRecords()
# rename the active theme
QgsProject.instance().mapThemeCollection().renameMapTheme('theme1', 'theme5')
# canvas theme should now be set to theme5
canvas.refresh()
canvas.waitWhileRendering()
self.assertEqual(canvas.theme(), 'theme5')
# theme5 should render as theme1
theme5 = QgsProject.instance().mapThemeCollection().mapThemeState('theme5')
theme5Layers = theme5.layerRecords()
self.assertEqual(themeLayers, theme5Layers, 'themes are different')
#self.assertTrue(self.canvasImageCheck('theme5', 'theme5', canvas))

def canvasImageCheck(self, name, reference_image, canvas):
self.report += "<h2>Render {}</h2>\n".format(name)
temp_dir = QDir.tempPath() + '/'
Expand Down

0 comments on commit 5d45b71

Please sign in to comment.