Skip to content

Commit 45b931b

Browse files
committed
Merge pull request #494 from palmerj/wfs_ui_improvements
WFS Layer Selection UI Improvements
2 parents 4f6c2d2 + 60c20ab commit 45b931b

File tree

3 files changed

+312
-159
lines changed

3 files changed

+312
-159
lines changed

src/providers/wfs/qgswfssourceselect.cpp

Lines changed: 183 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include <QMessageBox>
3636
#include <QSettings>
3737
#include <QFileDialog>
38+
#include <QPainter>
3839

3940

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

46-
btnAdd = buttonBox->button( QDialogButtonBox::Apply );
47-
btnAdd->setEnabled( false );
48-
4947
if ( embeddedMode )
5048
{
51-
buttonBox->button( QDialogButtonBox::Apply )->hide();
5249
buttonBox->button( QDialogButtonBox::Close )->hide();
5350
}
5451

55-
connect( buttonBox->button( QDialogButtonBox::Apply ), SIGNAL( clicked() ), this, SLOT( addLayer() ) );
52+
mAddButton = new QPushButton( tr( "&Add" ) );
53+
mAddButton->setEnabled( false );
54+
55+
mBuildQueryButton = new QPushButton( tr( "&Build query" ) );
56+
mBuildQueryButton->setToolTip( tr( "Build query" ) );
57+
mBuildQueryButton->setDisabled( true );
58+
59+
60+
buttonBox->addButton( mAddButton, QDialogButtonBox::ActionRole );
61+
connect( mAddButton, SIGNAL( clicked() ), this, SLOT( addLayer() ) );
62+
63+
buttonBox->addButton( mBuildQueryButton, QDialogButtonBox::ActionRole );
64+
connect( mBuildQueryButton, SIGNAL( clicked() ), this, SLOT( on_mBuildQueryButton_clicked() ) );
65+
5666
connect( buttonBox, SIGNAL( rejected() ), this, SLOT( reject() ) );
5767
connect( btnNew, SIGNAL( clicked() ), this, SLOT( addEntryToServerList() ) );
5868
connect( btnEdit, SIGNAL( clicked() ), this, SLOT( modifyEntryOfServerList() ) );
5969
connect( btnDelete, SIGNAL( clicked() ), this, SLOT( deleteEntryOfServerList() ) );
6070
connect( btnConnect, SIGNAL( clicked() ), this, SLOT( connectToServer() ) );
6171
connect( btnChangeSpatialRefSys, SIGNAL( clicked() ), this, SLOT( changeCRS() ) );
62-
connect( treeWidget, SIGNAL( currentItemChanged( QTreeWidgetItem*, QTreeWidgetItem* ) ), this, SLOT( changeCRSFilter() ) );
72+
connect( lineFilter, SIGNAL( textChanged( QString ) ), this, SLOT( filterChanged( QString ) ) );
6373
populateConnectionList();
6474
mProjectionSelector = new QgsGenericProjectionSelector( this );
6575
mProjectionSelector->setMessage();
6676

77+
mItemDelegate = new QgsWFSItemDelegate( treeView );
78+
treeView->setItemDelegate( mItemDelegate );
79+
6780
QSettings settings;
68-
QgsDebugMsg( "restoring geometry" );
81+
QgsDebugMsg( "restoring settings" );
6982
restoreGeometry( settings.value( "/Windows/WFSSourceSelect/geometry" ).toByteArray() );
83+
cbxUseTitleLayerName->setChecked( settings.value( "/Windows/WFSSourceSelect/UseTitleLayerName", false ).toBool() );
84+
85+
mModel = new QStandardItemModel();
86+
mModel->setHorizontalHeaderItem( 0, new QStandardItem( "Title" ) );
87+
mModel->setHorizontalHeaderItem( 1, new QStandardItem( "Name" ) );
88+
mModel->setHorizontalHeaderItem( 2, new QStandardItem( "Abstract" ) );
89+
mModel->setHorizontalHeaderItem( 3, new QStandardItem( "Cache Feature" ) );
90+
mModel->setHorizontalHeaderItem( 4, new QStandardItem( "Filter" ) );
91+
92+
mModelProxy = new QSortFilterProxyModel( this );
93+
mModelProxy->setSourceModel( mModel );
94+
mModelProxy->setSortCaseSensitivity( Qt::CaseInsensitive );
95+
treeView->setModel( mModelProxy );
96+
97+
connect( treeView, SIGNAL( doubleClicked(const QModelIndex&) ), this, SLOT( on_treeWidget_itemDoubleClicked(const QModelIndex&) ) );
98+
connect( treeView->selectionModel(), SIGNAL( currentRowChanged ( QModelIndex, QModelIndex) ), this, SLOT( on_treeWidget_currentRowChanged(const QModelIndex&, const QModelIndex&) ) );
7099
}
71100

