Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Further tweaks and fixes for transformation selection dialog #30540

Merged
merged 4 commits into from
Jul 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions python/core/auto_generated/qgsdatumtransform.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ and ``destinationTransformId`` transforms.
QString scope;

QString remarks;

QString areaOfUse;
};

struct TransformDetails
Expand All @@ -95,8 +97,14 @@ and ``destinationTransformId`` transforms.
QString name;
double accuracy;

QString scope;

QString remarks;

bool isAvailable;

QString areaOfUse;

QList< QgsDatumTransform::GridDetails > grids;

QList< QgsDatumTransform::SingleOperationDetails > operationDetails;
Expand Down
17 changes: 17 additions & 0 deletions src/core/qgsdatumtransform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,17 @@ QgsDatumTransform::TransformDetails QgsDatumTransform::transformDetailsFromPj( P
details.accuracy = proj_coordoperation_get_accuracy( pjContext, op );
details.isAvailable = proj_coordoperation_is_instantiable( pjContext, op );

const char *areaOfUseName = nullptr;
if ( proj_get_area_of_use( pjContext, op, nullptr, nullptr, nullptr, nullptr, &areaOfUseName ) )
{
details.areaOfUse = QString( areaOfUseName );
}

#if PROJ_VERSION_MAJOR > 6 or PROJ_VERSION_MINOR >= 2
details.remarks = QString( proj_get_remarks( op ) );
details.scope = QString( proj_get_scope( op ) );
#endif

for ( int j = 0; j < proj_coordoperation_get_grid_used_count( pjContext, op ); ++j )
{
const char *shortName = nullptr;
Expand Down Expand Up @@ -354,6 +365,12 @@ QgsDatumTransform::TransformDetails QgsDatumTransform::transformDetailsFromPj( P
SingleOperationDetails singleOpDetails;
singleOpDetails.remarks = QString( proj_get_remarks( step.get() ) );
singleOpDetails.scope = QString( proj_get_scope( step.get() ) );

const char *areaOfUseName = nullptr;
if ( proj_get_area_of_use( pjContext, step.get(), nullptr, nullptr, nullptr, nullptr, &areaOfUseName ) )
{
singleOpDetails.areaOfUse = QString( areaOfUseName );
}
details.operationDetails.append( singleOpDetails );
}
}
Expand Down
27 changes: 27 additions & 0 deletions src/core/qgsdatumtransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@ class CORE_EXPORT QgsDatumTransform

//! Remarks for operation, from EPSG registry database
QString remarks;

//! Area of use, from EPSG registry database
QString areaOfUse;
};

/**
Expand All @@ -177,6 +180,22 @@ class CORE_EXPORT QgsDatumTransform
//! Transformation accuracy (in meters)
double accuracy = 0;

/**
* Scope of operation, from EPSG registry database.
*
* This is only available for single step coordinate operations. For multi-step operations, check
* \a operationDetails instead.
*/
QString scope;

/**
* Remarks for operation, from EPSG registry database.
*
* This is only available for single step coordinate operations. For multi-step operations, check
* \a operationDetails instead.
*/
QString remarks;

/**
* TRUE if operation is available.
*
Expand All @@ -185,6 +204,14 @@ class CORE_EXPORT QgsDatumTransform
*/
bool isAvailable = false;

/**
* Area of use string.
*
* This is only available for single step coordinate operations. For multi-step operations, check
* \a operationDetails instead.
*/
QString areaOfUse;

