Skip to content

Commit

Permalink
Merge pull request #52321 from YoannQDQ/clear-recent-crs
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kuhn committed Apr 26, 2023
2 parents 3adce04 + 3c7741a commit 69a2bb8
Show file tree
Hide file tree
Showing 7 changed files with 241 additions and 55 deletions.
Expand Up @@ -1123,6 +1123,20 @@ Pushes a recently used CRS to the top of the recent CRS list.
.. versionadded:: 3.10.3
%End

static void removeRecentCoordinateReferenceSystem( const QgsCoordinateReferenceSystem &crs );
%Docstring
Removes a CRS from the list of recently used CRS.

.. versionadded:: 3.32
%End

static void clearRecentCoordinateReferenceSystems();
%Docstring
Cleans the list of recently used CRS.

.. versionadded:: 3.32
%End


static void invalidateCache();
%Docstring
Expand Down
11 changes: 11 additions & 0 deletions python/gui/auto_generated/qgsprojectionselectiontreewidget.sip.in
Expand Up @@ -155,6 +155,14 @@ Marks the current selected projection for push to front of recent projections li
Has no effect since QGIS 3.20
%End


void clearRecentCrs();
%Docstring
Clear the list of recent projections.

.. versionadded:: 3.32
%End

signals:

void crsSelected();
Expand Down Expand Up @@ -190,6 +198,9 @@ Emitted when the selection in the tree is changed from a valid selection to an i
virtual void resizeEvent( QResizeEvent *event );


virtual bool eventFilter( QObject *obj, QEvent *ev );


};

/************************************************************************
Expand Down
34 changes: 34 additions & 0 deletions src/core/proj/qgscoordinatereferencesystem.cpp
Expand Up @@ -2942,6 +2942,40 @@ void QgsCoordinateReferenceSystem::pushRecentCoordinateReferenceSystem( const Qg
settings.setValue( QStringLiteral( "UI/recentProjectionsProj4" ), proj );
}


void QgsCoordinateReferenceSystem::removeRecentCoordinateReferenceSystem( const QgsCoordinateReferenceSystem &crs )
{
if ( crs.srsid() == 0 || !crs.isValid() )
return;

QList<QgsCoordinateReferenceSystem> recent = recentCoordinateReferenceSystems();
recent.removeAll( crs );
QStringList authids;
authids.reserve( recent.size() );
QStringList proj;
proj.reserve( recent.size() );
QStringList wkt;
wkt.reserve( recent.size() );
for ( const QgsCoordinateReferenceSystem &c : std::as_const( recent ) )
{
authids << c.authid();
proj << c.toProj();
wkt << c.toWkt( WKT_PREFERRED );
}
QgsSettings settings;
settings.setValue( QStringLiteral( "UI/recentProjectionsAuthId" ), authids );
settings.setValue( QStringLiteral( "UI/recentProjectionsWkt" ), wkt );
settings.setValue( QStringLiteral( "UI/recentProjectionsProj4" ), proj );
}

void QgsCoordinateReferenceSystem::clearRecentCoordinateReferenceSystems()
{
QgsSettings settings;
settings.remove( QStringLiteral( "UI/recentProjectionsAuthId" ) );
settings.remove( QStringLiteral( "UI/recentProjectionsWkt" ) );
settings.remove( QStringLiteral( "UI/recentProjectionsProj4" ) );
}

void QgsCoordinateReferenceSystem::invalidateCache( bool disableCache )
{
sSrIdCacheLock()->lockForWrite();
Expand Down
12 changes: 12 additions & 0 deletions src/core/proj/qgscoordinatereferencesystem.h
Expand Up @@ -1063,6 +1063,18 @@ class CORE_EXPORT QgsCoordinateReferenceSystem
*/
static void pushRecentCoordinateReferenceSystem( const QgsCoordinateReferenceSystem &crs );

/**
* Removes a CRS from the list of recently used CRS.
* \since QGIS 3.32
*/
static void removeRecentCoordinateReferenceSystem( const QgsCoordinateReferenceSystem &crs );

/**
* Cleans the list of recently used CRS.
* \since QGIS 3.32
*/
static void clearRecentCoordinateReferenceSystems();

