31 #include <QHeaderView> 
   34 #include <QTableWidget> 
   35 #include <QStringListModel> 
   39 #include <nlohmann/json.hpp> 
   40 using namespace nlohmann;
 
   55     int cbxIdx = mComboBox->currentIndex();
 
   58       v = mComboBox->currentData();
 
   62   const int nofColumns = columnCount();
 
   66     QStringList selection;
 
   67     for ( 
int j = 0; j < mTableWidget->rowCount(); j++ )
 
   69       for ( 
int i = 0; i < nofColumns; ++i )
 
   71         QTableWidgetItem *item = mTableWidget->item( j, i );
 
   74           if ( item->checkState() == Qt::Checked )
 
   75             selection << item->data( Qt::UserRole ).toString();
 
   82     for ( 
const QString &s : std::as_const( selection ) )
 
   85       const QVariant::Type type { fkType() };
 
   88         case QVariant::Type::Int:
 
   89           vl.push_back( s.toInt() );
 
   91         case QVariant::Type::LongLong:
 
   92           vl.push_back( s.toLongLong() );
 
  100     if ( 
layer()->fields().at( 
fieldIdx() ).type() == QVariant::Map ||
 
  101          layer()->fields().at( 
fieldIdx() ).type() == QVariant::List )
 
  116       if ( item.value == mLineEdit->text() )
 
  133   mExpression = 