/**
* Contains a list of transform grids used by the operation.
*/
Expand Down
4 changes: 1 addition & 3 deletions src/core/qgsprojutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,7 @@ QList<QgsDatumTransform::GridDetails> QgsProjUtils::gridsUsed( const QString &pr
const QString gridName = match.captured( 1 );
QgsDatumTransform::GridDetails grid;
grid.shortName = gridName;
#if PROJ_VERSION_MAJOR >= 6
#if PROJ_VERSION_MINOR >= 2
#if PROJ_VERSION_MAJOR > 6 or PROJ_VERSION_MINOR >= 2
const char *fullName = nullptr;
const char *packageName = nullptr;
const char *url = nullptr;
Expand All @@ -219,7 +218,6 @@ QList<QgsDatumTransform::GridDetails> QgsProjUtils::gridsUsed( const QString &pr
grid.directDownload = directDownload;
grid.openLicense = openLicense;
grid.isAvailable = available;
#endif
#endif
grids.append( grid );
}
Expand Down
120 changes: 108 additions & 12 deletions src/gui/qgsdatumtransformdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ QgsDatumTransformDialog::QgsDatumTransformDialog( const QgsCoordinateReferenceSy

QgsGui::enableAutoGeometryRestore( this );

mLabelSrcDescription->setTextInteractionFlags( Qt::TextBrowserInteraction );
mLabelSrcDescription->setOpenExternalLinks( true );

if ( !showMakeDefault )
mMakeDefaultCheckBox->setVisible( false );

Expand All @@ -92,10 +95,15 @@ QgsDatumTransformDialog::QgsDatumTransformDialog( const QgsCoordinateReferenceSy
setWindowFlags( windowFlags() & ~Qt::WindowCloseButtonHint );
}

#if PROJ_VERSION_MAJOR>=6
mDatumTransformTableWidget->setColumnCount( 3 );
#else
mDatumTransformTableWidget->setColumnCount( 2 );
#endif

QStringList headers;
#if PROJ_VERSION_MAJOR>=6
headers << tr( "Transformation" ) << tr( "Accuracy (meters)" ) ;
headers << tr( "Transformation" ) << tr( "Accuracy (meters)" ) << tr( "Area of Use" );
#else
headers << tr( "Source Transform" ) << tr( "Destination Transform" ) ;
#endif
Expand Down Expand Up @@ -159,10 +167,9 @@ void QgsDatumTransformDialog::load( QPair<int, int> selectedDatumTransforms, con
Q_UNUSED( selectedDatumTransforms )
for ( const QgsDatumTransform::TransformDetails &transform : qgis::as_const( mDatumTransforms ) )
{
bool itemDisabled = !transform.isAvailable;

std::unique_ptr< QTableWidgetItem > item = qgis::make_unique< QTableWidgetItem >();
item->setData( ProjRole, transform.proj );
item->setData( AvailableRole, transform.isAvailable );
item->setFlags( item->flags() & ~Qt::ItemIsEditable );

item->setText( transform.name );
Expand All @@ -175,12 +182,55 @@ void QgsDatumTransformDialog::load( QPair<int, int> selectedDatumTransforms, con
item->setForeground( QBrush( QColor( 0, 120, 0 ) ) );
}

if ( !transform.isAvailable )
{
item->setForeground( QBrush( palette().color( QPalette::Disabled, QPalette::Text ) ) );
}

if ( preferredInitialRow < 0 && transform.isAvailable )
{
// try to select a "preferred" entry by default
preferredInitialRow = row;
}

QString missingMessage;
if ( !transform.isAvailable )
{
QStringList gridMessages;
for ( const QgsDatumTransform::GridDetails &grid : transform.grids )
{
if ( !grid.isAvailable )
{
QString m = tr( "This transformation requires the grid file “%1”, which is not available for use on the system." ).arg( grid.shortName );
if ( !grid.url.isEmpty() )
{
if ( !grid.packageName.isEmpty() )
{
m += ' ' + tr( "This grid is part of the <i>%1</i> package, available for download from <a href=\"%2\">%2</a>." ).arg( grid.packageName, grid.url );
}
else
{
m += ' ' + tr( "This grid is available for download from <a href=\"%1\">%1</a>." ).arg( grid.url );
}
}
gridMessages << m;
}
}

if ( gridMessages.count() > 1 )
{
for ( int k = 0; k < gridMessages.count(); ++k )
gridMessages[k] = QStringLiteral( "<li>%1</li>" ).arg( gridMessages.at( k ) );

missingMessage = QStringLiteral( "<ul>%1</ul" ).arg( gridMessages.join( QString() ) );
}
else if ( !gridMessages.empty() )
{
missingMessage = gridMessages.constFirst();
}
}

QStringList areasOfUse;

#if PROJ_VERSION_MAJOR > 6 or PROJ_VERSION_MINOR >= 2
QStringList opText;
Expand All @@ -197,48 +247,89 @@ void QgsDatumTransformDialog::load( QPair<int, int> selectedDatumTransforms, con
text += QStringLiteral( "<br>" );
text += QStringLiteral( "<b>%1</b>: %2" ).arg( tr( "Remarks" ), singleOpDetails.remarks );
}
if ( !singleOpDetails.areaOfUse.isEmpty() )
{
if ( !areasOfUse.contains( singleOpDetails.areaOfUse ) )
areasOfUse << singleOpDetails.areaOfUse;
}

if ( !text.isEmpty() )
{
opText.append( text );
}
}

QString text;
if ( !transform.scope.isEmpty() )
{
text += QStringLiteral( "<b>%1</b>: %2" ).arg( tr( "Scope" ), transform.scope );
}
if ( !transform.remarks.isEmpty() )
{
if ( !text.isEmpty() )
text += QStringLiteral( "<br>" );
text += QStringLiteral( "<b>%1</b>: %2" ).arg( tr( "Remarks" ), transform.remarks );
}
if ( !text.isEmpty() )
{
opText.append( text );
}

if ( opText.count() > 1 )
{
for ( int k = 0; k < opText.count(); ++k )
opText[k] = QStringLiteral( "<li>%1</li>" ).arg( opText.at( k ) );
}
#endif

if ( !transform.areaOfUse.isEmpty() && !areasOfUse.contains( transform.areaOfUse ) )
areasOfUse << transform.areaOfUse;

#if PROJ_VERSION_MAJOR > 6 or PROJ_VERSION_MINOR >= 2
const QColor disabled = palette().color( QPalette::Disabled, QPalette::Text );
const QColor active = palette().color( QPalette::Active, QPalette::Text );

const QColor codeColor( static_cast< int >( active.red() * 0.6 + disabled.red() * 0.4 ),
static_cast< int >( active.green() * 0.6 + disabled.green() * 0.4 ),
static_cast< int >( active.blue() * 0.6 + disabled.blue() * 0.4 ) );
const QString toolTipString = QStringLiteral( "<b>%1</b>" ).arg( transform.name )
+ ( !opText.empty() ? ( opText.count() == 1 ? QStringLiteral( "<p>%1</p>" ).arg( opText.at( 0 ) ) : QStringLiteral( "<ul>%1</ul>" ).arg( opText.join( QString() ) ) ) : QString() ) +
QStringLiteral( "<p><code style=\"color: %1\">%2</code></p>" ).arg( codeColor.name(), transform.proj );
+ ( !opText.empty() ? ( opText.count() == 1 ? QStringLiteral( "<p>%1</p>" ).arg( opText.at( 0 ) ) : QStringLiteral( "<ul>%1</ul>" ).arg( opText.join( QString() ) ) ) : QString() )
+ ( !areasOfUse.empty() ? QStringLiteral( "<p><b>%1</b>: %2</p>" ).arg( tr( "Area of use" ), areasOfUse.join( QStringLiteral( ", " ) ) ) : QString() )
+ ( !missingMessage.isEmpty() ? QStringLiteral( "<p><b style=\"color: red\">%1</b></p>" ).arg( missingMessage ) : QString() )
+ QStringLiteral( "<p><code style=\"color: %1\">%2</code></p>" ).arg( codeColor.name(), transform.proj );
#else
const QString toolTipString = QStringLiteral( "<b>%1</b><p><code>%2</code></p>" ).arg( transform.name, transform.proj );
const QString toolTipString = QStringLiteral( "<b>%1</b>%2%3<p><code>%4</code></p>" ).arg( transform.name,
( !transform.areaOfUse.isEmpty() ? QStringLiteral( "<p><b>%1</b>: %2</p>" ).arg( tr( "Area of use" ), transform.areaOfUse ) : QString() ),
( !missingMessage.isEmpty() ? QStringLiteral( "<p><b style=\"color: red\">%1</b></p>" ).arg( missingMessage ) : QString() ),
transform.proj );
#endif
item->setToolTip( toolTipString );
if ( itemDisabled )
{
item->setFlags( Qt::NoItemFlags );
}
mDatumTransformTableWidget->setRowCount( row + 1 );
mDatumTransformTableWidget->setItem( row, 0, item.release() );

item = qgis::make_unique< QTableWidgetItem >();
item->setFlags( item->flags() & ~Qt::ItemIsEditable );
item->setText( transform.accuracy >= 0 ? QString::number( transform.accuracy ) : tr( "Unknown" ) );
if ( itemDisabled )
item->setToolTip( toolTipString );
if ( !transform.isAvailable )
{
item->setFlags( Qt::NoItemFlags );
item->setForeground( QBrush( palette().color( QPalette::Disabled, QPalette::Text ) ) );
}
mDatumTransformTableWidget->setItem( row, 1, item.release() );

#if PROJ_VERSION_MAJOR>=6
// area of use column
item = qgis::make_unique< QTableWidgetItem >();
item->setFlags( item->flags() & ~Qt::ItemIsEditable );
item->setText( areasOfUse.join( QStringLiteral( ", " ) ) );
item->setToolTip( toolTipString );
if ( !transform.isAvailable )
{
item->setForeground( QBrush( palette().color( QPalette::Disabled, QPalette::Text ) ) );
}
mDatumTransformTableWidget->setItem( row, 2, item.release() );
#endif

if ( transform.proj == selectedProj )
{
mDatumTransformTableWidget->selectRow( row );
Expand Down Expand Up @@ -356,7 +447,12 @@ void QgsDatumTransformDialog::load( QPair<int, int> selectedDatumTransforms, con
void QgsDatumTransformDialog::setOKButtonEnabled()
{
int row = mDatumTransformTableWidget->currentRow();
#if PROJ_VERSION_MAJOR>=6
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( mSourceCrs.isValid() && mDestinationCrs.isValid()
&& mDatumTransformTableWidget->item( row, 0 ) && mDatumTransformTableWidget->item( row, 0 )->data( AvailableRole ).toBool() );
#else
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( mSourceCrs.isValid() && mDestinationCrs.isValid() && row >= 0 );
#endif
}

QgsDatumTransformDialog::~QgsDatumTransformDialog()
Expand Down
1 change: 1 addition & 0 deletions src/gui/qgsdatumtransformdialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class GUI_EXPORT QgsDatumTransformDialog : public QDialog, private Ui::QgsDatumT
{
TransformIdRole = Qt::UserRole + 1,
ProjRole,
AvailableRole,
};

bool gridShiftTransformation( const QString &itemText ) const;
Expand Down
18 changes: 15 additions & 3 deletions src/gui/qgsprojectionselectiontreewidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,15 @@ QgsProjectionSelectionTreeWidget::QgsProjectionSelectionTreeWidget( QWidget *par
mRecentProjections = QgsCoordinateReferenceSystem::recentProjections();

mCheckBoxNoProjection->setHidden( true );
mCheckBoxNoProjection->setEnabled( false );
connect( mCheckBoxNoProjection, &QCheckBox::toggled, this, &QgsProjectionSelectionTreeWidget::crsSelected );
connect( mCheckBoxNoProjection, &QCheckBox::toggled, mFrameProjections, &QFrame::setDisabled );
connect( mCheckBoxNoProjection, &QCheckBox::toggled, this, [ = ]( bool checked )
{
if ( mCheckBoxNoProjection->isEnabled() )
{
mFrameProjections->setDisabled( checked );
}
} );
}

QgsProjectionSelectionTreeWidget::~QgsProjectionSelectionTreeWidget()
Expand Down Expand Up @@ -472,7 +479,7 @@ QString QgsProjectionSelectionTreeWidget::getSelectedExpression( const QString &

QgsCoordinateReferenceSystem QgsProjectionSelectionTreeWidget::crs() const
{
if ( mCheckBoxNoProjection->isChecked() )
if ( mCheckBoxNoProjection->isEnabled() && mCheckBoxNoProjection->isChecked() )
return QgsCoordinateReferenceSystem();

int srid = getSelectedExpression( QStringLiteral( "srs_id" ) ).toLong();
Expand All @@ -484,7 +491,12 @@ QgsCoordinateReferenceSystem QgsProjectionSelectionTreeWidget::crs() const

void QgsProjectionSelectionTreeWidget::setShowNoProjection( bool show )
{
mCheckBoxNoProjection->setHidden( !show );
mCheckBoxNoProjection->setVisible( show );
mCheckBoxNoProjection->setEnabled( show );
if ( show )
{
mFrameProjections->setDisabled( mCheckBoxNoProjection->isChecked() );
}
}

void QgsProjectionSelectionTreeWidget::setShowBoundsMap( bool show )
Expand Down