Skip to content

Commit

Permalink
Merge pull request #52043 from YoannQDQ/measure-tool-copy-coordinates
Browse files Browse the repository at this point in the history
Measure tool copy coordinates
  • Loading branch information
nirvn committed Apr 23, 2023
2 parents 4dcd0d4 + 0945734 commit 2d4f1a8
Show file tree
Hide file tree
Showing 7 changed files with 517 additions and 293 deletions.
47 changes: 41 additions & 6 deletions src/app/options/qgsoptions.cpp
Expand Up @@ -59,6 +59,7 @@
#include "options/qgsadvancedoptions.h"
#include "qgssettingsentryimpl.h"
#include "qgssettingsentryenumflag.h"
#include "qgsmeasuredialog.h"

#ifdef HAVE_OPENCL
#include "qgsopenclutils.h"
Expand Down Expand Up @@ -643,16 +644,33 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WindowFlags fl, const QList<QgsOpti

// set if base unit of measure tool should be changed
bool baseUnit = mSettings->value( QStringLiteral( "qgis/measure/keepbaseunit" ), true ).toBool();
if ( baseUnit )
{
mKeepBaseUnitCheckBox->setChecked( true );
}
mKeepBaseUnitCheckBox->setChecked( baseUnit );

mPlanimetricMeasurementsComboBox->setChecked( mSettings->value( QStringLiteral( "measure/planimetric" ), false, QgsSettings::Core ).toBool() );

// set the measure tool copy settings
connect( mSeparatorOther, &QRadioButton::toggled, mSeparatorCustom, &QLineEdit::setEnabled );
mIncludeHeader->setChecked( QgsMeasureDialog::settingClipboardHeader->value() );

const QString sep = QgsMeasureDialog::settingClipboardSeparator->value();

if ( sep.isEmpty() || sep == QStringLiteral( "\t" ) )
mSeparatorTab->setChecked( true );
else if ( sep == QStringLiteral( "," ) )
mSeparatorComma->setChecked( true );
else if ( sep == QStringLiteral( ";" ) )
mSeparatorSemicolon->setChecked( true );
else if ( sep == QStringLiteral( " " ) )
mSeparatorSpace->setChecked( true );
else if ( sep == QStringLiteral( ":" ) )
mSeparatorColon->setChecked( true );
else
{
mKeepBaseUnitCheckBox->setChecked( false );
mSeparatorOther->setChecked( true );
mSeparatorCustom->setText( sep );
}
mPlanimetricMeasurementsComboBox->setChecked( mSettings->value( QStringLiteral( "measure/planimetric" ), false, QgsSettings::Core ).toBool() );

// set the default icon size
cmbIconSize->setCurrentIndex( cmbIconSize->findText( mSettings->value( QStringLiteral( "qgis/iconSize" ), QGIS_ICON_SIZE ).toString() ) );

// set font size and family
Expand Down Expand Up @@ -1665,6 +1683,23 @@ void QgsOptions::saveOptions()
bool baseUnit = mKeepBaseUnitCheckBox->isChecked();
mSettings->setValue( QStringLiteral( "/qgis/measure/keepbaseunit" ), baseUnit );

QgsMeasureDialog::settingClipboardHeader->setValue( mIncludeHeader->isChecked() );
QString separator;
if ( mSeparatorTab->isChecked() )
separator = QStringLiteral( "\t" );
else if ( mSeparatorComma->isChecked() )
separator = QStringLiteral( "," );
else if ( mSeparatorSemicolon->isChecked() )
separator = QStringLiteral( ";" );
else if ( mSeparatorSpace->isChecked() )
separator = QStringLiteral( " " );
else if ( mSeparatorColon->isChecked() )
separator = QStringLiteral( ":" );
else
separator = mSeparatorCustom->text();

QgsMeasureDialog::settingClipboardSeparator->setValue( separator );

//set the color for selections
QColor myColor = pbnSelectionColor->color();
mSettings->setValue( QStringLiteral( "/qgis/default_selection_color_red" ), myColor.red() );
Expand Down
143 changes: 104 additions & 39 deletions src/app/qgsmeasuredialog.cpp
Expand Up @@ -15,6 +15,7 @@
***************************************************************************/