72101
QgsWFSSourceSelect::~QgsWFSSourceSelect()
73102
{
74103
QSettings settings;
75-
QgsDebugMsg( "saving geometry" );
104+
QgsDebugMsg( "saving settings" );
76105
settings.setValue( "/Windows/WFSSourceSelect/geometry", saveGeometry() );
106+
settings.setValue( "/Windows/WFSSourceSelect/UseTitleLayerName", cbxUseTitleLayerName->isChecked() );
77107

108+
delete mItemDelegate;
78109
delete mProjectionSelector;
79110
delete mCapabilities;
111+
delete mModel;
112+
delete mModelProxy;
113+
delete mAddButton;
114+
delete mBuildQueryButton;
80115
}
81116

82117
void QgsWFSSourceSelect::populateConnectionList()
@@ -183,13 +218,18 @@ void QgsWFSSourceSelect::capabilitiesReplyFinished()
183218
foreach ( QgsWFSCapabilities::FeatureType featureType, caps.featureTypes )
184219
{
185220
// insert the typenames, titles and abstracts into the tree view
186-
QTreeWidgetItem* newItem = new QTreeWidgetItem();
187-
newItem->setText( 0, featureType.title );
188-
newItem->setText( 1, featureType.name );
189-
newItem->setText( 2, featureType.abstract );
190-
newItem->setToolTip( 2, "<font color=black>" + featureType.abstract + "</font>" );
191-
newItem->setCheckState( 3, Qt::Checked );
192-
treeWidget->addTopLevelItem( newItem );
221+
QStandardItem* titleItem = new QStandardItem( featureType.title );
222+
QStandardItem* nameItem = new QStandardItem( featureType.name );
223+
QStandardItem* abstractItem = new QStandardItem( featureType.abstract );
224+
abstractItem->setToolTip( "<font color=black>" + featureType.abstract + "</font>" );
225+
abstractItem->setTextAlignment( Qt::AlignLeft | Qt::AlignTop );
226+
QStandardItem* cachedItem = new QStandardItem();
227+
QStandardItem* filterItem = new QStandardItem();
228+
cachedItem->setCheckable( true );
229+
cachedItem->setCheckState( Qt::Checked );
230+
231+
typedef QList< QStandardItem* > StandardItemList;
232+
mModel->appendRow( StandardItemList() << titleItem << nameItem << abstractItem << cachedItem << filterItem);
193233

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

203243
if ( caps.featureTypes.count() > 0 )
204244
{
205-
btnAdd->setEnabled( true );
206-
treeWidget->setCurrentItem( treeWidget->topLevelItem( 0 ) );
245+
treeView->resizeColumnToContents( 0 );
246+
treeView->resizeColumnToContents( 1 );
247+
treeView->resizeColumnToContents( 2 );
248+
treeView->resizeColumnToContents( 3 );
249+
for ( int i = 0; i < 2; i++ )
250+
{
251+
if ( treeView->columnWidth( i ) > 300 )
252+
{
253+
treeView->setColumnWidth( i, 300 );
254+
}
255+
}
256+
if ( treeView->columnWidth( 2 ) > 150 )
257+
{
258+
treeView->setColumnWidth( 2, 150 );
259+
}
207260
btnChangeSpatialRefSys->setEnabled( true );
261+
treeView->selectionModel()->select( mModel->index( 0, 0 ), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows );
262+
treeView->setFocus();
208263
}
209264
else
210265
{
211266
QMessageBox::information( 0, tr( "No Layers" ), tr( "capabilities document contained no layers." ) );
212-
btnAdd->setEnabled( false );
267+
mAddButton->setEnabled( false );
268+
mBuildQueryButton->setEnabled( false );
213269
}
214270
}
215271