#ifndef SIP_RUN

/**
Expand Down
156 changes: 124 additions & 32 deletions src/gui/qgsprojectionselectiontreewidget.cpp
Expand Up @@ -28,6 +28,9 @@
#include "qgsunittypes.h"

//qt includes
#include <QAction>
#include <QToolButton>
#include <QMenu>
#include <QFileInfo>
#include <QHeaderView>
#include <QResizeEvent>
Expand Down Expand Up @@ -63,14 +66,41 @@ QgsProjectionSelectionTreeWidget::QgsProjectionSelectionTreeWidget( QWidget *par

// Hide (internal) ID column
lstCoordinateSystems->setColumnHidden( QgisCrsIdColumn, true );

lstRecent->header()->setSectionResizeMode( AuthidColumn, QHeaderView::Stretch );
lstRecent->header()->resizeSection( QgisCrsIdColumn, 0 );
lstRecent->header()->setSectionResizeMode( QgisCrsIdColumn, QHeaderView::Fixed );

// Hide (internal) ID column
lstRecent->setColumnHidden( QgisCrsIdColumn, true );

// Clear Crs Column
lstRecent->header()->setMinimumSectionSize( 10 );
lstRecent->header()->setStretchLastSection( false );
lstRecent->header()->resizeSection( ClearColumn, 20 );

// Clear recent crs context menu
lstRecent->setContextMenuPolicy( Qt::CustomContextMenu );
connect( lstRecent, &QTreeWidget::customContextMenuRequested, this, [this]( const QPoint & pos )
{
// If list is empty, do nothing
if ( lstRecent->topLevelItemCount() == 0 )
return;
QMenu menu;
// Clear selected
QTreeWidgetItem *currentItem = lstRecent->itemAt( pos );
if ( currentItem )
{
QAction *clearSelected = menu.addAction( QgsApplication::getThemeIcon( "/mIconClearItem.svg" ), tr( "Remove selected CRS from recently used CRS" ) );
connect( clearSelected, &QAction::triggered, this, [this, currentItem ] { removeRecentCrsItem( currentItem ); } );
menu.addSeparator();
}
// Clear all
QAction *clearAll = menu.addAction( QgsApplication::getThemeIcon( "/console/iconClearConsole.svg" ), tr( "Clear all recently used CRS" ) );
connect( clearAll, &QAction::triggered, this, &QgsProjectionSelectionTreeWidget::clearRecentCrs );
menu.exec( lstRecent->viewport()->mapToGlobal( pos ) );
} );

// Install event fiter to catch delete key press on the recent crs list
lstRecent->installEventFilter( this );

mRecentProjections = QgsCoordinateReferenceSystem::recentCoordinateReferenceSystems();

mCheckBoxNoProjection->setHidden( true );
Expand Down Expand Up @@ -112,9 +142,10 @@ void QgsProjectionSelectionTreeWidget::resizeEvent( QResizeEvent *event )
lstCoordinateSystems->header()->resizeSection( AuthidColumn, 240 );
lstCoordinateSystems->header()->resizeSection( QgisCrsIdColumn, 0 );

lstRecent->header()->resizeSection( NameColumn, event->size().width() - 240 );
lstRecent->header()->resizeSection( NameColumn, event->size().width() - 260 );
lstRecent->header()->resizeSection( AuthidColumn, 240 );
lstRecent->header()->resizeSection( QgisCrsIdColumn, 0 );
lstRecent->header()->resizeSection( ClearColumn, 20 );
}

void QgsProjectionSelectionTreeWidget::showEvent( QShowEvent *event )
Expand Down Expand Up @@ -146,6 +177,25 @@ void QgsProjectionSelectionTreeWidget::showEvent( QShowEvent *event )
mInitialized = true;
}


bool QgsProjectionSelectionTreeWidget::eventFilter( QObject *obj, QEvent *ev )
{
if ( obj != lstRecent )
return false;

if ( ev->type() != QEvent::KeyPress )
return false;

QKeyEvent *keyEvent = static_cast<QKeyEvent *>( ev );
if ( keyEvent->matches( QKeySequence::Delete ) )
{
removeRecentCrsItem( lstRecent->currentItem() );
return true;
}

return false;
}

QString QgsProjectionSelectionTreeWidget::ogcWmsCrsFilterAsSqlExpression( QSet<QString> *crsFilter )
{
QString sqlExpression = QStringLiteral( "1" ); // it's "SQL" for "true"
Expand Down Expand Up @@ -253,13 +303,25 @@ void QgsProjectionSelectionTreeWidget::insertRecent( const QgsCoordinateReferenc
if ( nodes.isEmpty() )
return;

lstRecent->insertTopLevelItem( 0, new QTreeWidgetItem( lstRecent, QStringList()
<< nodes.first()->text( NameColumn )
<< nodes.first()->text( AuthidColumn )
<< nodes.first()->text( QgisCrsIdColumn ) ) );
QTreeWidgetItem *item = new QTreeWidgetItem( lstRecent, QStringList()
<< nodes.first()->text( NameColumn )
<< nodes.first()->text( AuthidColumn )
<< nodes.first()->text( QgisCrsIdColumn ) );

// Insert clear button in the last column
QToolButton *clearButton = new QToolButton();
clearButton->setIcon( QgsApplication::getThemeIcon( "/mIconClearItem.svg" ) );
clearButton->setAutoRaise( true );
clearButton->setToolTip( tr( "Remove from recently used CRS" ) );
connect( clearButton, &QToolButton::clicked, this, [this, item] { removeRecentCrsItem( item ); } );
lstRecent->setItemWidget( item, ClearColumn, clearButton );


lstRecent->insertTopLevelItem( 0, item );

}

//note this line just returns the projection name!
// note this line just returns the projection name!
QString QgsProjectionSelectionTreeWidget::selectedName()
{
// return the selected wkt name from the list view
Expand Down Expand Up @@ -307,25 +369,19 @@ QgsRectangle QgsProjectionSelectionTreeWidget::previewRect() const
return mAreaCanvas->canvasRect();
}

QString QgsProjectionSelectionTreeWidget::getSelectedExpression( const QString &expression ) const
QString QgsProjectionSelectionTreeWidget::expressionForItem( QTreeWidgetItem *item, const QString &expression ) const
{
// Only return the attribute if there is a node in the tree
// selected that has an srs_id. This prevents error if the user
// selects a top-level node rather than an actual coordinate
// system
//
// Get the selected node and make sure it is a srs andx
// not a top-level projection node
QTreeWidgetItem *lvi = lstCoordinateSystems->currentItem();
if ( !lvi || lvi->text( QgisCrsIdColumn ).isEmpty() )
// Only return the attribute if the selected item that has an srs_id.
// This prevents error if the user selects a top-level node rather
// than an actual coordinate system
if ( !item || item->text( QgisCrsIdColumn ).isEmpty() )
return QString();

//

// Determine if this is a user projection or a system on
// user projection defs all have srs_id >= 100000
//
QString databaseFileName;
if ( lvi->text( QgisCrsIdColumn ).toLong() >= USER_CRS_START_ID )
if ( item->text( QgisCrsIdColumn ).toLong() >= USER_CRS_START_ID )
{
databaseFileName = QgsApplication::qgisUserDatabaseFilePath();
if ( !QFileInfo::exists( databaseFileName ) )
Expand All @@ -338,7 +394,6 @@ QString QgsProjectionSelectionTreeWidget::getSelectedExpression( const QString &
databaseFileName = mSrsDatabaseFileName;
}

//
// set up the database
// XXX We could probably hold the database open for the life of this object,
// assuming that it will never be used anywhere else. Given the low overhead,
Expand All @@ -358,7 +413,7 @@ QString QgsProjectionSelectionTreeWidget::getSelectedExpression( const QString &
sqlite3_stmt *stmt = nullptr;
QString sql = QStringLiteral( "select %1 from tbl_srs where srs_id=%2" )
.arg( expression,
lvi->text( QgisCrsIdColumn ) );
item->text( QgisCrsIdColumn ) );

QgsDebugMsgLevel( QStringLiteral( "Finding selected attribute using : %1" ).arg( sql ), 4 );
rc = sqlite3_prepare( database, sql.toUtf8(), sql.toUtf8().length(), &stmt, &tail );
Expand All @@ -379,36 +434,42 @@ QString QgsProjectionSelectionTreeWidget::getSelectedExpression( const QString &
return attributeValue;
}

QgsCoordinateReferenceSystem QgsProjectionSelectionTreeWidget::crs() const


QgsCoordinateReferenceSystem QgsProjectionSelectionTreeWidget::crsForItem( QTreeWidgetItem *item ) const
{
if ( mCheckBoxNoProjection->isEnabled() && mCheckBoxNoProjection->isChecked() )
return QgsCoordinateReferenceSystem();

if ( !mInitialized && mDeferredLoadCrs.isValid() )
return mDeferredLoadCrs;

const QString srsIdString = getSelectedExpression( QStringLiteral( "srs_id" ) );
const QString srsIdString = expressionForItem( item, QStringLiteral( "srs_id" ) );
if ( !srsIdString.isEmpty() )
{
int srid = srsIdString.toLong();
if ( srid >= USER_CRS_START_ID )
return QgsCoordinateReferenceSystem::fromOgcWmsCrs( QStringLiteral( "USER:%1" ).arg( srid ) );
else
return QgsCoordinateReferenceSystem::fromOgcWmsCrs( getSelectedExpression( QStringLiteral( "upper(auth_name||':'||auth_id)" ) ) );
return QgsCoordinateReferenceSystem::fromOgcWmsCrs( expressionForItem( item, QStringLiteral( "upper(auth_name||':'||auth_id)" ) ) );
}
else
{
// custom CRS
QTreeWidgetItem *lvi = lstCoordinateSystems->currentItem();
if ( lvi && lvi->data( 0, RoleWkt ).isValid() )
return QgsCoordinateReferenceSystem::fromWkt( lvi->data( 0, RoleWkt ).toString() );
else if ( lvi && lvi->data( 0, RoleProj ).isValid() )
return QgsCoordinateReferenceSystem::fromProj( lvi->data( 0, RoleProj ).toString() );
if ( item && item->data( 0, RoleWkt ).isValid() )
return QgsCoordinateReferenceSystem::fromWkt( item->data( 0, RoleWkt ).toString() );
else if ( item && item->data( 0, RoleProj ).isValid() )
return QgsCoordinateReferenceSystem::fromProj( item->data( 0, RoleProj ).toString() );
else
return QgsCoordinateReferenceSystem();
}
}

QgsCoordinateReferenceSystem QgsProjectionSelectionTreeWidget::crs() const
{
return crsForItem( lstCoordinateSystems->currentItem() );
}

void QgsProjectionSelectionTreeWidget::setShowNoProjection( bool show )
{
mCheckBoxNoProjection->setVisible( show );
Expand Down Expand Up @@ -1053,3 +1114,34 @@ void QgsProjectionSelectionTreeWidget::showDBMissingWarning( const QString &file
"Because of this the projection selector will not work…" )
.arg( fileName ) );
}

void QgsProjectionSelectionTreeWidget::clearRecentCrs()
{
// If the list is empty, there is nothing to do
if ( lstRecent->topLevelItemCount() == 0 )
{
return;
}

// Ask for confirmation
if ( QMessageBox::question( this, tr( "Clear Recent CRS" ),
tr( "Are you sure you want to clear the list of recently used coordinate reference system?" ),
QMessageBox::Yes | QMessageBox::No ) != QMessageBox::Yes )
{
return;
}
QgsCoordinateReferenceSystem::clearRecentCoordinateReferenceSystems();
lstRecent->clear();
}


void QgsProjectionSelectionTreeWidget::removeRecentCrsItem( QTreeWidgetItem *item )
{
int index = lstRecent->indexOfTopLevelItem( item );
if ( index == -1 )
return;
QgsCoordinateReferenceSystem crs = crsForItem( item );
QgsCoordinateReferenceSystem::removeRecentCoordinateReferenceSystem( crs );
lstRecent->takeTopLevelItem( index );
delete item;
}

0 comments on commit 69a2bb8

Please sign in to comment.