Skip to content

Commit 69a2bb8

Browse files
authoredApr 26, 2023
Merge pull request #52321 from YoannQDQ/clear-recent-crs
2 parents 3adce04 + 3c7741a commit 69a2bb8

File tree

7 files changed

+241
-55
lines changed

7 files changed

+241
-55
lines changed
 

‎python/core/auto_generated/proj/qgscoordinatereferencesystem.sip.in

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,6 +1123,20 @@ Pushes a recently used CRS to the top of the recent CRS list.
11231123
.. versionadded:: 3.10.3
11241124
%End
11251125

1126+
static void removeRecentCoordinateReferenceSystem( const QgsCoordinateReferenceSystem &crs );
1127+
%Docstring
1128+
Removes a CRS from the list of recently used CRS.
1129+
1130+
.. versionadded:: 3.32
1131+
%End
1132+
1133+
static void clearRecentCoordinateReferenceSystems();
1134+
%Docstring
1135+
Cleans the list of recently used CRS.
1136+
1137+
.. versionadded:: 3.32
1138+
%End
1139+
11261140

11271141
static void invalidateCache();
11281142
%Docstring

‎python/gui/auto_generated/qgsprojectionselectiontreewidget.sip.in

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,14 @@ Marks the current selected projection for push to front of recent projections li
155155
Has no effect since QGIS 3.20
156156
%End
157157

158+
159+
void clearRecentCrs();
160+
%Docstring
161+
Clear the list of recent projections.
162+
163+
.. versionadded:: 3.32
164+
%End
165+
158166
signals:
159167

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

192200

201+
virtual bool eventFilter( QObject *obj, QEvent *ev );
202+
203+
193204
};
194205

195206
/************************************************************************

‎src/core/proj/qgscoordinatereferencesystem.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2942,6 +2942,40 @@ void QgsCoordinateReferenceSystem::pushRecentCoordinateReferenceSystem( const Qg
29422942
settings.setValue( QStringLiteral( "UI/recentProjectionsProj4" ), proj );
29432943
}
29442944

2945+
2946+
void QgsCoordinateReferenceSystem::removeRecentCoordinateReferenceSystem( const QgsCoordinateReferenceSystem &crs )
2947+
{
2948+
if ( crs.srsid() == 0 || !crs.isValid() )
2949+
return;
2950+
2951+
QList<QgsCoordinateReferenceSystem> recent = recentCoordinateReferenceSystems();
2952+
recent.removeAll( crs );
2953+
QStringList authids;
2954+
authids.reserve( recent.size() );
2955+
QStringList proj;
2956+
proj.reserve( recent.size() );
2957+
QStringList wkt;
2958+
wkt.reserve( recent.size() );
2959+
for ( const QgsCoordinateReferenceSystem &c : std::as_const( recent ) )
2960+
{
2961+
authids << c.authid();
2962+
proj << c.toProj();
2963+
wkt << c.toWkt( WKT_PREFERRED );
2964+
}
2965+
QgsSettings settings;
2966+
settings.setValue( QStringLiteral( "UI/recentProjectionsAuthId" ), authids );
2967+
settings.setValue( QStringLiteral( "UI/recentProjectionsWkt" ), wkt );
2968+
settings.setValue( QStringLiteral( "UI/recentProjectionsProj4" ), proj );
2969+
}
2970+
2971+
void QgsCoordinateReferenceSystem::clearRecentCoordinateReferenceSystems()
2972+
{
2973+
QgsSettings settings;
2974+
settings.remove( QStringLiteral( "UI/recentProjectionsAuthId" ) );
2975+
settings.remove( QStringLiteral( "UI/recentProjectionsWkt" ) );
2976+
settings.remove( QStringLiteral( "UI/recentProjectionsProj4" ) );
2977+
}
2978+
29452979
void QgsCoordinateReferenceSystem::invalidateCache( bool disableCache )
29462980
{
29472981
sSrIdCacheLock()->lockForWrite();

‎src/core/proj/qgscoordinatereferencesystem.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,6 +1063,18 @@ class CORE_EXPORT QgsCoordinateReferenceSystem
10631063
*/
10641064
static void pushRecentCoordinateReferenceSystem( const QgsCoordinateReferenceSystem &crs );
10651065

1066+
/**
1067+
* Removes a CRS from the list of recently used CRS.
1068+
* \since QGIS 3.32
1069+
*/
1070+
static void removeRecentCoordinateReferenceSystem( const QgsCoordinateReferenceSystem &crs );
1071+
1072+
/**
1073+
* Cleans the list of recently used CRS.
1074+
* \since QGIS 3.32
1075+
*/
1076+
static void clearRecentCoordinateReferenceSystems();
1077+
10661078
#ifndef SIP_RUN
10671079