@@ -253,8 +309,10 @@ void QgsWFSSourceSelect::deleteEntryOfServerList()
253309
void QgsWFSSourceSelect::connectToServer()
254310
{
255311
btnConnect->setEnabled( false );
256-
treeWidget->clear();
257-
312+
if ( mModel )
313+
{
314+
mModel->removeRows( 0, mModel->rowCount() );
315+
}
258316
if ( mCapabilities )
259317
{
260318
mCapabilities->requestCapabilities();
@@ -264,16 +322,13 @@ void QgsWFSSourceSelect::connectToServer()
264322

265323
void QgsWFSSourceSelect::addLayer()
266324
{
267-
//get selected entry in lstWidget
268-
QTreeWidgetItem* tItem = treeWidget->currentItem();
269-
if ( !tItem )
325+
//get selected entry in treeview
326+
QModelIndex currentIndex = treeView->selectionModel()->currentIndex();
327+
if ( !currentIndex.isValid() )
270328
{
271329
return;
272330
}
273331

274-
QList<QTreeWidgetItem*> selectedItems = treeWidget->selectedItems();
275-
QList<QTreeWidgetItem*>::const_iterator sIt = selectedItems.constBegin();
276-
277332
QgsOWSConnection connection( "WFS", cmbConnections->currentText() );
278333
QgsWFSCapabilities conn( connection.uri().encodedUri() );
279334

@@ -284,8 +339,6 @@ void QgsWFSSourceSelect::addLayer()
284339
QVariant extentVariant = property( "MapExtent" );
285340
if ( extentVariant.isValid() )
286341
{
287-
QString crs;
288-
QgsCoordinateTransform xform;
289342
QString extentString = extentVariant.toString();
290343
QStringList minMaxSplit = extentString.split( ":" );
291344
if ( minMaxSplit.size() > 1 )
@@ -312,25 +365,82 @@ void QgsWFSSourceSelect::addLayer()
312365
}
313366
}
314367
}
368+
315369
//create layers that user selected from this WFS source
316-
for ( ; sIt != selectedItems.constEnd(); ++sIt )
370+
QModelIndexList list = treeView->selectionModel()->selectedRows();
371+
for ( int i = 0; i < list.size(); i++ )
317372
{ //add a wfs layer to the map
318-
QString typeName = ( *sIt )->text( 1 ); //WFS repository's name for layer
319-
QString filter = ( *sIt )->text( 4 ); //optional filter specified by user
373+
QModelIndex idx = mModelProxy->mapToSource( list[i] );
374+
if ( !idx.isValid() )
375+
{
376+
continue;
377+
}
378+
int row = idx.row();
379+
QString typeName = mModel->item( row, 1 )->text(); //WFS repository's name for layer
380+
QString titleName = mModel->item( row, 0 )->text(); //WFS type name title for layer name (if option is set)
381+
QString filter = mModel->item( row, 4 )->text(); //optional filter specified by user
382+
QString layerName = typeName;
383+
if ( cbxUseTitleLayerName->isChecked() && !titleName.isEmpty() )
384+
{
385+
layerName = titleName;
386+
}
387+
QgsDebugMsg( "Layer " + typeName + " Filter is " + filter );
320388
//is "cache features" checked?
321-
if (( *sIt )->checkState( 3 ) == Qt::Checked )
389+
if ( mModel->item( row, 3 )->checkState() == Qt::Checked )
322390
{ //yes: entire WFS layer will be retrieved and cached
323391
mUri = conn.uriGetFeature( typeName, pCrsString, filter );
324392
}
325393
else
326394
{ //no: include BBOX of current canvas extent in URI
327395
mUri = conn.uriGetFeature( typeName, pCrsString, filter, extent );
328396
}
329-
emit addWfsLayer( mUri, typeName );
397+
emit addWfsLayer( mUri, layerName );
330398
}
331399
accept();
332400
}
333401