#include "qgisapp.h"
#include "qgsmessagebar.h"
#include "qgsmeasuredialog.h"
#include "qgsmeasuretool.h"
#include "qgsdistancearea.h"
Expand All @@ -23,6 +24,8 @@
#include "qgscoordinatereferencesystem.h"
#include "qgsunittypes.h"
#include "qgssettings.h"
#include "qgssettingsentryimpl.h"
#include "qgssettingstree.h"
#include "qgsgui.h"

#include <QClipboard>
Expand All @@ -31,6 +34,11 @@
#include <QPushButton>


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" ) );

const QgsSettingsEntryString *QgsMeasureDialog::settingClipboardSeparator = new QgsSettingsEntryString( QStringLiteral( "clipboard-separator" ), QgsSettingsTree::sTreeMeasure, QStringLiteral( "\t" ), QObject::tr( "Separator between the measure columns copied to the clipboard" ) );


QgsMeasureDialog::QgsMeasureDialog( QgsMeasureTool *tool, Qt::WindowFlags f )
: QDialog( tool->canvas()->topLevelWidget(), f )
, mMeasureArea( tool->measureArea() )
Expand All @@ -56,9 +64,15 @@ QgsMeasureDialog::QgsMeasureDialog( QgsMeasureTool *tool, Qt::WindowFlags f )

if ( !mMeasureArea )
{
QPushButton *cpb = new QPushButton( tr( "Copy &All" ) );
QAction *copyAction = new QAction( tr( "Copy" ), this );
QPushButton *cpb = new QPushButton( tr( "Copy" ) );
buttonBox->addButton( cpb, QDialogButtonBox::ActionRole );
connect( cpb, &QAbstractButton::clicked, this, &QgsMeasureDialog::copyMeasurements );
connect( cpb, &QAbstractButton::clicked, copyAction, &QAction::trigger );
connect( copyAction, &QAction::triggered, this, &QgsMeasureDialog::copyMeasurements );

// Add context menu in the table
mTable->setContextMenuPolicy( Qt::ActionsContextMenu );
mTable->addAction( copyAction );
}

repopulateComboBoxUnits( mMeasureArea );
Expand Down Expand Up @@ -107,8 +121,7 @@ void QgsMeasureDialog::projChanged()
mDa.setEllipsoid( QgsProject::instance()->ellipsoid() );
}

mTable->clear();
mTotal = 0.;
// Update the table and information displayed to the user
updateUi();
}

Expand All @@ -132,8 +145,6 @@ void QgsMeasureDialog::crsChanged()
mUnitsCombo->setEnabled( true );
}

mTable->clear();
mTotal = 0.;
updateUi();
}

Expand All @@ -148,8 +159,9 @@ void QgsMeasureDialog::updateSettings()
mMapDistanceUnits = QgsProject::instance()->crs().mapUnits();
mAreaUnits = QgsProject::instance()->areaUnits();
mDa.setSourceCrs( mCanvas->mapSettings().destinationCrs(), QgsProject::instance()->transformContext() );
projChanged();

// Calling projChanged() will set the ellipsoid and clear then re-populate the table
projChanged();

if ( mCartesian->isChecked() || !mCanvas->mapSettings().destinationCrs().isValid() ||
( mCanvas->mapSettings().destinationCrs().mapUnits() == Qgis::DistanceUnit::Degrees
Expand Down Expand Up @@ -192,24 +204,12 @@ void QgsMeasureDialog::unitsChanged( int index )
}
}

mTable->clear();
mTotal = 0.;
updateUi();

if ( !mTool->done() )
{
// re-add temporary mouse cursor position
addPoint();
mouseMove( mLastMousePoint );
}
}

void QgsMeasureDialog::restart()
{
mTool->restart();

mTable->clear();
mTotal = 0.;
updateUi();
}