config().value( QStringLiteral( 
"FilterExpression" ) ).toString();
 
  135   if ( 
config( QStringLiteral( 
"AllowMulti" ) ).toBool() )
 
  137     return new QTableWidget( parent );
 
  139   else if ( 
config( QStringLiteral( 
"UseCompleter" ) ).toBool() )
 
  145     return new QComboBox( parent );
 
  152   mComboBox = qobject_cast<QComboBox *>( editor );
 
  153   mTableWidget = qobject_cast<QTableWidget *>( editor );
 
  154   mLineEdit = qobject_cast<QLineEdit *>( editor );
 
  161     connect( mComboBox, 
static_cast<void ( QComboBox::* )( 
int )
>( &QComboBox::currentIndexChanged ),
 
  164   else if ( mTableWidget )
 
  166     mTableWidget->horizontalHeader()->setSectionResizeMode( QHeaderView::Stretch );
 
  167     mTableWidget->horizontalHeader()->setVisible( 
false );
 
  168     mTableWidget->verticalHeader()->setSectionResizeMode( QHeaderView::Stretch );
 
  169     mTableWidget->verticalHeader()->setVisible( 
false );
 
  170     mTableWidget->setShowGrid( 
false );
 
  171     mTableWidget->setEditTriggers( QAbstractItemView::NoEditTriggers );
 
  172     mTableWidget->setSelectionMode( QAbstractItemView::NoSelection );
 
  175   else if ( mLineEdit )
 
  177     connect( mLineEdit, &QLineEdit::textChanged, 
this, &QgsValueRelationWidgetWrapper::emitValueChangedInternal, Qt::UniqueConnection );
 
  183   return mTableWidget || mLineEdit || mComboBox;
 
  186 void QgsValueRelationWidgetWrapper::updateValues( 
const QVariant &value, 
const QVariantList & )
 
  190     QStringList checkList;
 
  192     if ( 
layer()->fields().at( 
fieldIdx() ).type() == QVariant::Map ||
 
  193          layer()->fields().at( 
fieldIdx() ).type() == QVariant::List )
 
  195       checkList = 
value.toStringList();
 
  202     QTableWidgetItem *lastChangedItem = 
nullptr;
 
  204     const int nofColumns = columnCount();
 
  208     for ( 
int j = 0; j < mTableWidget->rowCount(); j++ )
 
  210       auto signalBlockedTableWidget = 
whileBlocking( mTableWidget );
 
  211       Q_UNUSED( signalBlockedTableWidget )
 
  213       for ( 
int i = 0; i < nofColumns; ++i )
 
  215         QTableWidgetItem *item = mTableWidget->item( j, i );
 
  218           item->setCheckState( checkList.contains( item->data( Qt::UserRole ).toString() ) ? Qt::Checked : Qt::Unchecked );
 
  220           item->setFlags( mEnabled ? item->flags() | Qt::ItemIsEnabled : item->flags() & ~Qt::ItemIsEnabled );
 
  221           lastChangedItem = item;
 
  226     if ( lastChangedItem )
 
  227       lastChangedItem->setCheckState( checkList.contains( lastChangedItem->data( Qt::UserRole ).toString() ) ? Qt::Checked : Qt::Unchecked );
 
  230   else if ( mComboBox )
 
  235     for ( 
int i = 0; i < mComboBox->count(); i++ )
 
  237       QVariant v( mComboBox->itemData( i ) );
 
  244     mComboBox->setCurrentIndex( idx );
 
  246   else if ( mLineEdit )
 
  249     bool wasFound { 
false };
 
  252       if ( i.key == 
value )
 
  254         mLineEdit->setText( i.value );
 
  262       mLineEdit->setText( tr( 
"(no selection)" ) );
 
  271   if ( attributeChanged )
 
  273     QVariant oldValue( 
value( ) );
 
  281       updateValues( 
value( ) );
 
  296         QString attributeName( formFields.
names().at( 
fieldIdx() ) );
 
  318   if ( 
context().attributeFormMode() != QgsAttributeEditorContext::Mode::MultiEditMode
 
  320        && ! mCache.isEmpty()
 
  321        && ! 
config( QStringLiteral( 
"AllowNull" ) ).toBool( ) )
 
  325     QTimer::singleShot( 0, 
this, [ 
this ]
 
  327       if ( ! mCache.isEmpty() )
 
  329         updateValues( formFeature().attribute( fieldIdx() ).isValid() ? formFeature().attribute( fieldIdx() ) : mCache.at( 0 ).key );
 
  335 int QgsValueRelationWidgetWrapper::columnCount()
 const 
  337   return std::max( 1, 
config( QStringLiteral( 
"NofColumns" ) ).toInt() );
 
  341 QVariant::Type QgsValueRelationWidgetWrapper::fkType()
 const 
  350       return fields.
at( idx ).
type();
 
  353   return QVariant::Type::Invalid;
 
  356 void QgsValueRelationWidgetWrapper::populate( )
 
  362     if ( 
context().parentFormFeature().isValid() )
 
  371   else if ( mCache.empty() )
 
  379     if ( 
config( QStringLiteral( 
"AllowNull" ) ).toBool( ) )
 
  381       whileBlocking( mComboBox )->addItem( tr( 
"(no selection)" ), QVariant( 
field().type( ) ) );
 
  386       whileBlocking( mComboBox )->addItem( element.value, element.key );
 
  387       if ( !element.description.isEmpty() )
 
  388         mComboBox->setItemData( mComboBox->count() - 1, element.description, Qt::ToolTipRole );
 
  392   else if ( mTableWidget )
 
  394     const int nofColumns = columnCount();
 
  396     if ( ! mCache.empty() )
 
  398       mTableWidget->setRowCount( ( mCache.size() + nofColumns - 1 ) / nofColumns );
 
  401       mTableWidget->setRowCount( 1 );
 
  402     mTableWidget->setColumnCount( nofColumns );
 
  409       if ( column == nofColumns )
 
  414       QTableWidgetItem *item = 
nullptr;
 
  415       item = 
new QTableWidgetItem( element.value );
 
  416       item->setData( Qt::UserRole, element.key );
 
  422   else if ( mLineEdit )
 
  425     values.reserve( mCache.size() );
 
  430     QStringListModel *m = 
new QStringListModel( values, mLineEdit );
 
  431     QCompleter *completer = 
new QCompleter( m, mLineEdit );
 
  432     completer->setCaseSensitivity( Qt::CaseInsensitive );
 
  433     mLineEdit->setCompleter( completer );
 
  439   const int nofColumns = columnCount();
 
  443     for ( 
int j = 0; j < mTableWidget->rowCount(); j++ )
 
  445       for ( 
int i = 0; i < nofColumns; ++i )
 
  447         whileBlocking( mTableWidget )->item( j, i )->setCheckState( Qt::PartiallyChecked );
 
  451   else if ( mComboBox )
 
  455   else if ( mLineEdit )
 
  463   if ( mEnabled == enabled )
 
  470     auto signalBlockedTableWidget = 
whileBlocking( mTableWidget );
 
  471     Q_UNUSED( signalBlockedTableWidget )
 
  473     for ( 
int j = 0; j < mTableWidget->rowCount(); j++ )
 
  475       for ( 
int i = 0; i < mTableWidget->columnCount(); ++i )
 
  477         QTableWidgetItem *item = mTableWidget->item( j, i );
 
  480           item->setFlags( enabled ? item->flags() | Qt::ItemIsEnabled : item->flags() & ~Qt::ItemIsEnabled );
 
  496   ctx.setParentFormFeature( feature );
 
  501        && ( 
config( QStringLiteral( 
"Value" ) ).toString() == attribute ||
 
  502             config( QStringLiteral( 
"Key" ) ).toString() == attribute ||
 
  511 void QgsValueRelationWidgetWrapper::emitValueChangedInternal( 
const QString &value )
 
This class contains context information for attribute editor widgets.
QgsFeature parentFormFeature() const
Returns the feature of the currently edited parent form in its actual state.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Container of fields for a vector layer.
int count() const
Returns number of items.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
QStringList names() const
Returns a list with field names.
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
static QString buildArray(const QVariantList &list)
Build a postgres array like formatted list in a string from a QVariantList.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Represents a vector layer which manages a vector based data sets.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
bool qgsVariantEqual(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether they are equal, two NULL values are always treated a...
#define Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_PUSH
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.