28
28
#include " qgsunittypes.h"
29
29
30
30
// qt includes
31
+ #include < QAction>
32
+ #include < QToolButton>
33
+ #include < QMenu>
31
34
#include < QFileInfo>
32
35
#include < QHeaderView>
33
36
#include < QResizeEvent>
@@ -63,14 +66,41 @@ QgsProjectionSelectionTreeWidget::QgsProjectionSelectionTreeWidget( QWidget *par
63
66
64
67
// Hide (internal) ID column
65
68
lstCoordinateSystems->setColumnHidden ( QgisCrsIdColumn, true );
66
-
67
69
lstRecent->header ()->setSectionResizeMode ( AuthidColumn, QHeaderView::Stretch );
68
70
lstRecent->header ()->resizeSection ( QgisCrsIdColumn, 0 );
69
71
lstRecent->header ()->setSectionResizeMode ( QgisCrsIdColumn, QHeaderView::Fixed );
70
-
71
- // Hide (internal) ID column
72
72
lstRecent->setColumnHidden ( QgisCrsIdColumn, true );
73
73
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
+
74
104
mRecentProjections = QgsCoordinateReferenceSystem::recentCoordinateReferenceSystems ();
75
105
76
106
mCheckBoxNoProjection ->setHidden ( true );
@@ -112,9 +142,10 @@ void QgsProjectionSelectionTreeWidget::resizeEvent( QResizeEvent *event )
112
142
lstCoordinateSystems->header ()->resizeSection ( AuthidColumn, 240 );
113
143
lstCoordinateSystems->header ()->resizeSection ( QgisCrsIdColumn, 0 );
114
144
115
- lstRecent->header ()->resizeSection ( NameColumn, event->size ().width () - 240 );
145
+ lstRecent->header ()->resizeSection ( NameColumn, event->size ().width () - 260 );
116
146
lstRecent->header ()->resizeSection ( AuthidColumn, 240 );
117
147
lstRecent->header ()->resizeSection ( QgisCrsIdColumn, 0 );
148
+ lstRecent->header ()->resizeSection ( ClearColumn, 20 );
118
149
}
119
150
120
151
void QgsProjectionSelectionTreeWidget::showEvent ( QShowEvent *event )
@@ -146,6 +177,25 @@ void QgsProjectionSelectionTreeWidget::showEvent( QShowEvent *event )
146
177
mInitialized = true ;
147
178
}
148
179
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
+
149
199
QString QgsProjectionSelectionTreeWidget::ogcWmsCrsFilterAsSqlExpression ( QSet<QString> *crsFilter )
150
200
{
151
201
QString sqlExpression = QStringLiteral ( " 1" ); // it's "SQL" for "true"
@@ -253,13 +303,25 @@ void QgsProjectionSelectionTreeWidget::insertRecent( const QgsCoordinateReferenc
253
303
if ( nodes.isEmpty () )
254
304
return ;
255
305
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
+
260
322
}
261
323
262
- // note this line just returns the projection name!
324
+ // note this line just returns the projection name!
263
325
QString QgsProjectionSelectionTreeWidget::selectedName ()
264
326
{
265
327
// return the selected wkt name from the list view
@@ -307,25 +369,19 @@ QgsRectangle QgsProjectionSelectionTreeWidget::previewRect() const
307
369
return mAreaCanvas ->canvasRect ();
308
370
}
309
371
310
- QString QgsProjectionSelectionTreeWidget::getSelectedExpression ( const QString &expression ) const
372
+ QString QgsProjectionSelectionTreeWidget::expressionForItem ( QTreeWidgetItem *item, const QString &expression ) const
311
373
{
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 () )
321
378
return QString ();
322
379
323
- //
380
+
324
381
// Determine if this is a user projection or a system on
325
382
// user projection defs all have srs_id >= 100000
326
- //
327
383
QString databaseFileName;
328
- if ( lvi ->text ( QgisCrsIdColumn ).toLong () >= USER_CRS_START_ID )
384
+ if ( item ->text ( QgisCrsIdColumn ).toLong () >= USER_CRS_START_ID )
329
385
{
330
386
databaseFileName = QgsApplication::qgisUserDatabaseFilePath ();
331
387
if ( !QFileInfo::exists ( databaseFileName ) )
@@ -338,7 +394,6 @@ QString QgsProjectionSelectionTreeWidget::getSelectedExpression( const QString &
338
394
databaseFileName = mSrsDatabaseFileName ;
339
395
}
340
396
341
- //
342
397
// set up the database
343
398
// XXX We could probably hold the database open for the life of this object,
344
399
// assuming that it will never be used anywhere else. Given the low overhead,
@@ -358,7 +413,7 @@ QString QgsProjectionSelectionTreeWidget::getSelectedExpression( const QString &
358
413
sqlite3_stmt *stmt = nullptr ;
359
414
QString sql = QStringLiteral ( " select %1 from tbl_srs where srs_id=%2" )
360
415
.arg ( expression,
361
- lvi ->text ( QgisCrsIdColumn ) );
416
+ item ->text ( QgisCrsIdColumn ) );
362
417
363
418
QgsDebugMsgLevel ( QStringLiteral ( " Finding selected attribute using : %1" ).arg ( sql ), 4 );
364
419
rc = sqlite3_prepare ( database, sql.toUtf8 (), sql.toUtf8 ().length (), &stmt, &tail );
@@ -379,36 +434,42 @@ QString QgsProjectionSelectionTreeWidget::getSelectedExpression( const QString &
379
434
return attributeValue;
380
435
}
381
436
382
- QgsCoordinateReferenceSystem QgsProjectionSelectionTreeWidget::crs () const
437
+
438
+
439
+ QgsCoordinateReferenceSystem QgsProjectionSelectionTreeWidget::crsForItem ( QTreeWidgetItem *item ) const
383
440
{
384
441
if ( mCheckBoxNoProjection ->isEnabled () && mCheckBoxNoProjection ->isChecked () )
385
442
return QgsCoordinateReferenceSystem ();
386
443
387
444
if ( !mInitialized && mDeferredLoadCrs .isValid () )
388
445
return mDeferredLoadCrs ;
389
446
390
- const QString srsIdString = getSelectedExpression ( QStringLiteral ( " srs_id" ) );
447
+ const QString srsIdString = expressionForItem ( item, QStringLiteral ( " srs_id" ) );
391
448
if ( !srsIdString.isEmpty () )
392
449
{
393
450
int srid = srsIdString.toLong ();
394
451
if ( srid >= USER_CRS_START_ID )
395
452
return QgsCoordinateReferenceSystem::fromOgcWmsCrs ( QStringLiteral ( " USER:%1" ).arg ( srid ) );
396
453
else
397
- return QgsCoordinateReferenceSystem::fromOgcWmsCrs ( getSelectedExpression ( QStringLiteral ( " upper(auth_name||':'||auth_id)" ) ) );
454
+ return QgsCoordinateReferenceSystem::fromOgcWmsCrs ( expressionForItem ( item, QStringLiteral ( " upper(auth_name||':'||auth_id)" ) ) );
398
455
}
399
456
else
400
457
{
401
458
// 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 () );
407
463
else
408
464
return QgsCoordinateReferenceSystem ();
409
465
}
410
466
}
411
467
468
+ QgsCoordinateReferenceSystem QgsProjectionSelectionTreeWidget::crs () const
469
+ {
470
+ return crsForItem ( lstCoordinateSystems->currentItem () );
471
+ }
472
+
412
473
void QgsProjectionSelectionTreeWidget::setShowNoProjection ( bool show )
413
474
{
414
475
mCheckBoxNoProjection ->setVisible ( show );
@@ -1053,3 +1114,34 @@ void QgsProjectionSelectionTreeWidget::showDBMissingWarning( const QString &file
1053
1114
" Because of this the projection selector will not work…" )
1054
1115
.arg ( fileName ) );
1055
1116
}
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
+ }
0 commit comments