Expand Down Expand Up @@ -239,7 +239,9 @@ void QgsMeasureDialog::mouseMove( const QgsPointXY &point )
QTreeWidgetItem *item = mTable->topLevelItem( mTable->topLevelItemCount() - 1 );
if ( item )
{
item->setText( 0, QLocale().toString( d, 'f', mDecimalPlaces ) );
item->setText( Columns::X, QLocale().toString( p2.x(), 'f', mDecimalPlacesCoordinates ) );
item->setText( Columns::Y, QLocale().toString( p2.y(), 'f', mDecimalPlacesCoordinates ) );
item->setText( Columns::Distance, QLocale().toString( d, 'f', mDecimalPlaces ) );
}
}
}
Expand All @@ -256,8 +258,21 @@ void QgsMeasureDialog::addPoint()
{
if ( !mTool->done() )
{
QTreeWidgetItem *item = new QTreeWidgetItem( QStringList( QLocale().toString( 0.0, 'f', mDecimalPlaces ) ) );
item->setTextAlignment( 0, Qt::AlignRight );
if ( numPoints == 1 )
{
// First point, so we add a first item, with no computed distance and only the coordinates
QTreeWidgetItem *item = new QTreeWidgetItem();
QgsPointXY lastPoint = mTool->points().last();
item->setText( Columns::X, QLocale().toString( lastPoint.x(), 'f', mDecimalPlacesCoordinates ) );
item->setText( Columns::Y, QLocale().toString( lastPoint.y(), 'f', mDecimalPlacesCoordinates ) );
mTable->addTopLevelItem( item );
}
QTreeWidgetItem *item = new QTreeWidgetItem();
QgsPointXY lastPoint = mTool->points().last();
item->setText( Columns::X, QLocale().toString( lastPoint.x(), 'f', mDecimalPlacesCoordinates ) );
item->setText( Columns::Y, QLocale().toString( lastPoint.y(), 'f', mDecimalPlacesCoordinates ) );
item->setText( Columns::Distance, QLocale().toString( 0.0, 'f', mDecimalPlaces ) );
item->setTextAlignment( Columns::Distance, Qt::AlignRight );
mTable->addTopLevelItem( item );
mTable->scrollToItem( item );
}
Expand Down Expand Up @@ -304,7 +319,9 @@ void QgsMeasureDialog::removeLastPoint()
d = convertLength( d, mDistanceUnits );

QTreeWidgetItem *item = mTable->topLevelItem( mTable->topLevelItemCount() - 1 );
item->setText( 0, QLocale().toString( d, 'f', mDecimalPlaces ) );
item->setText( Columns::X, QLocale().toString( mLastMousePoint.x(), 'f', mDecimalPlacesCoordinates ) );
item->setText( Columns::Y, QLocale().toString( mLastMousePoint.y(), 'f', mDecimalPlacesCoordinates ) );
item->setText( Columns::Distance, QLocale().toString( d, 'f', mDecimalPlaces ) );
editTotal->setText( formatDistance( mTotal + d ) );
}
else
Expand Down Expand Up @@ -368,6 +385,10 @@ QString QgsMeasureDialog::formatArea( double area, bool convertUnits ) const

void QgsMeasureDialog::updateUi()
{
// Clear the table
mTable->clear();
mTotal = 0.;

// Set tooltip to indicate how we calculate measurements
QString toolTip = tr( "The calculations are based on:" );

Expand Down Expand Up @@ -551,6 +572,15 @@ void QgsMeasureDialog::updateUi()
}
}

if ( mCanvas->mapSettings().destinationCrs().mapUnits() == Qgis::DistanceUnit::Degrees )
{
mDecimalPlacesCoordinates = 5;
}
else
{
mDecimalPlacesCoordinates = 3;
}

editTotal->setToolTip( toolTip );
mTable->setToolTip( toolTip );
mNotesLabel->setText( toolTip );
Expand All @@ -567,15 +597,15 @@ void QgsMeasureDialog::updateUi()
if ( mUseMapUnits )
{
mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( static_cast< int >( Qgis::DistanceUnit::Unknown ) ) );
mTable->setHeaderLabels( QStringList( tr( "Segments [%1]" ).arg( QgsUnitTypes::toString( mMapDistanceUnits ) ) ) );
mTable->headerItem()->setText( Columns::Distance, tr( "Segments [%1]" ).arg( QgsUnitTypes::toString( mMapDistanceUnits ) ) );
}
else
{
mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( static_cast< int >( mDistanceUnits ) ) );
if ( mDistanceUnits != Qgis::DistanceUnit::Unknown )
mTable->setHeaderLabels( QStringList( tr( "Segments [%1]" ).arg( QgsUnitTypes::toString( mDistanceUnits ) ) ) );
mTable->headerItem()->setText( Columns::Distance, tr( "Segments [%1]" ).arg( QgsUnitTypes::toString( mDistanceUnits ) ) );
else
mTable->setHeaderLabels( QStringList( tr( "Segments" ) ) );
mTable->headerItem()->setText( Columns::Distance, tr( "Segments" ) );
}
}