402+
void QgsWFSSourceSelect::buildQuery( const QModelIndex& index )
403+
{
404+
if ( !index.isValid() )
405+
{
406+
return;
407+
}
408+
QModelIndex filterIndex = index.sibling( index.row(), 4 );
409+
QString typeName = index.sibling( index.row(), 1 ).data().toString();
410+
411+
//get available fields for wfs layer
412+
QgsWFSProvider p( "" ); //bypasses most provider instantiation logic
413+
QgsOWSConnection connection( "WFS", cmbConnections->currentText() );
414+
QgsWFSCapabilities conn( connection.uri().encodedUri() );
415+
QString uri = conn.uriDescribeFeatureType( typeName );
416+
417+
QgsFields fields;
418+
QString geometryAttribute;
419+
QGis::WkbType geomType;
420+
if ( p.describeFeatureType( uri, geometryAttribute, fields, geomType ) != 0 )
421+
{
422+
return;
423+
}
424+
425+
//show expression builder
426+
QgsExpressionBuilderDialog d( 0, filterIndex.data().toString() );
427+
428+
//add available attributes to expression builder
429+
QgsExpressionBuilderWidget* w = d.expressionBuilder();
430+
if ( !w )
431+
{
432+
return;
433+
}
434+
435+
w->loadFieldNames( fields );
436+
437+
if ( d.exec() == QDialog::Accepted )
438+
{
439+
QgsDebugMsg( "Expression text = " + w->expressionText() );
440+
mModelProxy->setData( filterIndex, QVariant( w->expressionText() ) );
441+
}
442+
}
443+
334444
void QgsWFSSourceSelect::changeCRS()
335445
{
336446
if ( mProjectionSelector->exec() )
@@ -342,11 +452,12 @@ void QgsWFSSourceSelect::changeCRS()
342452

343453
void QgsWFSSourceSelect::changeCRSFilter()
344454
{
455+
QgsDebugMsg("changeCRSFilter called");
345456
//evaluate currently selected typename and set the CRS filter in mProjectionSelector
346-
QTreeWidgetItem* currentTreeItem = treeWidget->currentItem();
347-
if ( currentTreeItem )
457+
QModelIndex currentIndex = treeView->selectionModel()->currentIndex();
458+
if ( currentIndex.isValid() )
348459
{
349-
QString currentTypename = currentTreeItem->text( 1 );
460+
QString currentTypename = currentIndex.sibling( currentIndex.row(), 1 ).data().toString();
350461
QgsDebugMsg( QString( "the current typename is: %1" ).arg( currentTypename ) );
351462

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

413-
void QgsWFSSourceSelect::on_treeWidget_itemDoubleClicked( QTreeWidgetItem* item, int column )
524+
void QgsWFSSourceSelect::on_treeWidget_itemDoubleClicked( const QModelIndex& index )
414525
{
415-
if ( item && column == 4 )
416-
{
417-
//get available fields for wfs layer
418-
QgsWFSProvider p( "" ); //bypasses most provider instantiation logic
419-
QgsOWSConnection connection( "WFS", cmbConnections->currentText() );
420-
QgsWFSCapabilities conn( connection.uri().encodedUri() );
421-
QString uri = conn.uriDescribeFeatureType( item->text( 1 ) );
422-
423-
QgsFields fields;
424-
QString geometryAttribute;
425-
QGis::WkbType geomType;
426-
if ( p.describeFeatureType( uri, geometryAttribute, fields, geomType ) != 0 )
427-
{
428-
return;
429-
}
526+
QgsDebugMsg( "double click called" );
527+
buildQuery( index );
528+
}
430529

431-
//show expression builder
432-
QgsExpressionBuilderDialog d( 0, item->text( 3 ) );
530+
void QgsWFSSourceSelect::on_treeWidget_currentRowChanged( const QModelIndex & current, const QModelIndex & previous)
531+
{
532+
Q_UNUSED( previous )
533+
QgsDebugMsg( "treeWidget_currentRowChanged called" );
534+
changeCRSFilter();
535+
mBuildQueryButton->setEnabled( current.isValid() );
536+
mAddButton->setEnabled( current.isValid() );
537+
}
433538

434-
//add available attributes to expression builder
435-
QgsExpressionBuilderWidget* w = d.expressionBuilder();
436-
if ( !w )
437-
{
438-
return;
439-
}
539+
void QgsWFSSourceSelect::on_mBuildQueryButton_clicked()
540+
{
541+
QgsDebugMsg( "mBuildQueryButton click called" );
542+
buildQuery( treeView->selectionModel()->currentIndex() );
543+
}
440544

441-
w->loadFieldNames( fields );
545+
void QgsWFSSourceSelect::filterChanged(QString text)
546+
{
547+
QgsDebugMsg( "WFS FeatureType filter changed to :" + text );
548+
QRegExp::PatternSyntax mySyntax = QRegExp::PatternSyntax( QRegExp::RegExp );
549+
Qt::CaseSensitivity myCaseSensitivity = Qt::CaseInsensitive;
550+
QRegExp myRegExp( text, myCaseSensitivity, mySyntax );
551+
mModelProxy->setFilterRegExp( myRegExp );
552+
mModelProxy->sort( mModelProxy->sortColumn(), mModelProxy->sortOrder() );
553+
}
442554

443-
if ( d.exec() == QDialog::Accepted )
555+
QSize QgsWFSItemDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
556+
{
557+
QVariant indexData;
558+
indexData = index.data(Qt::DisplayRole);
559+
if ( indexData.isNull() )
444560
{
445-
item->setText( 4, w->expressionText() );
561+
return QSize();
446562
}
447-
}
563+
QString data = indexData.toString();
564+
QSize size = option.fontMetrics.boundingRect(data).size();
565+
size.setHeight(size.height() + 2);
566+
return size;
448567
}

0 commit comments

Comments
 (0)