Merge pull request #52321 from YoannQDQ/clear-recent-crs

This commit is contained in:
Matthias Kuhn 2023-04-26 10:34:03 +02:00 committed by GitHub
commit 69a2bb81f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 241 additions and 55 deletions

View File

@ -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

View File

@ -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();
@ -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 );
};
/************************************************************************

View File

@ -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();

View File

@ -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
/**

View File

@ -28,6 +28,9 @@
#include "qgsunittypes.h"
//qt includes
#include <QAction>
#include <QToolButton>
#include <QMenu>
#include <QFileInfo>
#include <QHeaderView>
#include <QResizeEvent>
@ -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 );
@ -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 )
@ -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"
@ -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
@ -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 ) )
@ -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,
@ -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 );
@ -379,7 +434,9 @@ QString QgsProjectionSelectionTreeWidget::getSelectedExpression( const QString &
return attributeValue;
}
QgsCoordinateReferenceSystem QgsProjectionSelectionTreeWidget::crs() const
QgsCoordinateReferenceSystem QgsProjectionSelectionTreeWidget::crsForItem( QTreeWidgetItem *item ) const
{
if ( mCheckBoxNoProjection->isEnabled() && mCheckBoxNoProjection->isChecked() )
return QgsCoordinateReferenceSystem();
@ -387,28 +444,32 @@ QgsCoordinateReferenceSystem QgsProjectionSelectionTreeWidget::crs() const
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 );
@ -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;
}

View File

@ -145,6 +145,14 @@ class GUI_EXPORT QgsProjectionSelectionTreeWidget : public QWidget, private Ui::
*/
Q_DECL_DEPRECATED void pushProjectionToFront() SIP_DEPRECATED;
/**
* Clear the list of recent projections.
*
* \since QGIS 3.32
*/
void clearRecentCrs();
signals:
/**
@ -178,6 +186,9 @@ class GUI_EXPORT QgsProjectionSelectionTreeWidget : public QWidget, private Ui::
// Used to manage column sizes
void resizeEvent( QResizeEvent *event ) override;
// Used to catch key presses on the recent projections list
bool eventFilter( QObject *obj, QEvent *ev ) override;
private:
/**
@ -236,12 +247,11 @@ class GUI_EXPORT QgsProjectionSelectionTreeWidget : public QWidget, private Ui::
*/
void applySelection( int column = QgsProjectionSelectionTreeWidget::None, QString value = QString() );
/**
* \brief gets an arbitrary sqlite3 expression from the selection
*
* \param e The sqlite3 expression (typically "srid" or "sridid")
*/
QString getSelectedExpression( const QString &e ) const;
//! gets an arbitrary sqlite3 expression from the given item
QString expressionForItem( QTreeWidgetItem *item, const QString &expression ) const;
//! Returns the CRS of the given item
QgsCoordinateReferenceSystem crsForItem( QTreeWidgetItem *item ) const;
QString selectedName();
@ -290,7 +300,7 @@ class GUI_EXPORT QgsProjectionSelectionTreeWidget : public QWidget, private Ui::
//! Has the Recent Projection List been populated?
bool mRecentProjListDone = false;
enum Columns { NameColumn, AuthidColumn, QgisCrsIdColumn, None };
enum Columns { NameColumn, AuthidColumn, QgisCrsIdColumn, ClearColumn, None };
int mSearchColumn = QgsProjectionSelectionTreeWidget::None;
QString mSearchValue;
@ -320,6 +330,8 @@ class GUI_EXPORT QgsProjectionSelectionTreeWidget : public QWidget, private Ui::
void lstCoordinateSystems_currentItemChanged( QTreeWidgetItem *current, QTreeWidgetItem *prev );
void lstRecent_currentItemChanged( QTreeWidgetItem *current, QTreeWidgetItem *prev );
void updateFilter();
void removeRecentCrsItem( QTreeWidgetItem *item );
};
#endif

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>578</width>
<height>654</height>
<height>650</height>
</rect>
</property>
<property name="sizePolicy">
@ -82,17 +82,21 @@
</layout>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Recently Used Coordinate Reference Systems</string>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Recently Used Coordinate Reference Systems</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QSplitter" name="mSplitter">
@ -125,7 +129,7 @@
<bool>true</bool>
</property>
<property name="columnCount">
<number>3</number>
<number>4</number>
</property>
<column>
<property name="text">
@ -142,8 +146,13 @@
<string>ID</string>
</property>
</column>
<column>
<property name="text">
<string/>
</property>
</column>
</widget>
<widget class="QWidget" name="">
<widget class="QWidget" name="layoutWidget">
<layout class="QGridLayout" name="gridLayout">
<property name="horizontalSpacing">
<number>0</number>
@ -223,7 +232,7 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="">
<widget class="QWidget" name="layoutWidget_2">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="topMargin">
<number>0</number>
@ -314,6 +323,8 @@
<tabstop>cbxHideDeprecated</tabstop>
<tabstop>lstCoordinateSystems</tabstop>
</tabstops>
<resources/>
<resources>
<include location="../../images/images.qrc"/>
</resources>
<connections/>
</ui>