10681080
/**

‎src/gui/qgsprojectionselectiontreewidget.cpp

Lines changed: 124 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
#include "qgsunittypes.h"
2929

3030
//qt includes
31+
#include <QAction>
32+
#include <QToolButton>
33+
#include <QMenu>
3134
#include <QFileInfo>
3235
#include <QHeaderView>
3336
#include <QResizeEvent>
@@ -63,14 +66,41 @@ QgsProjectionSelectionTreeWidget::QgsProjectionSelectionTreeWidget( QWidget *par
6366

6467
// Hide (internal) ID column
6568
lstCoordinateSystems->setColumnHidden( QgisCrsIdColumn, true );
66-
6769
lstRecent->header()->setSectionResizeMode( AuthidColumn, QHeaderView::Stretch );
6870
lstRecent->header()->resizeSection( QgisCrsIdColumn, 0 );
6971
lstRecent->header()->setSectionResizeMode( QgisCrsIdColumn, QHeaderView::Fixed );
70-
71-
// Hide (internal) ID column
7272
lstRecent->setColumnHidden( QgisCrsIdColumn, true );
7373

74+
// Clear Crs Column
75+
lstRecent->header()->setMinimumSectionSize( 10 );
76+
lstRecent->header()->setStretchLastSection( false );
77+
lstRecent->header()->resizeSection( ClearColumn, 20 );
78+
79+
// Clear recent crs context menu
80+
lstRecent->setContextMenuPolicy( Qt::CustomContextMenu );
81+
connect( lstRecent, &QTreeWidget::customContextMenuRequested, this, [this]( const QPoint & pos )
82+
{
83+
// If list is empty, do nothing
84+
if ( lstRecent->topLevelItemCount() == 0 )
85+
return;
86+
QMenu menu;
87+
// Clear selected
88+
QTreeWidgetItem *currentItem = lstRecent->itemAt( pos );
89+
if ( currentItem )
90+
{
91+
QAction *clearSelected = menu.addAction( QgsApplication::getThemeIcon( "/mIconClearItem.svg" ), tr( "Remove selected CRS from recently used CRS" ) );
92+
connect( clearSelected, &QAction::triggered, this, [this, currentItem ] { removeRecentCrsItem( currentItem ); } );
93+
menu.addSeparator();
94+
}
95+
// Clear all
96+
QAction *clearAll = menu.addAction( QgsApplication::getThemeIcon( "/console/iconClearConsole.svg" ), tr( "Clear all recently used CRS" ) );
97+
connect( clearAll, &QAction::triggered, this, &QgsProjectionSelectionTreeWidget::clearRecentCrs );
98+
menu.exec( lstRecent->viewport()->mapToGlobal( pos ) );
99+
} );
100+
101+
// Install event fiter to catch delete key press on the recent crs list
102+
lstRecent->installEventFilter( this );
103+
74104
mRecentProjections = QgsCoordinateReferenceSystem::recentCoordinateReferenceSystems();
75105

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

115-
lstRecent->header()->resizeSection( NameColumn, event->size().width() - 240 );
145+
lstRecent->header()->resizeSection( NameColumn, event->size().width() - 260 );
116146
lstRecent->header()->resizeSection( AuthidColumn, 240 );
117147
lstRecent->header()->resizeSection( QgisCrsIdColumn, 0 );
148+
lstRecent->header()->resizeSection( ClearColumn, 20 );
118149
}
119150

120151
void QgsProjectionSelectionTreeWidget::showEvent( QShowEvent *event )
@@ -146,6 +177,25 @@ void QgsProjectionSelectionTreeWidget::showEvent( QShowEvent *event )
146177
mInitialized = true;
147178
}
148179

180+
181+
bool QgsProjectionSelectionTreeWidget::eventFilter( QObject *obj, QEvent *ev )
182+
{
183+
if ( obj != lstRecent )
184+
return false;
185+
186+
if ( ev->type() != QEvent::KeyPress )
187+
return false;
188+
189+
QKeyEvent *keyEvent = static_cast<QKeyEvent *>( ev );
190+
if ( keyEvent->matches( QKeySequence::Delete ) )
191+
{
192+
removeRecentCrsItem( lstRecent->currentItem() );
193+
return true;
194+
}
195+
196+
return false;
197+
}
198+
149199
QString QgsProjectionSelectionTreeWidget::ogcWmsCrsFilterAsSqlExpression( QSet<QString> *crsFilter )
150200
{
151201
QString sqlExpression = QStringLiteral( "1" ); // it's "SQL" for "true"
@@ -253,13 +303,25 @@ void QgsProjectionSelectionTreeWidget::insertRecent( const QgsCoordinateReferenc
253303
if ( nodes.isEmpty() )
254304
return;
255305

256-
lstRecent->insertTopLevelItem( 0, new QTreeWidgetItem( lstRecent, QStringList()
257-
<< nodes.first()->text( NameColumn )
258-
<< nodes.first()->text( AuthidColumn )
259-
<< nodes.first()->text( QgisCrsIdColumn ) ) );
306+
QTreeWidgetItem *item = new QTreeWidgetItem( lstRecent, QStringList()
307+
<< nodes.first()->text( NameColumn )
308+
<< nodes.first()->text( AuthidColumn )
309+
<< nodes.first()->text( QgisCrsIdColumn ) );
310+
311+
// Insert clear button in the last column
312+
QToolButton *clearButton = new QToolButton();
313+
clearButton->setIcon( QgsApplication::getThemeIcon( "/mIconClearItem.svg" ) );
314+
clearButton->setAutoRaise( true );
315+
clearButton->setToolTip( tr( "Remove from recently used CRS" ) );
316+
connect( clearButton, &QToolButton::clicked, this, [this, item] { removeRecentCrsItem( item ); } );
317+
lstRecent->setItemWidget( item, ClearColumn, clearButton );
318+
319+
320+
lstRecent->insertTopLevelItem( 0, item );
321+
260322
}
261323

262-
//note this line just returns the projection name!
324+
// note this line just returns the projection name!
263325
QString QgsProjectionSelectionTreeWidget::selectedName()
264326
{
265327
// return the selected wkt name from the list view
@@ -307,25 +369,19 @@ QgsRectangle QgsProjectionSelectionTreeWidget::previewRect() const
307369
return mAreaCanvas->canvasRect();
308370
}
309371

310-
QString QgsProjectionSelectionTreeWidget::getSelectedExpression( const QString &expression ) const
372+
QString QgsProjectionSelectionTreeWidget::expressionForItem( QTreeWidgetItem *item, const QString &expression ) const
311373
{
312-
// Only return the attribute if there is a node in the tree
313-
// selected that has an srs_id. This prevents error if the user
314-
// selects a top-level node rather than an actual coordinate
315-
// system
316-
//
317-
// Get the selected node and make sure it is a srs andx
318-
// not a top-level projection node
319-
QTreeWidgetItem *lvi = lstCoordinateSystems->currentItem();
320-
if ( !lvi || lvi->text( QgisCrsIdColumn ).isEmpty() )
374+
// Only return the attribute if the selected item that has an srs_id.
375+
// This prevents error if the user selects a top-level node rather
376+
// than an actual coordinate system
377+
if ( !item || item->text( QgisCrsIdColumn ).isEmpty() )
321378
return QString();
322379

323-
//
380+
324381
// Determine if this is a user projection or a system on
325382
// user projection defs all have srs_id >= 100000
326-
//
327383
QString databaseFileName;
328-
if ( lvi->text( QgisCrsIdColumn ).toLong() >= USER_CRS_START_ID )
384+
if ( item->text( QgisCrsIdColumn ).toLong() >= USER_CRS_START_ID )
329385
{
330386
databaseFileName = QgsApplication::qgisUserDatabaseFilePath();
331387
if ( !QFileInfo::exists( databaseFileName ) )
@@ -338,7 +394,6 @@ QString QgsProjectionSelectionTreeWidget::getSelectedExpression( const QString &
338394
databaseFileName = mSrsDatabaseFileName;
339395
}
340396

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

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

382-
QgsCoordinateReferenceSystem QgsProjectionSelectionTreeWidget::crs() const
437+
438+
439+
QgsCoordinateReferenceSystem QgsProjectionSelectionTreeWidget::crsForItem( QTreeWidgetItem *item ) const
383440
{
384441
if ( mCheckBoxNoProjection->isEnabled() && mCheckBoxNoProjection->isChecked() )
385442
return QgsCoordinateReferenceSystem();
386443

387444
if ( !mInitialized && mDeferredLoadCrs.isValid() )
388445
return mDeferredLoadCrs;
389446

390-
const QString srsIdString = getSelectedExpression( QStringLiteral( "srs_id" ) );
447+
const QString srsIdString = expressionForItem( item, QStringLiteral( "srs_id" ) );
391448
if ( !srsIdString.isEmpty() )
392449
{
393450
int srid = srsIdString.toLong();
394451
if ( srid >= USER_CRS_START_ID )
395452
return QgsCoordinateReferenceSystem::fromOgcWmsCrs( QStringLiteral( "USER:%1" ).arg( srid ) );
396453
else
397-
return QgsCoordinateReferenceSystem::fromOgcWmsCrs( getSelectedExpression( QStringLiteral( "upper(auth_name||':'||auth_id)" ) ) );
454+
return QgsCoordinateReferenceSystem::fromOgcWmsCrs( expressionForItem( item, QStringLiteral( "upper(auth_name||':'||auth_id)" ) ) );
398455
}
399456
else
400457
{
401458
// custom CRS
402-
QTreeWidgetItem *lvi = lstCoordinateSystems->currentItem();
403-
if ( lvi && lvi->data( 0, RoleWkt ).isValid() )
404-
return QgsCoordinateReferenceSystem::fromWkt( lvi->data( 0, RoleWkt ).toString() );
405-
else if ( lvi && lvi->data( 0, RoleProj ).isValid() )
406-
return QgsCoordinateReferenceSystem::fromProj( lvi->data( 0, RoleProj ).toString() );
459+
if ( item && item->data( 0, RoleWkt ).isValid() )
460+
return QgsCoordinateReferenceSystem::fromWkt( item->data( 0, RoleWkt ).toString() );
461+
else if ( item && item->data( 0, RoleProj ).isValid() )
462+
return QgsCoordinateReferenceSystem::fromProj( item->data( 0, RoleProj ).toString() );
407463
else
408464
return QgsCoordinateReferenceSystem();
409465
}
410466
}
411467

468+
QgsCoordinateReferenceSystem QgsProjectionSelectionTreeWidget::crs() const
469+
{
470+
return crsForItem( lstCoordinateSystems->currentItem() );
471+
}
472+
412473
void QgsProjectionSelectionTreeWidget::setShowNoProjection( bool show )
413474
{
414475
mCheckBoxNoProjection->setVisible( show );
@@ -1053,3 +1114,34 @@ void QgsProjectionSelectionTreeWidget::showDBMissingWarning( const QString &file
10531114
"Because of this the projection selector will not work…" )
10541115
.arg( fileName ) );
10551116
}
1117+
1118+
void QgsProjectionSelectionTreeWidget::clearRecentCrs()
1119+
{
1120+
// If the list is empty, there is nothing to do
1121+
if ( lstRecent->topLevelItemCount() == 0 )
1122+
{
1123+
return;
1124+
}
1125+
1126+
// Ask for confirmation
1127+
if ( QMessageBox::question( this, tr( "Clear Recent CRS" ),
1128+
tr( "Are you sure you want to clear the list of recently used coordinate reference system?" ),
1129+
QMessageBox::Yes | QMessageBox::No ) != QMessageBox::Yes )
1130+
{
1131+
return;
1132+
}
1133+
QgsCoordinateReferenceSystem::clearRecentCoordinateReferenceSystems();
1134+
lstRecent->clear();
1135+
}
1136+
1137+
1138+
void QgsProjectionSelectionTreeWidget::removeRecentCrsItem( QTreeWidgetItem *item )
1139+
{
1140+
int index = lstRecent->indexOfTopLevelItem( item );
1141+
if ( index == -1 )
1142+
return;
1143+
QgsCoordinateReferenceSystem crs = crsForItem( item );
1144+
QgsCoordinateReferenceSystem::removeRecentCoordinateReferenceSystem( crs );
1145+
lstRecent->takeTopLevelItem( index );
1146+
delete item;
1147+
}

‎src/gui/qgsprojectionselectiontreewidget.h

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,14 @@ class GUI_EXPORT QgsProjectionSelectionTreeWidget : public QWidget, private Ui::
145145
*/
146146
Q_DECL_DEPRECATED void pushProjectionToFront() SIP_DEPRECATED;
147147

