Skip to content

Commit

Permalink
Merge pull request #494 from palmerj/wfs_ui_improvements
Browse files Browse the repository at this point in the history
WFS Layer Selection UI Improvements
  • Loading branch information
timlinux committed Apr 2, 2013
2 parents 4f6c2d2 + 60c20ab commit 45b931b
Show file tree
Hide file tree
Showing 3 changed files with 312 additions and 159 deletions.
247 changes: 183 additions & 64 deletions src/providers/wfs/qgswfssourceselect.cpp
Expand Up @@ -35,6 +35,7 @@
#include <QMessageBox>
#include <QSettings>
#include <QFileDialog>
#include <QPainter>


QgsWFSSourceSelect::QgsWFSSourceSelect( QWidget* parent, Qt::WFlags fl, bool embeddedMode )
Expand All @@ -43,40 +44,74 @@ QgsWFSSourceSelect::QgsWFSSourceSelect( QWidget* parent, Qt::WFlags fl, bool emb
{
setupUi( this );

btnAdd = buttonBox->button( QDialogButtonBox::Apply );
btnAdd->setEnabled( false );

if ( embeddedMode )
{
buttonBox->button( QDialogButtonBox::Apply )->hide();
buttonBox->button( QDialogButtonBox::Close )->hide();
}

connect( buttonBox->button( QDialogButtonBox::Apply ), SIGNAL( clicked() ), this, SLOT( addLayer() ) );
mAddButton = new QPushButton( tr( "&Add" ) );
mAddButton->setEnabled( false );

mBuildQueryButton = new QPushButton( tr( "&Build query" ) );
mBuildQueryButton->setToolTip( tr( "Build query" ) );
mBuildQueryButton->setDisabled( true );


buttonBox->addButton( mAddButton, QDialogButtonBox::ActionRole );
connect( mAddButton, SIGNAL( clicked() ), this, SLOT( addLayer() ) );

buttonBox->addButton( mBuildQueryButton, QDialogButtonBox::ActionRole );
connect( mBuildQueryButton, SIGNAL( clicked() ), this, SLOT( on_mBuildQueryButton_clicked() ) );

connect( buttonBox, SIGNAL( rejected() ), this, SLOT( reject() ) );
connect( btnNew, SIGNAL( clicked() ), this, SLOT( addEntryToServerList() ) );
connect( btnEdit, SIGNAL( clicked() ), this, SLOT( modifyEntryOfServerList() ) );
connect( btnDelete, SIGNAL( clicked() ), this, SLOT( deleteEntryOfServerList() ) );
connect( btnConnect, SIGNAL( clicked() ), this, SLOT( connectToServer() ) );
connect( btnChangeSpatialRefSys, SIGNAL( clicked() ), this, SLOT( changeCRS() ) );
connect( treeWidget, SIGNAL( currentItemChanged( QTreeWidgetItem*, QTreeWidgetItem* ) ), this, SLOT( changeCRSFilter() ) );
connect( lineFilter, SIGNAL( textChanged( QString ) ), this, SLOT( filterChanged( QString ) ) );
populateConnectionList();
mProjectionSelector = new QgsGenericProjectionSelector( this );
mProjectionSelector->setMessage();

mItemDelegate = new QgsWFSItemDelegate( treeView );
treeView->setItemDelegate( mItemDelegate );

QSettings settings;
QgsDebugMsg( "restoring geometry" );
QgsDebugMsg( "restoring settings" );
restoreGeometry( settings.value( "/Windows/WFSSourceSelect/geometry" ).toByteArray() );
cbxUseTitleLayerName->setChecked( settings.value( "/Windows/WFSSourceSelect/UseTitleLayerName", false ).toBool() );

mModel = new QStandardItemModel();
mModel->setHorizontalHeaderItem( 0, new QStandardItem( "Title" ) );
mModel->setHorizontalHeaderItem( 1, new QStandardItem( "Name" ) );
mModel->setHorizontalHeaderItem( 2, new QStandardItem( "Abstract" ) );
mModel->setHorizontalHeaderItem( 3, new QStandardItem( "Cache Feature" ) );
mModel->setHorizontalHeaderItem( 4, new QStandardItem( "Filter" ) );

mModelProxy = new QSortFilterProxyModel( this );
mModelProxy->setSourceModel( mModel );
mModelProxy->setSortCaseSensitivity( Qt::CaseInsensitive );
treeView->setModel( mModelProxy );

connect( treeView, SIGNAL( doubleClicked(const QModelIndex&) ), this, SLOT( on_treeWidget_itemDoubleClicked(const QModelIndex&) ) );
connect( treeView->selectionModel(), SIGNAL( currentRowChanged ( QModelIndex, QModelIndex) ), this, SLOT( on_treeWidget_currentRowChanged(const QModelIndex&, const QModelIndex&) ) );
}

QgsWFSSourceSelect::~QgsWFSSourceSelect()
{
QSettings settings;
QgsDebugMsg( "saving geometry" );
QgsDebugMsg( "saving settings" );
settings.setValue( "/Windows/WFSSourceSelect/geometry", saveGeometry() );
settings.setValue( "/Windows/WFSSourceSelect/UseTitleLayerName", cbxUseTitleLayerName->isChecked() );

delete mItemDelegate;
delete mProjectionSelector;
delete mCapabilities;
delete mModel;
delete mModelProxy;
delete mAddButton;
delete mBuildQueryButton;
}

void QgsWFSSourceSelect::populateConnectionList()
Expand Down Expand Up @@ -183,13 +218,18 @@ void QgsWFSSourceSelect::capabilitiesReplyFinished()
foreach ( QgsWFSCapabilities::FeatureType featureType, caps.featureTypes )
{
// insert the typenames, titles and abstracts into the tree view
QTreeWidgetItem* newItem = new QTreeWidgetItem();
newItem->setText( 0, featureType.title );
newItem->setText( 1, featureType.name );
newItem->setText( 2, featureType.abstract );
newItem->setToolTip( 2, "<font color=black>" + featureType.abstract + "</font>" );
newItem->setCheckState( 3, Qt::Checked );
treeWidget->addTopLevelItem( newItem );
QStandardItem* titleItem = new QStandardItem( featureType.title );
QStandardItem* nameItem = new QStandardItem( featureType.name );
QStandardItem* abstractItem = new QStandardItem( featureType.abstract );
abstractItem->setToolTip( "<font color=black>" + featureType.abstract + "</font>" );
abstractItem->setTextAlignment( Qt::AlignLeft | Qt::AlignTop );
QStandardItem* cachedItem = new QStandardItem();
QStandardItem* filterItem = new QStandardItem();
cachedItem->setCheckable( true );
cachedItem->setCheckState( Qt::Checked );

typedef QList< QStandardItem* > StandardItemList;
mModel->appendRow( StandardItemList() << titleItem << nameItem << abstractItem << cachedItem << filterItem);

// insert the available CRS into mAvailableCRS
std::list<QString> currentCRSList;
Expand All @@ -202,14 +242,30 @@ void QgsWFSSourceSelect::capabilitiesReplyFinished()

if ( caps.featureTypes.count() > 0 )
{
btnAdd->setEnabled( true );
treeWidget->setCurrentItem( treeWidget->topLevelItem( 0 ) );
treeView->resizeColumnToContents( 0 );
treeView->resizeColumnToContents( 1 );
treeView->resizeColumnToContents( 2 );
treeView->resizeColumnToContents( 3 );
for ( int i = 0; i < 2; i++ )
{
if ( treeView->columnWidth( i ) > 300 )
{
treeView->setColumnWidth( i, 300 );
}
}
if ( treeView->columnWidth( 2 ) > 150 )
{
treeView->setColumnWidth( 2, 150 );
}
btnChangeSpatialRefSys->setEnabled( true );
treeView->selectionModel()->select( mModel->index( 0, 0 ), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows );
treeView->setFocus();
}
else
{
QMessageBox::information( 0, tr( "No Layers" ), tr( "capabilities document contained no layers." ) );
btnAdd->setEnabled( false );
mAddButton->setEnabled( false );
mBuildQueryButton->setEnabled( false );
}
}

Expand Down Expand Up @@ -253,8 +309,10 @@ void QgsWFSSourceSelect::deleteEntryOfServerList()
void QgsWFSSourceSelect::connectToServer()
{
btnConnect->setEnabled( false );
treeWidget->clear();

if ( mModel )
{
mModel->removeRows( 0, mModel->rowCount() );
}
if ( mCapabilities )
{
mCapabilities->requestCapabilities();
Expand All @@ -264,16 +322,13 @@ void QgsWFSSourceSelect::connectToServer()

void QgsWFSSourceSelect::addLayer()
{
//get selected entry in lstWidget
QTreeWidgetItem* tItem = treeWidget->currentItem();
if ( !tItem )
//get selected entry in treeview
QModelIndex currentIndex = treeView->selectionModel()->currentIndex();
if ( !currentIndex.isValid() )
{
return;
}

QList<QTreeWidgetItem*> selectedItems = treeWidget->selectedItems();
QList<QTreeWidgetItem*>::const_iterator sIt = selectedItems.constBegin();

QgsOWSConnection connection( "WFS", cmbConnections->currentText() );
QgsWFSCapabilities conn( connection.uri().encodedUri() );

Expand All @@ -284,8 +339,6 @@ void QgsWFSSourceSelect::addLayer()
QVariant extentVariant = property( "MapExtent" );
if ( extentVariant.isValid() )
{
QString crs;
QgsCoordinateTransform xform;
QString extentString = extentVariant.toString();
QStringList minMaxSplit = extentString.split( ":" );
if ( minMaxSplit.size() > 1 )
Expand All @@ -312,25 +365,82 @@ void QgsWFSSourceSelect::addLayer()
}
}
}

//create layers that user selected from this WFS source
for ( ; sIt != selectedItems.constEnd(); ++sIt )
QModelIndexList list = treeView->selectionModel()->selectedRows();
for ( int i = 0; i < list.size(); i++ )
{ //add a wfs layer to the map
QString typeName = ( *sIt )->text( 1 ); //WFS repository's name for layer
QString filter = ( *sIt )->text( 4 ); //optional filter specified by user
QModelIndex idx = mModelProxy->mapToSource( list[i] );
if ( !idx.isValid() )
{
continue;
}
int row = idx.row();
QString typeName = mModel->item( row, 1 )->text(); //WFS repository's name for layer
QString titleName = mModel->item( row, 0 )->text(); //WFS type name title for layer name (if option is set)
QString filter = mModel->item( row, 4 )->text(); //optional filter specified by user
QString layerName = typeName;
if ( cbxUseTitleLayerName->isChecked() && !titleName.isEmpty() )
{
layerName = titleName;
}
QgsDebugMsg( "Layer " + typeName + " Filter is " + filter );
//is "cache features" checked?
if (( *sIt )->checkState( 3 ) == Qt::Checked )
if ( mModel->item( row, 3 )->checkState() == Qt::Checked )
{ //yes: entire WFS layer will be retrieved and cached
mUri = conn.uriGetFeature( typeName, pCrsString, filter );
}
else
{ //no: include BBOX of current canvas extent in URI
mUri = conn.uriGetFeature( typeName, pCrsString, filter, extent );
}
emit addWfsLayer( mUri, typeName );
emit addWfsLayer( mUri, layerName );
}
accept();
}

void QgsWFSSourceSelect::buildQuery( const QModelIndex& index )
{
if ( !index.isValid() )
{
return;
}
QModelIndex filterIndex = index.sibling( index.row(), 4 );
QString typeName = index.sibling( index.row(), 1 ).data().toString();

//get available fields for wfs layer
QgsWFSProvider p( "" ); //bypasses most provider instantiation logic
QgsOWSConnection connection( "WFS", cmbConnections->currentText() );
QgsWFSCapabilities conn( connection.uri().encodedUri() );
QString uri = conn.uriDescribeFeatureType( typeName );

QgsFields fields;
QString geometryAttribute;
QGis::WkbType geomType;
if ( p.describeFeatureType( uri, geometryAttribute, fields, geomType ) != 0 )
{
return;
}

//show expression builder
QgsExpressionBuilderDialog d( 0, filterIndex.data().toString() );

//add available attributes to expression builder
QgsExpressionBuilderWidget* w = d.expressionBuilder();
if ( !w )
{
return;
}

w->loadFieldNames( fields );

if ( d.exec() == QDialog::Accepted )
{
QgsDebugMsg( "Expression text = " + w->expressionText() );
mModelProxy->setData( filterIndex, QVariant( w->expressionText() ) );
}
}

void QgsWFSSourceSelect::changeCRS()
{
if ( mProjectionSelector->exec() )
Expand All @@ -342,11 +452,12 @@ void QgsWFSSourceSelect::changeCRS()

void QgsWFSSourceSelect::changeCRSFilter()
{
QgsDebugMsg("changeCRSFilter called");
//evaluate currently selected typename and set the CRS filter in mProjectionSelector
QTreeWidgetItem* currentTreeItem = treeWidget->currentItem();
if ( currentTreeItem )
QModelIndex currentIndex = treeView->selectionModel()->currentIndex();
if ( currentIndex.isValid() )
{
QString currentTypename = currentTreeItem->text( 1 );
QString currentTypename = currentIndex.sibling( currentIndex.row(), 1 ).data().toString();
QgsDebugMsg( QString( "the current typename is: %1" ).arg( currentTypename ) );

std::map<QString, std::list<QString> >::const_iterator crsIterator = mAvailableCRS.find( currentTypename );
Expand Down Expand Up @@ -410,39 +521,47 @@ void QgsWFSSourceSelect::on_btnLoad_clicked()
emit connectionsChanged();
}

void QgsWFSSourceSelect::on_treeWidget_itemDoubleClicked( QTreeWidgetItem* item, int column )
void QgsWFSSourceSelect::on_treeWidget_itemDoubleClicked( const QModelIndex& index )
{
if ( item && column == 4 )
{
//get available fields for wfs layer
QgsWFSProvider p( "" ); //bypasses most provider instantiation logic
QgsOWSConnection connection( "WFS", cmbConnections->currentText() );
QgsWFSCapabilities conn( connection.uri().encodedUri() );
QString uri = conn.uriDescribeFeatureType( item->text( 1 ) );

QgsFields fields;
QString geometryAttribute;
QGis::WkbType geomType;
if ( p.describeFeatureType( uri, geometryAttribute, fields, geomType ) != 0 )
{
return;
}
QgsDebugMsg( "double click called" );
buildQuery( index );
}

//show expression builder
QgsExpressionBuilderDialog d( 0, item->text( 3 ) );
void QgsWFSSourceSelect::on_treeWidget_currentRowChanged( const QModelIndex & current, const QModelIndex & previous)
{
Q_UNUSED( previous )
QgsDebugMsg( "treeWidget_currentRowChanged called" );
changeCRSFilter();
mBuildQueryButton->setEnabled( current.isValid() );
mAddButton->setEnabled( current.isValid() );
}

//add available attributes to expression builder
QgsExpressionBuilderWidget* w = d.expressionBuilder();
if ( !w )
{
return;
}
void QgsWFSSourceSelect::on_mBuildQueryButton_clicked()
{
QgsDebugMsg( "mBuildQueryButton click called" );
buildQuery( treeView->selectionModel()->currentIndex() );
}

w->loadFieldNames( fields );
void QgsWFSSourceSelect::filterChanged(QString text)
{
QgsDebugMsg( "WFS FeatureType filter changed to :" + text );
QRegExp::PatternSyntax mySyntax = QRegExp::PatternSyntax( QRegExp::RegExp );
Qt::CaseSensitivity myCaseSensitivity = Qt::CaseInsensitive;
QRegExp myRegExp( text, myCaseSensitivity, mySyntax );
mModelProxy->setFilterRegExp( myRegExp );
mModelProxy->sort( mModelProxy->sortColumn(), mModelProxy->sortOrder() );
}

if ( d.exec() == QDialog::Accepted )
QSize QgsWFSItemDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
QVariant indexData;
indexData = index.data(Qt::DisplayRole);
if ( indexData.isNull() )
{
item->setText( 4, w->expressionText() );
return QSize();
}
}
QString data = indexData.toString();
QSize size = option.fontMetrics.boundingRect(data).size();
size.setHeight(size.height() + 2);
return size;
}

0 comments on commit 45b931b

Please sign in to comment.