15
15
***************************************************************************/
16
16
17
17
#include " qgisapp.h"
18
+ #include " qgsmessagebar.h"
18
19
#include " qgsmeasuredialog.h"
19
20
#include " qgsmeasuretool.h"
20
21
#include " qgsdistancearea.h"
23
24
#include " qgscoordinatereferencesystem.h"
24
25
#include " qgsunittypes.h"
25
26
#include " qgssettings.h"
27
+ #include " qgssettingsentryimpl.h"
28
+ #include " qgssettingstree.h"
26
29
#include " qgsgui.h"
27
30
28
31
#include < QClipboard>
31
34
#include < QPushButton>
32
35
33
36
37
+ const QgsSettingsEntryBool *QgsMeasureDialog::settingClipboardHeader = new QgsSettingsEntryBool( QStringLiteral( " clipboard-header" ), QgsSettingsTree::sTreeMeasure , false , QObject::tr( " Whether the header should be copied to the cliboard along the coordinates, distances" ) );
38
+
39
+ const QgsSettingsEntryString *QgsMeasureDialog::settingClipboardSeparator = new QgsSettingsEntryString( QStringLiteral( " clipboard-separator" ), QgsSettingsTree::sTreeMeasure , QStringLiteral( " \t " ), QObject::tr( " Separator between the measure columns copied to the clipboard" ) );
40
+
41
+
34
42
QgsMeasureDialog::QgsMeasureDialog ( QgsMeasureTool *tool, Qt::WindowFlags f )
35
43
: QDialog( tool->canvas ()->topLevelWidget(), f )
36
44
, mMeasureArea( tool->measureArea () )
@@ -56,9 +64,15 @@ QgsMeasureDialog::QgsMeasureDialog( QgsMeasureTool *tool, Qt::WindowFlags f )
56
64
57
65
if ( !mMeasureArea )
58
66
{
59
- QPushButton *cpb = new QPushButton ( tr ( " Copy &All" ) );
67
+ QAction *copyAction = new QAction ( tr ( " Copy" ), this );
68
+ QPushButton *cpb = new QPushButton ( tr ( " Copy" ) );
60
69
buttonBox->addButton ( cpb, QDialogButtonBox::ActionRole );
61
- connect ( cpb, &QAbstractButton::clicked, this , &QgsMeasureDialog::copyMeasurements );
70
+ connect ( cpb, &QAbstractButton::clicked, copyAction, &QAction::trigger );
71
+ connect ( copyAction, &QAction::triggered, this , &QgsMeasureDialog::copyMeasurements );
72
+
73
+ // Add context menu in the table
74
+ mTable ->setContextMenuPolicy ( Qt::ActionsContextMenu );
75
+ mTable ->addAction ( copyAction );
62
76
}
63
77
64
78
repopulateComboBoxUnits ( mMeasureArea );
@@ -107,8 +121,7 @@ void QgsMeasureDialog::projChanged()
107
121
mDa .setEllipsoid ( QgsProject::instance ()->ellipsoid () );
108
122
}
109
123
110
- mTable ->clear ();
111
- mTotal = 0 .;
124
+ // Update the table and information displayed to the user
112
125
updateUi ();
113
126
}
114
127
@@ -132,8 +145,6 @@ void QgsMeasureDialog::crsChanged()
132
145
mUnitsCombo ->setEnabled ( true );
133
146
}
134
147
135
- mTable ->clear ();
136
- mTotal = 0 .;
137
148
updateUi ();
138
149
}
139
150
@@ -148,8 +159,9 @@ void QgsMeasureDialog::updateSettings()
148
159
mMapDistanceUnits = QgsProject::instance ()->crs ().mapUnits ();
149
160
mAreaUnits = QgsProject::instance ()->areaUnits ();
150
161
mDa .setSourceCrs ( mCanvas ->mapSettings ().destinationCrs (), QgsProject::instance ()->transformContext () );
151
- projChanged ();
152
162
163
+ // Calling projChanged() will set the ellipsoid and clear then re-populate the table
164
+ projChanged ();
153
165
154
166
if ( mCartesian ->isChecked () || !mCanvas ->mapSettings ().destinationCrs ().isValid () ||
155
167
( mCanvas ->mapSettings ().destinationCrs ().mapUnits () == Qgis::DistanceUnit::Degrees
@@ -192,24 +204,12 @@ void QgsMeasureDialog::unitsChanged( int index )
192
204
}
193
205
}
194
206
195
- mTable ->clear ();
196
- mTotal = 0 .;
197
207
updateUi ();
198
-
199
- if ( !mTool ->done () )
200
- {
201
- // re-add temporary mouse cursor position
202
- addPoint ();
203
- mouseMove ( mLastMousePoint );
204
- }
205
208
}
206
209
207
210
void QgsMeasureDialog::restart ()
208
211
{
209
212
mTool ->restart ();
210
-
211
- mTable ->clear ();
212
- mTotal = 0 .;
213
213
updateUi ();
214
214
}
215
215
@@ -239,7 +239,9 @@ void QgsMeasureDialog::mouseMove( const QgsPointXY &point )
239
239
QTreeWidgetItem *item = mTable ->topLevelItem ( mTable ->topLevelItemCount () - 1 );
240
240
if ( item )
241
241
{
242
- item->setText ( 0 , QLocale ().toString ( d, ' f' , mDecimalPlaces ) );
242
+ item->setText ( Columns::X, QLocale ().toString ( p2.x (), ' f' , mDecimalPlacesCoordinates ) );
243
+ item->setText ( Columns::Y, QLocale ().toString ( p2.y (), ' f' , mDecimalPlacesCoordinates ) );
244
+ item->setText ( Columns::Distance, QLocale ().toString ( d, ' f' , mDecimalPlaces ) );
243
245
}
244
246
}
245
247
}
@@ -256,8 +258,21 @@ void QgsMeasureDialog::addPoint()
256
258
{
257
259
if ( !mTool ->done () )
258
260
{
259
- QTreeWidgetItem *item = new QTreeWidgetItem ( QStringList ( QLocale ().toString ( 0.0 , ' f' , mDecimalPlaces ) ) );
260
- item->setTextAlignment ( 0 , Qt::AlignRight );
261
+ if ( numPoints == 1 )
262
+ {
263
+ // First point, so we add a first item, with no computed distance and only the coordinates
264
+ QTreeWidgetItem *item = new QTreeWidgetItem ();
265
+ QgsPointXY lastPoint = mTool ->points ().last ();
266
+ item->setText ( Columns::X, QLocale ().toString ( lastPoint.x (), ' f' , mDecimalPlacesCoordinates ) );
267
+ item->setText ( Columns::Y, QLocale ().toString ( lastPoint.y (), ' f' , mDecimalPlacesCoordinates ) );
268
+ mTable ->addTopLevelItem ( item );
269
+ }
270
+ QTreeWidgetItem *item = new QTreeWidgetItem ();
271
+ QgsPointXY lastPoint = mTool ->points ().last ();
272
+ item->setText ( Columns::X, QLocale ().toString ( lastPoint.x (), ' f' , mDecimalPlacesCoordinates ) );
273
+ item->setText ( Columns::Y, QLocale ().toString ( lastPoint.y (), ' f' , mDecimalPlacesCoordinates ) );
274
+ item->setText ( Columns::Distance, QLocale ().toString ( 0.0 , ' f' , mDecimalPlaces ) );
275
+ item->setTextAlignment ( Columns::Distance, Qt::AlignRight );
261
276
mTable ->addTopLevelItem ( item );
262
277
mTable ->scrollToItem ( item );
263
278
}
@@ -304,7 +319,9 @@ void QgsMeasureDialog::removeLastPoint()
304
319
d = convertLength ( d, mDistanceUnits );
305
320
306
321
QTreeWidgetItem *item = mTable ->topLevelItem ( mTable ->topLevelItemCount () - 1 );
307
- item->setText ( 0 , QLocale ().toString ( d, ' f' , mDecimalPlaces ) );
322
+ item->setText ( Columns::X, QLocale ().toString ( mLastMousePoint .x (), ' f' , mDecimalPlacesCoordinates ) );
323
+ item->setText ( Columns::Y, QLocale ().toString ( mLastMousePoint .y (), ' f' , mDecimalPlacesCoordinates ) );
324
+ item->setText ( Columns::Distance, QLocale ().toString ( d, ' f' , mDecimalPlaces ) );
308
325
editTotal->setText ( formatDistance ( mTotal + d ) );
309
326
}
310
327
else
@@ -368,6 +385,10 @@ QString QgsMeasureDialog::formatArea( double area, bool convertUnits ) const
368
385
369
386
void QgsMeasureDialog::updateUi ()
370
387
{
388
+ // Clear the table
389
+ mTable ->clear ();
390
+ mTotal = 0 .;
391
+
371
392
// Set tooltip to indicate how we calculate measurements
372
393
QString toolTip = tr ( " The calculations are based on:" );
373
394
@@ -551,6 +572,15 @@ void QgsMeasureDialog::updateUi()
551
572
}
552
573
}
553
574
575
+ if ( mCanvas ->mapSettings ().destinationCrs ().mapUnits () == Qgis::DistanceUnit::Degrees )
576
+ {
577
+ mDecimalPlacesCoordinates = 5 ;
578
+ }
579
+ else
580
+ {
581
+ mDecimalPlacesCoordinates = 3 ;
582
+ }
583
+
554
584
editTotal->setToolTip ( toolTip );
555
585
mTable ->setToolTip ( toolTip );
556
586
mNotesLabel ->setText ( toolTip );
@@ -567,15 +597,15 @@ void QgsMeasureDialog::updateUi()
567
597
if ( mUseMapUnits )
568
598
{
569
599
mUnitsCombo ->setCurrentIndex ( mUnitsCombo ->findData ( static_cast < int >( Qgis::DistanceUnit::Unknown ) ) );
570
- mTable ->setHeaderLabels ( QStringList ( tr ( " Segments [%1]" ).arg ( QgsUnitTypes::toString ( mMapDistanceUnits ) ) ) );
600
+ mTable ->headerItem ()-> setText ( Columns::Distance, tr ( " Segments [%1]" ).arg ( QgsUnitTypes::toString ( mMapDistanceUnits ) ) );
571
601
}
572
602
else
573
603
{
574
604
mUnitsCombo ->setCurrentIndex ( mUnitsCombo ->findData ( static_cast < int >( mDistanceUnits ) ) );
575
605
if ( mDistanceUnits != Qgis::DistanceUnit::Unknown )
576
- mTable ->setHeaderLabels ( QStringList ( tr ( " Segments [%1]" ).arg ( QgsUnitTypes::toString ( mDistanceUnits ) ) ) );
606
+ mTable ->headerItem ()-> setText ( Columns::Distance, tr ( " Segments [%1]" ).arg ( QgsUnitTypes::toString ( mDistanceUnits ) ) );
577
607
else
578
- mTable ->setHeaderLabels ( QStringList ( tr ( " Segments" ) ) );
608
+ mTable ->headerItem ()-> setText ( Columns::Distance, tr ( " Segments" ) );
579
609
}
580
610
}
581
611
@@ -592,40 +622,54 @@ void QgsMeasureDialog::updateUi()
592
622
}
593
623
else
594
624
{
625
+ // Repopulate the table
595
626
QVector<QgsPointXY>::const_iterator it;
596
- bool b = true ; // first point
627
+ bool firstPoint = true ;
597
628
598
- QgsPointXY p1, p2 ;
629
+ QgsPointXY previousPoint, point ;
599
630
mTotal = 0 ;
600
631
const QVector< QgsPointXY > tmpPoints = mTool ->points ();
601
632
for ( it = tmpPoints.constBegin (); it != tmpPoints.constEnd (); ++it )
602
633
{
603
- p2 = *it;
604
- if ( !b )
634
+ point = *it;
635
+
636
+ QTreeWidgetItem *item = new QTreeWidgetItem ();
637
+ item->setText ( Columns::X, QLocale ().toString ( point.x (), ' f' , mDecimalPlacesCoordinates ) );
638
+ item->setText ( Columns::Y, QLocale ().toString ( point.y (), ' f' , mDecimalPlacesCoordinates ) );
639
+
640
+ if ( !firstPoint )
605
641
{
606
642
double d = -1 ;
607
- d = mDa .measureLine ( p1, p2 );
643
+ d = mDa .measureLine ( previousPoint, point );
608
644
if ( mConvertToDisplayUnits )
609
645
{
610
646
if ( mDistanceUnits == Qgis::DistanceUnit::Unknown && mMapDistanceUnits != Qgis::DistanceUnit::Unknown )
611
647
d = convertLength ( d, mMapDistanceUnits );
612
648
else
613
649
d = convertLength ( d, mDistanceUnits );
614
650
}
615
-
616
- QTreeWidgetItem *item = new QTreeWidgetItem ( QStringList ( QLocale ().toString ( d, ' f' , mDecimalPlaces ) ) );
617
- item->setTextAlignment ( 0 , Qt::AlignRight );
618
- mTable ->addTopLevelItem ( item );
619
- mTable ->scrollToItem ( item );
651
+ item->setText ( Columns::Distance, QLocale ().toString ( d, ' f' , mDecimalPlaces ) );
652
+ item->setTextAlignment ( Columns::Distance, Qt::AlignRight );
620
653
}
621
- p1 = p2;
622
- b = false ;
654
+
655
+ mTable ->addTopLevelItem ( item );
656
+ mTable ->scrollToItem ( item );
657
+
658
+ previousPoint = point;
659
+ firstPoint = false ;
623
660
}
624
661
625
662
mTotal = mDa .measureLine ( mTool ->points () );
626
663
mTable ->show (); // Show the table with items
627
664
mSpacer ->changeSize ( 40 , 5 , QSizePolicy::Fixed, QSizePolicy::Maximum );
628
665
editTotal->setText ( formatDistance ( mTotal , mConvertToDisplayUnits ) );
666
+
667
+ if ( !mTool ->done () )
668
+ {
669
+ // re-add temporary mouse cursor position
670
+ addPoint ();
671
+ mouseMove ( mLastMousePoint );
672
+ }
629
673
}
630
674
}
631
675
@@ -676,15 +720,36 @@ double QgsMeasureDialog::convertArea( double area, Qgis::AreaUnit toUnit ) const
676
720
677
721
void QgsMeasureDialog::copyMeasurements ()
678
722
{
723
+ bool includeHeader = settingClipboardHeader->value ();
724
+
725
+ // Get the separator
726
+ QString separator = settingClipboardSeparator->value ();
727
+ if ( separator.isEmpty () )
728
+ separator = QStringLiteral ( " \t " );
729
+
679
730
QClipboard *clipboard = QApplication::clipboard ();
680
731
QString text;
681
732
QTreeWidgetItemIterator it ( mTable );
733
+
734
+ if ( includeHeader )
735
+ {
736
+ text += mTable ->headerItem ()->text ( Columns::X ) + separator;
737
+ text += mTable ->headerItem ()->text ( Columns::Y ) + separator;
738
+ text += mTable ->headerItem ()->text ( Columns::Distance ) + QStringLiteral ( " \n " );
739
+ }
740
+
682
741
while ( *it )
683
742
{
684
- text += ( *it )->text ( 0 ) + QStringLiteral ( " \n " );
743
+ text += ( *it )->text ( Columns::X ) + separator;
744
+ text += ( *it )->text ( Columns::Y ) + separator;
745
+ text += ( *it )->text ( Columns::Distance ) + QStringLiteral ( " \n " );
685
746
it++;
686
747
}
748
+
687
749
clipboard->setText ( text );
750
+
751
+ // Display a message to the user
752
+ QgisApp::instance ()->messageBar ()->pushInfo ( tr ( " Measure" ), tr ( " Measurements copied to clipboard" ) );
688
753
}
689
754
690
755
void QgsMeasureDialog::reject ()
0 commit comments