148+
149+
/**
150+
* Clear the list of recent projections.
151+
*
152+
* \since QGIS 3.32
153+
*/
154+
void clearRecentCrs();
155+
148156
signals:
149157

150158
/**
@@ -178,6 +186,9 @@ class GUI_EXPORT QgsProjectionSelectionTreeWidget : public QWidget, private Ui::
178186
// Used to manage column sizes
179187
void resizeEvent( QResizeEvent *event ) override;
180188

189+
// Used to catch key presses on the recent projections list
190+
bool eventFilter( QObject *obj, QEvent *ev ) override;
191+
181192
private:
182193

183194
/**
@@ -236,12 +247,11 @@ class GUI_EXPORT QgsProjectionSelectionTreeWidget : public QWidget, private Ui::
236247
*/
237248
void applySelection( int column = QgsProjectionSelectionTreeWidget::None, QString value = QString() );
238249

239-
/**
240-
* \brief gets an arbitrary sqlite3 expression from the selection
241-
*
242-
* \param e The sqlite3 expression (typically "srid" or "sridid")
243-
*/
244-
QString getSelectedExpression( const QString &e ) const;
250+
//! gets an arbitrary sqlite3 expression from the given item
251+
QString expressionForItem( QTreeWidgetItem *item, const QString &expression ) const;
252+
253+
//! Returns the CRS of the given item
254+
QgsCoordinateReferenceSystem crsForItem( QTreeWidgetItem *item ) const;
245255

