Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add dock/undock action to 2d map canvas views
To match the behaviour of 3d canvas views
  • Loading branch information
nyalldawson committed Mar 31, 2023
1 parent 4466318 commit 75b07d4
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 76 deletions.
3 changes: 0 additions & 3 deletions src/app/3d/qgs3dmapcanvaswidget.h
Expand Up @@ -62,9 +62,6 @@ class APP_EXPORT Qgs3DMapCanvasWidget : public QWidget
void setCanvasName( const QString &name );
QString canvasName() const { return mCanvasName; }

signals:
void toggleDockModeRequested( bool docked );

protected:
void resizeEvent( QResizeEvent *event ) override;

Expand Down
103 changes: 64 additions & 39 deletions src/app/qgisapp.cpp
Expand Up @@ -4611,8 +4611,6 @@ QgsMapCanvas *QgisApp::createNewMapCanvas( const QString &name )
if ( !dock )
return nullptr;

setupDockWidget( dock ); // use default dock position settings

dock->mapCanvas()->setLayers( mMapCanvas->layers() );
dock->mapCanvas()->setExtent( mMapCanvas->extent() );
QgsDebugMsgLevel( QStringLiteral( "QgisApp::createNewMapCanvas -2- : QgsProject::instance()->crs().description[%1]ellipsoid[%2]" ).arg( QgsProject::instance()->crs().description(), QgsProject::instance()->crs().ellipsoidAcronym() ), 3 );
Expand All @@ -4621,7 +4619,7 @@ QgsMapCanvas *QgisApp::createNewMapCanvas( const QString &name )
return dock->mapCanvas();
}

QgsMapCanvasDockWidget *QgisApp::createNewMapCanvasDock( const QString &name )
QgsMapCanvasDockWidget *QgisApp::createNewMapCanvasDock( const QString &name, bool isDocked )
{
const auto canvases = mapCanvases();
for ( QgsMapCanvas *canvas : canvases )
Expand All @@ -4633,8 +4631,7 @@ QgsMapCanvasDockWidget *QgisApp::createNewMapCanvasDock( const QString &name )
}
}

QgsMapCanvasDockWidget *mapCanvasWidget = new QgsMapCanvasDockWidget( name, this );
mapCanvasWidget->setAllowedAreas( Qt::AllDockWidgetAreas );
QgsMapCanvasDockWidget *mapCanvasWidget = new QgsMapCanvasDockWidget( name, this, isDocked );
mapCanvasWidget->setMainCanvas( mMapCanvas );

QgsMapCanvas *mapCanvas = mapCanvasWidget->mapCanvas();
Expand All @@ -4655,16 +4652,22 @@ QgsMapCanvasDockWidget *QgisApp::createNewMapCanvasDock( const QString &name )
Q_UNUSED( canvasItem ) //item is already added automatically to canvas scene
}

markDirty();
mapCanvas->setCustomDropHandlers( mCustomDropHandlers );

markDirty();
connect( mapCanvasWidget, &QgsMapCanvasDockWidget::closed, this, &QgisApp::markDirty );
connect( mapCanvasWidget->dockableWidgetHelper(), &QgsDockableWidgetHelper::closed, this, [ this, mapCanvasWidget]
{
mOpen2DMapViews.remove( mapCanvasWidget );
delete mapCanvasWidget;
markDirty();
} );
connect( mapCanvasWidget, &QgsMapCanvasDockWidget::renameTriggered, this, &QgisApp::renameView );

mOpen2DMapViews.insert( mapCanvasWidget );

return mapCanvasWidget;
}