Expand All @@ -592,40 +622,54 @@ void QgsMeasureDialog::updateUi()
}
else
{
// Repopulate the table
QVector<QgsPointXY>::const_iterator it;
bool b = true; // first point
bool firstPoint = true;

QgsPointXY p1, p2;
QgsPointXY previousPoint, point;
mTotal = 0;
const QVector< QgsPointXY > tmpPoints = mTool->points();
for ( it = tmpPoints.constBegin(); it != tmpPoints.constEnd(); ++it )
{
p2 = *it;
if ( !b )
point = *it;

QTreeWidgetItem *item = new QTreeWidgetItem();
item->setText( Columns::X, QLocale().toString( point.x(), 'f', mDecimalPlacesCoordinates ) );
item->setText( Columns::Y, QLocale().toString( point.y(), 'f', mDecimalPlacesCoordinates ) );

if ( !firstPoint )
{
double d = -1;
d = mDa.measureLine( p1, p2 );
d = mDa.measureLine( previousPoint, point );
if ( mConvertToDisplayUnits )
{
if ( mDistanceUnits == Qgis::DistanceUnit::Unknown && mMapDistanceUnits != Qgis::DistanceUnit::Unknown )
d = convertLength( d, mMapDistanceUnits );
else
d = convertLength( d, mDistanceUnits );
}

QTreeWidgetItem *item = new QTreeWidgetItem( QStringList( QLocale().toString( d, 'f', mDecimalPlaces ) ) );
item->setTextAlignment( 0, Qt::AlignRight );
mTable->addTopLevelItem( item );
mTable->scrollToItem( item );
item->setText( Columns::Distance, QLocale().toString( d, 'f', mDecimalPlaces ) );
item->setTextAlignment( Columns::Distance, Qt::AlignRight );
}
p1 = p2;
b = false;

mTable->addTopLevelItem( item );
mTable->scrollToItem( item );

previousPoint = point;
firstPoint = false;
}

mTotal = mDa.measureLine( mTool->points() );
mTable->show(); // Show the table with items
mSpacer->changeSize( 40, 5, QSizePolicy::Fixed, QSizePolicy::Maximum );
editTotal->setText( formatDistance( mTotal, mConvertToDisplayUnits ) );

if ( !mTool->done() )
{
// re-add temporary mouse cursor position
addPoint();
mouseMove( mLastMousePoint );
}
}
}

Expand Down Expand Up @@ -676,15 +720,36 @@ double QgsMeasureDialog::convertArea( double area, Qgis::AreaUnit toUnit ) const

void QgsMeasureDialog::copyMeasurements()
{
bool includeHeader = settingClipboardHeader->value();

// Get the separator
QString separator = settingClipboardSeparator->value();
if ( separator.isEmpty() )
separator = QStringLiteral( "\t" );

QClipboard *clipboard = QApplication::clipboard();
QString text;
QTreeWidgetItemIterator it( mTable );

if ( includeHeader )
{
text += mTable->headerItem()->text( Columns::X ) + separator;
text += mTable->headerItem()->text( Columns::Y ) + separator;
text += mTable->headerItem()->text( Columns::Distance ) + QStringLiteral( "\n" );
}

while ( *it )
{
text += ( *it )->text( 0 ) + QStringLiteral( "\n" );
text += ( *it )->text( Columns::X ) + separator;
text += ( *it )->text( Columns::Y ) + separator;
text += ( *it )->text( Columns::Distance ) + QStringLiteral( "\n" );
it++;
}

clipboard->setText( text );

// Display a message to the user
QgisApp::instance()->messageBar()->pushInfo( tr( "Measure" ), tr( "Measurements copied to clipboard" ) );
}

void QgsMeasureDialog::reject()
Expand Down

0 comments on commit 2d4f1a8

Please sign in to comment.