Skip to content

Commit

Permalink
Add "Custom CRS" tab to projection selection dialog
Browse files Browse the repository at this point in the history
This allows users to just directly enter a custom CRS definition
(from proj or wkt), instead of requiring them to add a custom
CRS to their database.

It's much friendlier for users who just want to defined a custom
projection for e.g. an overview map.
  • Loading branch information
nyalldawson committed Jan 11, 2022
1 parent 0ad1324 commit d8de543
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 40 deletions.
7 changes: 7 additions & 0 deletions python/gui/auto_generated/qgsprojectionselectiondialog.sip.in
Expand Up @@ -105,6 +105,13 @@ Sets the dialog to require a valid selection only, preventing users from accepti
dialog if no selection is present.

.. versionadded:: 3.18
%End

bool hasValidSelection() const;
%Docstring
Returns ``True`` if the dialog has a valid CRS defined.

.. versionadded:: 3.24
%End

public slots:
Expand Down
96 changes: 88 additions & 8 deletions src/gui/qgsprojectionselectiondialog.cpp
Expand Up @@ -35,6 +35,29 @@ QgsProjectionSelectionDialog::QgsProjectionSelectionDialog( QWidget *parent,
//we will show this only when a message is set
textEdit->hide();

tabWidget->setCurrentWidget( mTabDatabase );

mCheckBoxNoProjection->setHidden( true );
mCheckBoxNoProjection->setEnabled( false );
connect( mCheckBoxNoProjection, &QCheckBox::toggled, this, [ = ]
{
#if 0
if ( !mBlockSignals )
{
emit crsSelected();
emit hasValidSelectionChanged( hasValidSelection() );
}
#endif
} );
connect( mCheckBoxNoProjection, &QCheckBox::toggled, this, [ = ]( bool checked )
{
if ( mCheckBoxNoProjection->isEnabled() )
{
tabWidget->setDisabled( checked );
}
} );


//apply selected projection upon double-click on item
connect( projectionSelector, &QgsProjectionSelectionTreeWidget::projectionDoubleClicked, this, &QgsProjectionSelectionDialog::accept );

Expand Down Expand Up @@ -65,37 +88,94 @@ void QgsProjectionSelectionDialog::showNoCrsForLayerMessage()

void QgsProjectionSelectionDialog::setShowNoProjection( bool show )
{
projectionSelector->setShowNoProjection( show );
mCheckBoxNoProjection->setVisible( show );
mCheckBoxNoProjection->setEnabled( show );
if ( show )
{
tabWidget->setDisabled( mCheckBoxNoProjection->isChecked() );
}

if ( mRequireValidSelection )
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( hasValidSelection() );
}

bool QgsProjectionSelectionDialog::showNoProjection() const
{
return projectionSelector->showNoProjection();
return !mCheckBoxNoProjection->isHidden();
}

void QgsProjectionSelectionDialog::setNotSetText( const QString &text )
{
projectionSelector->setNotSetText( text );
mCheckBoxNoProjection->setText( text );
}

void QgsProjectionSelectionDialog::setRequireValidSelection()
{
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( projectionSelector->hasValidSelection() );
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( hasValidSelection() );

connect( projectionSelector, &QgsProjectionSelectionTreeWidget::hasValidSelectionChanged, this, [ = ]( bool )
{
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( hasValidSelection() );
} );

connect( projectionSelector, &QgsProjectionSelectionTreeWidget::hasValidSelectionChanged, this, [ = ]( bool isValid )
connect( mCheckBoxNoProjection, &QCheckBox::toggled, this, [ = ]( bool )
{
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( isValid );
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( hasValidSelection() );
} );

connect( mCrsDefinitionWidget, &QgsCrsDefinitionWidget::crsChanged, this, [ = ]()
{
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( hasValidSelection() );
} );

connect( tabWidget, &QTabWidget::currentChanged, this, [ = ]()
{
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( hasValidSelection() );
} );
}

bool QgsProjectionSelectionDialog::hasValidSelection() const
{
if ( mCheckBoxNoProjection->isChecked() )
return true;

if ( tabWidget->currentWidget() == mTabCustom )
return mCrsDefinitionWidget->crs().isValid();
else
return projectionSelector->hasValidSelection();
}

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

if ( tabWidget->currentWidget() == mTabCustom )
return mCrsDefinitionWidget->crs();
else
return projectionSelector->crs();
}

void QgsProjectionSelectionDialog::setCrs( const QgsCoordinateReferenceSystem &crs )
{
projectionSelector->setCrs( crs );
if ( !crs.isValid() )
{
mCheckBoxNoProjection->setChecked( true );
}
else
{
mCheckBoxNoProjection->setChecked( false );

projectionSelector->setCrs( crs );
mCrsDefinitionWidget->setCrs( crs );
if ( crs.isValid() && crs.authid().isEmpty() )
tabWidget->setCurrentWidget( mTabCustom );
else
tabWidget->setCurrentWidget( mTabDatabase );
}

if ( mRequireValidSelection )
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( hasValidSelection() );
}

void QgsProjectionSelectionDialog::setOgcWmsCrsFilter( const QSet<QString> &crsFilter )
Expand Down
11 changes: 11 additions & 0 deletions src/gui/qgsprojectionselectiondialog.h
Expand Up @@ -114,6 +114,13 @@ class GUI_EXPORT QgsProjectionSelectionDialog : public QDialog, private Ui::QgsG
*/
void setRequireValidSelection();

/**
* Returns TRUE if the dialog has a valid CRS defined.
*
* \since QGIS 3.24
*/
bool hasValidSelection() const;

public slots:

/**
Expand All @@ -140,6 +147,10 @@ class GUI_EXPORT QgsProjectionSelectionDialog : public QDialog, private Ui::QgsG
private slots:

void showHelp();

private:

bool mRequireValidSelection = false;
};

#endif // #ifndef QGSLAYERCRSSELECTOR_H
104 changes: 72 additions & 32 deletions src/ui/qgsgenericprojectionselectorbase.ui
Expand Up @@ -20,42 +20,76 @@
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QSplitter" name="mSplitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
<widget class="QCheckBox" name="mCheckBoxNoProjection">
<property name="toolTip">
<string>Use this option to treat all coordinates as Cartesian coordinates in an unknown reference system.</string>
</property>
<property name="childrenCollapsible">
<bool>false</bool>
<property name="text">
<string>No CRS (or unknown/non-Earth projection)</string>
</property>
</widget>
</item>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QTextEdit" name="textEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>160</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="lineWidth">
<number>2</number>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<widget class="QWidget" name="mTabDatabase">
<attribute name="title">
<string>CRS Database</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QSplitter" name="mSplitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="childrenCollapsible">
<bool>false</bool>
</property>
<widget class="QTextEdit" name="textEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>160</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="lineWidth">
<number>2</number>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
<widget class="QgsProjectionSelectionTreeWidget" name="projectionSelector" native="true"/>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="mTabCustom">
<attribute name="title">
<string>Custom CRS</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QgsCrsDefinitionWidget" name="mCrsDefinitionWidget" native="true"/>
</item>
</layout>
</widget>
<widget class="QgsProjectionSelectionTreeWidget" name="projectionSelector" native="true"/>
</widget>
</item>
<item>
Expand All @@ -72,6 +106,12 @@
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>QgsCrsDefinitionWidget</class>
<extends>QWidget</extends>
<header>qgscrsdefinitionwidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsProjectionSelectionTreeWidget</class>
<extends>QWidget</extends>
Expand Down

0 comments on commit d8de543

Please sign in to comment.