void QgisApp::setupDockWidget( QDockWidget *dockWidget, bool isFloating, QRect dockGeometry, Qt::DockWidgetArea area )
{
dockWidget->setFloating( isFloating );
Expand Down Expand Up @@ -4695,21 +4698,40 @@ void QgisApp::setupDockWidget( QDockWidget *dockWidget, bool isFloating, QRect d

void QgisApp::closeMapCanvas( const QString &name )
{
for ( QgsMapCanvasDockWidget *w : mOpen2DMapViews )
{
if ( w->mapCanvas()->objectName() == name )
{
w->close();
delete w;
mOpen2DMapViews.remove( w );
return;
}
}

const auto dockWidgets = findChildren< QgsMapCanvasDockWidget * >();
for ( QgsMapCanvasDockWidget *w : dockWidgets )
{
if ( w->mapCanvas()->objectName() == name )
{
w->close();
delete w;
break;
return;
}
}
}

void QgisApp::closeAdditionalMapCanvases()
{
QgsCanvasRefreshBlocker refreshBlocker; // closing docks may cause canvases to resize, and we don't want a map refresh occurring

for ( QgsMapCanvasDockWidget *w : mOpen2DMapViews )
{
w->close();
delete w;
}
mOpen2DMapViews.clear();

const auto dockWidgets = findChildren< QgsMapCanvasDockWidget * >();
for ( QgsMapCanvasDockWidget *w : dockWidgets )
{
Expand Down Expand Up @@ -9452,7 +9474,16 @@ QList<QgsMapCanvas *> QgisApp::mapCanvases()
{
// filter out browser canvases -- they are children of app, but a different
// kind of beast, and here we only want the main canvas or dock canvases
auto canvases = findChildren< QgsMapCanvas * >();
QList<QgsMapCanvas *> canvases = findChildren< QgsMapCanvas * >();

for ( QgsMapCanvasDockWidget *dock : std::as_const( mOpen2DMapViews ) )
{
if ( !canvases.contains( dock->mapCanvas() ) )
{
canvases.append( dock->mapCanvas() );
}
}

canvases.erase( std::remove_if( canvases.begin(), canvases.end(),
[]( QgsMapCanvas * canvas )
{
Expand All @@ -9461,6 +9492,23 @@ QList<QgsMapCanvas *> QgisApp::mapCanvases()
return canvases;
}

QgsMapCanvasDockWidget *QgisApp::getMapCanvas( const QString &name )
{
for ( QgsMapCanvasDockWidget *w : std::as_const( mOpen2DMapViews ) )
{
if ( w->canvasName() == name )
return w;
}

const auto dockWidgets = findChildren< QgsMapCanvasDockWidget * >();
for ( QgsMapCanvasDockWidget *w : dockWidgets )
{
if ( w->canvasName() == name )
return w;
}
return nullptr;
}

QMap< QString, Qgs3DMapScene * > QgisApp::map3DScenes()
{
QMap< QString, Qgs3DMapScene * > res;
Expand Down Expand Up @@ -13038,7 +13086,6 @@ void QgisApp::newMapCanvas()
QgsMapCanvasDockWidget *dock = createNewMapCanvasDock( name );
if ( dock )
{
setupDockWidget( dock, true );
dock->mapCanvas()->setLayers( mMapCanvas->layers() );
dock->mapCanvas()->setExtent( mMapCanvas->extent() );
QgsDebugMsgLevel( QStringLiteral( "QgisApp::newMapCanvas() -4- : QgsProject::instance()->crs().description[%1] ellipsoid[%2]" ).arg( QgsProject::instance()->crs().description(), QgsProject::instance()->crs().ellipsoidAcronym() ), 3 );
Expand Down Expand Up @@ -16047,8 +16094,7 @@ void QgisApp::writeProject( QDomDocument &doc )

// Save the position of the map view docks
QDomElement mapViewNode = doc.createElement( QStringLiteral( "mapViewDocks" ) );
const auto dockWidgets = findChildren< QgsMapCanvasDockWidget * >();
for ( QgsMapCanvasDockWidget *w : dockWidgets )
for ( QgsMapCanvasDockWidget *w : std::as_const( mOpen2DMapViews ) )
{
QDomElement node = doc.createElement( QStringLiteral( "view" ) );
node.setAttribute( QStringLiteral( "name" ), w->mapCanvas()->objectName() );
Expand All @@ -16059,7 +16105,7 @@ void QgisApp::writeProject( QDomDocument &doc )
node.setAttribute( QStringLiteral( "scaleFactor" ), w->scaleFactor() );
node.setAttribute( QStringLiteral( "showLabels" ), w->labelsVisible() );
node.setAttribute( QStringLiteral( "zoomSelected" ), w->isAutoZoomToSelected() );
writeDockWidgetSettings( w, node );
w->dockableWidgetHelper()->writeXml( node );
mapViewNode.appendChild( node );
}
qgisNode.appendChild( mapViewNode );
Expand All @@ -16078,16 +16124,6 @@ void QgisApp::writeProject( QDomDocument &doc )
projectChanged( doc );
}

void QgisApp::writeDockWidgetSettings( QDockWidget *dockWidget, QDomElement &elem )
{
elem.setAttribute( QStringLiteral( "x" ), dockWidget->x() );
elem.setAttribute( QStringLiteral( "y" ), dockWidget->y() );
elem.setAttribute( QStringLiteral( "width" ), dockWidget->width() );
elem.setAttribute( QStringLiteral( "height" ), dockWidget->height() );
elem.setAttribute( QStringLiteral( "floating" ), dockWidget->isFloating() );
elem.setAttribute( QStringLiteral( "area" ), dockWidgetArea( dockWidget ) );
}

bool QgisApp::askUserForDatumTransform( const QgsCoordinateReferenceSystem &sourceCrs, const QgsCoordinateReferenceSystem &destinationCrs, const QgsMapLayer *layer )
{
Q_ASSERT( qApp->thread() == QThread::currentThread() );
Expand Down Expand Up @@ -16122,19 +16158,6 @@ bool QgisApp::askUserForDatumTransform( const QgsCoordinateReferenceSystem &sour
return QgsDatumTransformDialog::run( sourceCrs, destinationCrs, this, mMapCanvas, title );
}

void QgisApp::readDockWidgetSettings( QDockWidget *dockWidget, const QDomElement &elem )
{
int x = elem.attribute( QStringLiteral( "x" ), QStringLiteral( "0" ) ).toInt();
int y = elem.attribute( QStringLiteral( "y" ), QStringLiteral( "0" ) ).toInt();
int w = elem.attribute( QStringLiteral( "width" ), QStringLiteral( "400" ) ).toInt();
int h = elem.attribute( QStringLiteral( "height" ), QStringLiteral( "400" ) ).toInt();
bool floating = elem.attribute( QStringLiteral( "floating" ), QStringLiteral( "0" ) ).toInt();
Qt::DockWidgetArea area = static_cast< Qt::DockWidgetArea >( elem.attribute( QStringLiteral( "area" ), QString::number( Qt::RightDockWidgetArea ) ).toInt() );

setupDockWidget( dockWidget, floating, QRect( x, y, w, h ), area );
}


void QgisApp::readProject( const QDomDocument &doc )
{
projectChanged( doc );
Expand Down Expand Up @@ -16165,9 +16188,11 @@ void QgisApp::readProject( const QDomDocument &doc )
double scaleFactor = elementNode.attribute( QStringLiteral( "scaleFactor" ), QStringLiteral( "1" ) ).toDouble();
bool showLabels = elementNode.attribute( QStringLiteral( "showLabels" ), QStringLiteral( "1" ) ).toInt();
bool zoomSelected = elementNode.attribute( QStringLiteral( "zoomSelected" ), QStringLiteral( "0" ) ).toInt();
bool isDocked = elementNode.attribute( QStringLiteral( "isDocked" ), QStringLiteral( "1" ) ).toInt() == 1;

QgsMapCanvasDockWidget *mapCanvasDock = createNewMapCanvasDock( mapName, isDocked );
mapCanvasDock->dockableWidgetHelper()->readXml( elementNode );

QgsMapCanvasDockWidget *mapCanvasDock = createNewMapCanvasDock( mapName );
readDockWidgetSettings( mapCanvasDock, elementNode );
QgsMapCanvas *mapCanvas = mapCanvasDock->mapCanvas();
mapCanvasDock->setViewCenterSynchronized( synced );
mapCanvasDock->setCursorMarkerVisible( showCursor );
Expand Down
22 changes: 9 additions & 13 deletions src/app/qgisapp.h
Expand Up @@ -266,6 +266,11 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
*/
QList< QgsMapCanvas * > mapCanvases();

/**
* Returns the 2D map canvas dock widget named \a name
*/
QgsMapCanvasDockWidget *getMapCanvas( const QString &name );

/**
* Returns a map of all 3D map scenes (by name) open in the app.
*/
Expand All @@ -282,7 +287,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
* unwanted map redraws. Callers must manually unfreeze the map canvas when they have finished
* setting the initial state of the canvas and are ready for it to begin rendering.
*/
QgsMapCanvasDockWidget *createNewMapCanvasDock( const QString &name );
QgsMapCanvasDockWidget *createNewMapCanvasDock( const QString &name, bool isDocked = true );

/**
* Closes the additional map canvas with matching \a name.
Expand Down Expand Up @@ -1696,6 +1701,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow

//! Creates a new map canvas view
void newMapCanvas();

//! Creates a new 3D map canvas view
void new3DMapCanvas();

Expand Down Expand Up @@ -2326,18 +2332,6 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
void setupDockWidget( QDockWidget *dockWidget, bool isFloating = false, QRect dockGeometry = QRect(),
Qt::DockWidgetArea area = Qt::RightDockWidgetArea );

/**
* Reads dock widget's position settings from a DOM element and calls setupDockWidget()
* \sa writeDockWidgetSettings()
*/
void readDockWidgetSettings( QDockWidget *dockWidget, const QDomElement &elem );

/**
* Writes dock widget's position settings to a DOM element
* \sa readDockWidgetSettings()
*/
void writeDockWidgetSettings( QDockWidget *dockWidget, QDomElement &elem );

#ifdef HAVE_3D

/**
Expand Down Expand Up @@ -2738,6 +2732,8 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QMap< QString, QToolButton * > mAnnotationItemGroupToolButtons;
QAction *mAnnotationsItemInsertBefore = nullptr; // Used to insert annotation items at the appropriate location in the annotations toolbar

QSet<QgsMapCanvasDockWidget *> mOpen2DMapViews;

#ifdef HAVE_3D
QSet<Qgs3DMapCanvasWidget *> mOpen3DMapViews;
#endif
Expand Down
38 changes: 33 additions & 5 deletions src/app/qgsmapcanvasdockwidget.cpp
Expand Up @@ -29,23 +29,26 @@
#include "qgsrubberband.h"
#include "qgsvectorlayer.h"
#include "qgsapplication.h"
#include "qgsdockablewidgethelper.h"

#include <QMessageBox>
#include <QMenu>
#include <QToolBar>
#include <QToolButton>
#include <QRadioButton>


QgsMapCanvasDockWidget::QgsMapCanvasDockWidget( const QString &name, QWidget *parent )
: QgsDockWidget( parent )
QgsMapCanvasDockWidget::QgsMapCanvasDockWidget( const QString &name, QWidget *parent, bool isDocked )
: QWidget( parent )
, mCanvasName( name )
{
setupUi( this );
setAttribute( Qt::WA_DeleteOnClose );

mContents->layout()->setContentsMargins( 0, 0, 0, 0 );
static_cast< QVBoxLayout * >( mContents->layout() )->setSpacing( 0 );
layout()->setContentsMargins( 0, 0, 0, 0 );
qgis::down_cast< QVBoxLayout * >( layout() )->setSpacing( 0 );

setWindowTitle( name );
setWindowTitle( mCanvasName );
mToolbar->setIconSize( QgisApp::instance()->iconSize( true ) );

mMapCanvas = new QgsMapCanvas( this );
Expand Down Expand Up @@ -240,6 +243,25 @@ QgsMapCanvasDockWidget::QgsMapCanvasDockWidget( const QString &name, QWidget *pa
} );

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

mDockableWidgetHelper = new QgsDockableWidgetHelper( isDocked, mCanvasName, this, QgisApp::instance(), Qt::RightDockWidgetArea );
QToolButton *toggleButton = mDockableWidgetHelper->createDockUndockToolButton();
toggleButton->setToolTip( tr( "Dock 2D Map View" ) );
mToolbar->addWidget( toggleButton );
connect( mDockableWidgetHelper, &QgsDockableWidgetHelper::closed, this, [ = ]()
{
close();
} );
}

QgsMapCanvasDockWidget::~QgsMapCanvasDockWidget()
{
delete mDockableWidgetHelper;
}

QgsDockableWidgetHelper *QgsMapCanvasDockWidget::dockableWidgetHelper()
{
return mDockableWidgetHelper;
}

void QgsMapCanvasDockWidget::setMainCanvas( QgsMapCanvas *canvas )
Expand Down Expand Up @@ -268,6 +290,12 @@ QgsMapCanvas *QgsMapCanvasDockWidget::mapCanvas()
return mMapCanvas;
}

void QgsMapCanvasDockWidget::setCanvasName( const QString &name )
{
mCanvasName = name;
mDockableWidgetHelper->setWindowTitle( name );
}

void QgsMapCanvasDockWidget::setViewCenterSynchronized( bool enabled )
{
mSyncExtentCheck->setChecked( enabled );
Expand Down

0 comments on commit 75b07d4

Please sign in to comment.