32
32
#include " qgsmessagebar.h"
33
33
#include " qgsrelationreferenceconfigdlg.h"
34
34
#include " qgsvectorlayer.h"
35
+ #include " qgsattributetablemodel.h"
35
36
36
37
bool orderByLessThan ( const QgsRelationReferenceWidget::ValueRelationItem& p1
37
38
, const QgsRelationReferenceWidget::ValueRelationItem& p2 )
@@ -58,7 +59,6 @@ QgsRelationReferenceWidget::QgsRelationReferenceWidget( QWidget* parent )
58
59
, mCanvas( NULL )
59
60
, mMessageBar( NULL )
60
61
, mForeignKey( QVariant() )
61
- , mFeatureId( QgsFeatureId() )
62
62
, mFkeyFieldIdx( -1 )
63
63
, mAllowNull( true )
64
64
, mHighlight( NULL )
@@ -68,6 +68,9 @@ QgsRelationReferenceWidget::QgsRelationReferenceWidget( QWidget* parent )
68
68
, mReferencedAttributeForm( NULL )
69
69
, mReferencedLayer( NULL )
70
70
, mReferencingLayer( NULL )
71
+ , mMasterModel( 0 )
72
+ , mFilterModel( 0 )
73
+ , mFeatureListModel( 0 )
71
74
, mWindowWidget( NULL )
72
75
, mShown( false )
73
76
, mIsEditable( true )
@@ -86,9 +89,21 @@ QgsRelationReferenceWidget::QgsRelationReferenceWidget( QWidget* parent )
86
89
editLayout->setContentsMargins ( 0 , 0 , 0 , 0 );
87
90
editLayout->setSpacing ( 2 );
88
91
92
+ // Prepare the container and layout for the filter comboboxes
93
+ mChooserGroupBox = new QGroupBox ( this );
94
+ editLayout->addWidget ( mChooserGroupBox );
95
+ QHBoxLayout* chooserLayout = new QHBoxLayout;
96
+ chooserLayout->setContentsMargins ( 0 , 0 , 0 , 0 );
97
+ mFilterLayout = new QHBoxLayout;
98
+ mFilterLayout ->setContentsMargins ( 0 , 0 , 0 , 0 );
99
+ mFilterContainer = new QWidget;
100
+ mFilterContainer ->setLayout ( mFilterLayout );
101
+ mChooserGroupBox ->setLayout ( chooserLayout );
102
+ chooserLayout->addWidget ( mFilterContainer );
103
+
89
104
// combobox (for non-geometric relation)
90
105
mComboBox = new QComboBox ( this );
91
- editLayout ->addWidget ( mComboBox );
106
+ mChooserGroupBox -> layout () ->addWidget ( mComboBox );
92
107
93
108
// read-only line edit
94
109
mLineEdit = new QLineEdit ( this );
@@ -211,6 +226,7 @@ void QgsRelationReferenceWidget::setRelationEditable( bool editable )
211
226
if ( !editable )
212
227
unsetMapTool ();
213
228
229
+ mFilterContainer ->setEnabled ( editable );
214
230
mComboBox ->setEnabled ( editable );
215
231
mMapIdentificationButton ->setEnabled ( editable );
216
232
mRemoveFKButton ->setEnabled ( editable );
@@ -225,38 +241,36 @@ void QgsRelationReferenceWidget::setForeignKey( const QVariant& value )
225
241
return ;
226
242
}
227
243
228
- QgsFeature f;
229
244
if ( !mReferencedLayer )
230
245
return ;
231
246
232
247
// TODO: Rewrite using expression
233
248
QgsFeatureIterator fit = mReferencedLayer ->getFeatures ( QgsFeatureRequest () );
234
- while ( fit.nextFeature ( f ) )
249
+ while ( fit.nextFeature ( mFeature ) )
235
250
{
236
- if ( f .attribute ( mFkeyFieldIdx ) == value )
251
+ if ( mFeature .attribute ( mFkeyFieldIdx ) == value )
237
252
{
238
253
break ;
239
254
}
240
255
}
241
256
242
- if ( !f .isValid () )
257
+ if ( !mFeature .isValid () )
243
258
{
244
259
deleteForeignKey ();
245
260
return ;
246
261
}
247
262
248
- mForeignKey = f .attribute ( mFkeyFieldIdx );
263
+ mForeignKey = mFeature .attribute ( mFkeyFieldIdx );
249
264
250
265
if ( mReadOnlySelector )
251
266
{
252
267
QgsExpression expr ( mReferencedLayer ->displayExpression () );
253
- QString title = expr.evaluate ( &f ).toString ();
268
+ QString title = expr.evaluate ( &mFeature ).toString ();
254
269
if ( expr.hasEvalError () )
255
270
{
256
- title = f .attribute ( mFkeyFieldIdx ).toString ();
271
+ title = mFeature .attribute ( mFkeyFieldIdx ).toString ();
257
272
}
258
273
mLineEdit ->setText ( title );
259
- mFeatureId = f.id ();
260
274
}
261
275
else
262
276
{
@@ -272,8 +286,8 @@ void QgsRelationReferenceWidget::setForeignKey( const QVariant& value )
272
286
}
273
287
274
288
mRemoveFKButton ->setEnabled ( mIsEditable );
275
- highlightFeature ( f );
276
- updateAttributeEditorFrame ( f );
289
+ highlightFeature ( mFeature );
290
+ updateAttributeEditorFrame ( mFeature );
277
291
emit foreignKeyChanged ( foreignKey () );
278
292
}
279
293
@@ -289,7 +303,7 @@ void QgsRelationReferenceWidget::deleteForeignKey()
289
303
}
290
304
mLineEdit ->setText ( nullText );
291
305
mForeignKey = QVariant ();
292
- mFeatureId = QgsFeatureId ( );
306
+ mFeature . setValid ( false );
293
307
}
294
308
else
295
309
{
@@ -315,7 +329,7 @@ QgsFeature QgsRelationReferenceWidget::referencedFeature()
315
329
QgsFeatureId fid;
316
330
if ( mReadOnlySelector )
317
331
{
318
- fid = mFeatureId ;
332
+ fid = mFeature . id () ;
319
333
}
320
334
else
321
335
{
@@ -366,7 +380,7 @@ void QgsRelationReferenceWidget::setEmbedForm( bool display )
366
380
367
381
void QgsRelationReferenceWidget::setReadOnlySelector ( bool readOnly )
368
382
{
369
- mComboBox ->setHidden ( readOnly );
383
+ mChooserGroupBox ->setHidden ( readOnly );
370
384
mLineEdit ->setVisible ( readOnly );
371
385
mRemoveFKButton ->setVisible ( mAllowNull && readOnly );
372
386
mReadOnlySelector = readOnly;
@@ -384,6 +398,11 @@ void QgsRelationReferenceWidget::setOrderByValue( bool orderByValue )
384
398
mOrderByValue = orderByValue;
385
399
}
386
400
401
+ void QgsRelationReferenceWidget::setFilterFields ( QStringList filterFields )
402
+ {
403
+ mFilterFields = filterFields;
404
+ }
405
+
387
406
void QgsRelationReferenceWidget::setOpenFormButtonVisible ( bool openFormButtonVisible )
388
407
{
389
408
mOpenFormButton ->setVisible ( openFormButtonVisible );
@@ -404,6 +423,69 @@ void QgsRelationReferenceWidget::init()
404
423
if ( !mReadOnlySelector && mComboBox ->count () == 0 && mReferencedLayer )
405
424
{
406
425
QApplication::setOverrideCursor ( Qt::WaitCursor );
426
+
427
+ QSet<QString> requestedAttrs;
428
+
429
+ QgsVectorLayerCache* layerCache = new QgsVectorLayerCache ( mReferencedLayer , 100000 , this );
430
+
431
+ if ( mFilterFields .size () )
432
+ {
433
+ Q_FOREACH ( const QString& fieldName, mFilterFields )
434
+ {
435
+ QVariantList uniqueValues;
436
+ int idx = mReferencedLayer ->fieldNameIndex ( fieldName );
437
+ QComboBox* cb = new QComboBox ();
438
+ cb->setProperty ( " Field" , fieldName );
439
+ mFilterComboBoxes << cb;
440
+ mReferencedLayer ->uniqueValues ( idx, uniqueValues );
441
+ cb->addItem ( mReferencedLayer ->attributeAlias ( idx ).isEmpty () ? fieldName : mReferencedLayer ->attributeAlias ( idx ) );
442
+
443
+ Q_FOREACH ( QVariant v, uniqueValues )
444
+ {
445
+ cb->addItem ( v.toString (), v );
446
+ }
447
+
448
+ connect ( cb, SIGNAL ( currentIndexChanged ( int ) ), this , SLOT ( filterChanged () ) );
449
+
450
+ // Request this attribute for caching
451
+ requestedAttrs << fieldName;
452
+
453
+ mFilterLayout ->addWidget ( cb );
454
+ }
455
+
456
+ if ( true )
457
+ {
458
+ QgsFeature ft;
459
+ QgsFeatureIterator fit = layerCache->getFeatures ();
460
+ while ( fit.nextFeature ( ft ) )
461
+ {
462
+ for ( int i = 0 ; i < mFilterComboBoxes .count () - 1 ; ++i )
463
+ {
464
+ mFilterCache [mFilterFields [i]][ft.attribute (mFilterFields [i]).toString ()] << ft.attribute ( mFilterFields [i + 1 ] ).toString ();
465
+ }
466
+ }
467
+ }
468
+ }
469
+
470
+ QgsExpression exp ( mReferencedLayer ->displayExpression () );
471
+
472
+ requestedAttrs += exp .referencedColumns ().toSet ();
473
+ requestedAttrs << mRelation .fieldPairs ().first ().second ;
474
+
475
+ QgsAttributeList attributes;
476
+ Q_FOREACH ( const QString& attr, requestedAttrs )
477
+ attributes << mReferencedLayer ->fieldNameIndex ( attr );
478
+
479
+ layerCache->setCacheSubsetOfAttributes ( attributes );
480
+ mMasterModel = new QgsAttributeTableModel ( layerCache );
481
+ mMasterModel ->setRequest ( QgsFeatureRequest ().setFlags ( QgsFeatureRequest::NoGeometry ).setSubsetOfAttributes ( requestedAttrs.toList (), mReferencedLayer ->pendingFields () ) );
482
+ mFilterModel = new QgsAttributeTableFilterModel ( mCanvas , mMasterModel , mMasterModel );
483
+ mFeatureListModel = new QgsFeatureListModel ( mFilterModel , this );
484
+ mFeatureListModel ->setDisplayExpression ( mReferencedLayer ->displayExpression () );
485
+
486
+ mMasterModel ->loadLayer ();
487
+
488
+ mComboBox ->setModel ( mFeatureListModel );
407
489
if ( mAllowNull )
408
490
{
409
491
const QString nullValue = QSettings ().value ( " qgis/nullValue" , " NULL" ).toString ();
@@ -412,12 +494,7 @@ void QgsRelationReferenceWidget::init()
412
494
mComboBox ->setItemData ( 0 , QColor ( Qt::gray ), Qt::ForegroundRole );
413
495
}
414
496
415
- QgsExpression exp ( mReferencedLayer ->displayExpression () );
416
-
417
- QStringList attrs = exp .referencedColumns ();
418
- attrs << mRelation .fieldPairs ().first ().second ;
419
-
420
- QgsFeatureIterator fit = mReferencedLayer ->getFeatures ( QgsFeatureRequest ().setFlags ( QgsFeatureRequest::NoGeometry ).setSubsetOfAttributes ( attrs, mReferencedLayer ->pendingFields () ) );
497
+ QgsFeatureIterator fit = mReferencedLayer ->getFeatures ( QgsFeatureRequest ().setFlags ( QgsFeatureRequest::NoGeometry ).setSubsetOfAttributes ( requestedAttrs.toList (), mReferencedLayer ->pendingFields () ) );
421
498
422
499
exp .prepare ( mReferencedLayer ->pendingFields () );
423
500
@@ -461,6 +538,14 @@ void QgsRelationReferenceWidget::init()
461
538
}
462
539
}
463
540
541
+ if ( true && mFeature .isValid () )
542
+ {
543
+ for ( int i = 0 ; i < mFilterFields .size (); i++ )
544
+ {
545
+ mFilterComboBoxes [i]->setCurrentIndex ( mFilterComboBoxes [i]->findText ( mFeature .attribute ( mFilterFields [i] ).toString () ) );
546
+ }
547
+ }
548
+
464
549
// Only connect after iterating, to have only one iterator on the referenced table at once
465
550
connect ( mComboBox , SIGNAL ( activated ( int ) ), this , SLOT ( comboReferenceChanged ( int ) ) );
466
551
QApplication::restoreOverrideCursor ();
@@ -634,7 +719,7 @@ void QgsRelationReferenceWidget::featureIdentified( const QgsFeature& feature )
634
719
}
635
720
mLineEdit ->setText ( title );
636
721
mForeignKey = feature.attribute ( mFkeyFieldIdx );
637
- mFeatureId = feature. id () ;
722
+ mFeature = feature;
638
723
}
639
724
else
640
725
{
@@ -674,3 +759,97 @@ void QgsRelationReferenceWidget::mapToolDeactivated()
674
759
mMessageBarItem = NULL ;
675
760
}
676
761
762
+ void QgsRelationReferenceWidget::filterChanged ()
763
+ {
764
+ QStringList filters;
765
+ QgsAttributeList attrs;
766
+
767
+ QComboBox* scb = qobject_cast<QComboBox*>( sender () );
768
+
769
+ Q_ASSERT ( scb );
770
+
771
+ if ( true )
772
+ {
773
+ QComboBox* ccb = 0 ;
774
+ Q_FOREACH ( QComboBox* cb, mFilterComboBoxes )
775
+ {
776
+ if ( ccb == 0 )
777
+ {
778
+ if ( cb != scb )
779
+ continue ;
780
+ else
781
+ {
782
+ ccb = cb;
783
+ continue ;
784
+ }
785
+ }
786
+
787
+ if ( ccb->currentIndex () == 0 )
788
+ {
789
+ cb->setCurrentIndex ( 0 );
790
+ cb->setEnabled ( false );
791
+ }
792
+ else
793
+ {
794
+ cb->blockSignals ( true );
795
+ cb->clear ();
796
+ cb->addItem ( cb->property ( " Field" ).toString () );
797
+
798
+ // ccb = scb
799
+ // cb = scb + 1
800
+ Q_FOREACH ( const QString& txt, mFilterCache [ccb->property ( " Field" ).toString ()][ccb->currentText ()] )
801
+ {
802
+ cb->addItem ( txt );
803
+ }
804
+
805
+ cb->setEnabled ( true );
806
+ cb->blockSignals ( false );
807
+
808
+ ccb = cb;
809
+ }
810
+ }
811
+ }
812
+
813
+ Q_FOREACH ( QComboBox* cb, mFilterComboBoxes )
814
+ {
815
+ if ( cb->currentIndex () != 0 )
816
+ {
817
+ const QString fieldName = cb->property ( " Field" ).toString ();
818
+
819
+ cb->itemData ( cb->currentIndex () );
820
+
821
+ if ( mReferencedLayer ->pendingFields ().field ( fieldName ).type () == QVariant::String )
822
+ {
823
+ filters << QString ( " \" %1\" = '%2'" ).arg ( fieldName ).arg ( cb->currentText () );
824
+ }
825
+ else
826
+ {
827
+ filters << QString ( " \" %1\" = %2" ).arg ( fieldName ).arg ( cb->currentText () );
828
+ }
829
+
830
+ attrs << mReferencedLayer ->fieldNameIndex ( fieldName );
831
+ }
832
+ }
833
+
834
+ QString filterExpression = filters.join ( " AND " );
835
+
836
+ QgsFeatureIterator it ( mMasterModel ->layerCache ()->getFeatures ( QgsFeatureRequest ().setFilterExpression ( filterExpression ).setSubsetOfAttributes ( attrs ) ) );
837
+
838
+ QgsFeature f;
839
+ QgsFeatureIds featureIds;
840
+
841
+ while ( it.nextFeature ( f ) )
842
+ {
843
+ featureIds << f.id ();
844
+ }
845
+
846
+ mFilterModel ->setFilteredFeatures ( featureIds );
847
+
848
+ if ( mAllowNull )
849
+ {
850
+ const QString nullValue = QSettings ().value ( " qgis/nullValue" , " NULL" ).toString ();
851
+
852
+ mComboBox ->addItem ( tr ( " %1 (no selection)" ).arg ( nullValue ), QVariant ( QVariant::Int ) );
853
+ mComboBox ->setItemData ( 0 , QColor ( Qt::gray ), Qt::ForegroundRole );
854
+ }
855
+ }
0 commit comments