246256
QString selectedName();
247257

@@ -290,7 +300,7 @@ class GUI_EXPORT QgsProjectionSelectionTreeWidget : public QWidget, private Ui::
290300
//! Has the Recent Projection List been populated?
291301
bool mRecentProjListDone = false;
292302

293-
enum Columns { NameColumn, AuthidColumn, QgisCrsIdColumn, None };
303+
enum Columns { NameColumn, AuthidColumn, QgisCrsIdColumn, ClearColumn, None };
294304
int mSearchColumn = QgsProjectionSelectionTreeWidget::None;
295305
QString mSearchValue;
296306

@@ -320,6 +330,8 @@ class GUI_EXPORT QgsProjectionSelectionTreeWidget : public QWidget, private Ui::
320330
void lstCoordinateSystems_currentItemChanged( QTreeWidgetItem *current, QTreeWidgetItem *prev );
321331
void lstRecent_currentItemChanged( QTreeWidgetItem *current, QTreeWidgetItem *prev );
322332
void updateFilter();
333+
334+
void removeRecentCrsItem( QTreeWidgetItem *item );
323335
};
324336

325337
#endif

‎src/ui/qgsprojectionselectorbase.ui

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<x>0</x>
88
<y>0</y>
99
<width>578</width>
10-
<height>654</height>
10+
<height>650</height>
1111
</rect>
1212
</property>
1313
<property name="sizePolicy">
@@ -82,17 +82,21 @@
8282
</layout>
8383
</item>
8484
<item>
85-
<widget class="QLabel" name="label_3">
86-
<property name="font">
87-
<font>
88-
<weight>75</weight>
89-
<bold>true</bold>
90-
</font>
91-
</property>
92-
<property name="text">
93-
<string>Recently Used Coordinate Reference Systems</string>
94-
</property>
95-
</widget>
85+
<layout class="QHBoxLayout" name="horizontalLayout_2">
86+
<item>
87+
<widget class="QLabel" name="label_3">
88+
<property name="font">
89+
<font>
90+
<weight>75</weight>
91+
<bold>true</bold>
92+
</font>
93+
</property>
94+
<property name="text">
95+
<string>Recently Used Coordinate Reference Systems</string>
96+
</property>
97+
</widget>
98+
</item>
99+
</layout>
96100
</item>
97101
<item>
98102
<widget class="QSplitter" name="mSplitter">
@@ -125,7 +129,7 @@
125129
<bool>true</bool>
126130
</property>
127131
<property name="columnCount">
128-
<number>3</number>
132+
<number>4</number>
129133
</property>
130134
<column>
131135
<property name="text">
@@ -142,8 +146,13 @@
142146
<string>ID</string>
143147
</property>
144148
</column>
149+
<column>
150+
<property name="text">
151+
<string/>
152+
</property>
153+
</column>
145154
</widget>
146-
<widget class="QWidget" name="">
155+
<widget class="QWidget" name="layoutWidget">
147156
<layout class="QGridLayout" name="gridLayout">
148157
<property name="horizontalSpacing">
149158
<number>0</number>
@@ -223,7 +232,7 @@
223232
</item>
224233
</layout>
225234
</widget>
226-
<widget class="QWidget" name="">
235+
<widget class="QWidget" name="layoutWidget_2">
227236
<layout class="QHBoxLayout" name="horizontalLayout_4">
228237
<property name="topMargin">
229238
<number>0</number>
@@ -314,6 +323,8 @@
314323
<tabstop>cbxHideDeprecated</tabstop>
315324
<tabstop>lstCoordinateSystems</tabstop>
316325
</tabstops>
317-
<resources/>
326+
<resources>
327+
<include location="../../images/images.qrc"/>
328+
</resources>
318329
<connections/>
319330
</ui>

0 commit comments

Comments
 (0)
Please sign in to comment.