32 #include <QHeaderView> 
   35 #include <QTableWidget> 
   36 #include <QStringListModel> 
   40 #include <nlohmann/json.hpp> 
   41 using namespace nlohmann;
 
   56     int cbxIdx = mComboBox->currentIndex();
 
   59       v = mComboBox->currentData();
 
   61         v = QVariant( 
field().type() );
 
   64   else if ( mTableWidget )
 
   66     const int nofColumns = columnCount();
 
   67     QStringList selection;
 
   68     for ( 
int j = 0; j < mTableWidget->rowCount(); j++ )
 
   70       for ( 
int i = 0; i < nofColumns; ++i )
 
   72         QTableWidgetItem *item = mTableWidget->item( j, i );
 
   75           if ( item->checkState() == Qt::Checked )
 
   76             selection << item->data( Qt::UserRole ).toString();
 
   82     if ( selection.isEmpty() && ! 
config( QStringLiteral( 
"AllowNull" ) ).toBool( ) )
 
   84       return QVariant( QVariant::Type::List );
 
   89     for ( 
const QString &s : std::as_const( selection ) )
 
   92       const QVariant::Type type { fkType() };
 
   95         case QVariant::Type::Int:
 
   96           vl.push_back( s.toInt() );
 
   98         case QVariant::Type::LongLong:
 
   99           vl.push_back( s.toLongLong() );
 
  107     if ( 
layer()->fields().at( 
fieldIdx() ).type() == QVariant::Map ||
 
  108          layer()->fields().at( 
fieldIdx() ).type() == QVariant::List )
 
  118   else if ( mLineEdit )
 
  122       if ( item.value == mLineEdit->text() )
 
  139   mExpression = 
config().value( QStringLiteral( 
"FilterExpression" ) ).toString();
 
  141   if ( 
config( QStringLiteral( 
"AllowMulti" ) ).toBool() )
 
  143     return new QTableWidget( parent );
 
  145   else if ( 
config( QStringLiteral( 
"UseCompleter" ) ).toBool() )
 
  151     return new QComboBox( parent );
 
  158   mComboBox = qobject_cast<QComboBox *>( editor );
 
  159   mTableWidget = qobject_cast<QTableWidget *>( editor );
 
  160   mLineEdit = qobject_cast<QLineEdit *>( editor );
 
  167     mComboBox->view()->setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded );
 
  168     connect( mComboBox, 
static_cast<void ( QComboBox::* )( 
int )
>( &QComboBox::currentIndexChanged ),
 
  171   else if ( mTableWidget )
 
  173     mTableWidget->horizontalHeader()->setSectionResizeMode( QHeaderView::Stretch );
 
  174     mTableWidget->horizontalHeader()->setVisible( 
false );
 
  175     mTableWidget->verticalHeader()->setSectionResizeMode( QHeaderView::Stretch );
 
  176     mTableWidget->verticalHeader()->setVisible( 
false );
 
  177     mTableWidget->setShowGrid( 
false );
 
  178     mTableWidget->setEditTriggers( QAbstractItemView::NoEditTriggers );
 
  179     mTableWidget->setSelectionMode( QAbstractItemView::NoSelection );
 
  182   else if ( mLineEdit )
 
  184     connect( mLineEdit, &QLineEdit::textChanged, 
this, &QgsValueRelationWidgetWrapper::emitValueChangedInternal, Qt::UniqueConnection );
 
  190   return mTableWidget || mLineEdit || mComboBox;
 
  193 void QgsValueRelationWidgetWrapper::updateValues( 
const QVariant &value, 
const QVariantList & )
 
  197     QStringList checkList;
 
  199     if ( 
layer()->fields().at( 
fieldIdx() ).type() == QVariant::Map ||
 
  200          layer()->fields().at( 
fieldIdx() ).type() == QVariant::List )
 
  202       checkList = 
value.toStringList();
 
  209     QTableWidgetItem *lastChangedItem = 
nullptr;
 
  211     const int nofColumns = columnCount();
 
  215     for ( 
int j = 0; j < mTableWidget->rowCount(); j++ )
 
  217       auto signalBlockedTableWidget = 
whileBlocking( mTableWidget );
 
  218       Q_UNUSED( signalBlockedTableWidget )
 
  220       for ( 
int i = 0; i < nofColumns; ++i )
 
  222         QTableWidgetItem *item = mTableWidget->item( j, i );
 
  225           item->setCheckState( checkList.contains( item->data( Qt::UserRole ).toString() ) ? Qt::Checked : Qt::Unchecked );
 
  227           item->setFlags( mEnabled ? item->flags() | Qt::ItemIsEnabled : item->flags() & ~Qt::ItemIsEnabled );
 
  228           lastChangedItem = item;
 
  233     if ( lastChangedItem )
 
  234       lastChangedItem->setCheckState( checkList.contains( lastChangedItem->data( Qt::UserRole ).toString() ) ? Qt::Checked : Qt::Unchecked );
 
  237   else if ( mComboBox )
 
  242     for ( 
int i = 0; i < mComboBox->count(); i++ )
 
  244       QVariant v( mComboBox->itemData( i ) );
 
  255       if ( 
value.isNull( ) )
 
  257         mComboBox->setCurrentIndex( -1 );
 
  261         mComboBox->addItem( 
value.toString().prepend( 
'(' ).append( 
')' ), 
value );
 
  262         mComboBox->setCurrentIndex( mComboBox->findData( 
value ) );
 
  267       mComboBox->setCurrentIndex( idx );
 
  270   else if ( mLineEdit )
 
  273     bool wasFound { 
false };
 
  276       if ( i.key == 
value )
 
  278         mLineEdit->setText( i.value );
 
  286       mLineEdit->setText( tr( 
"(no selection)" ) );
 
  295   if ( attributeChanged )
 
  297     QVariant oldValue( 
value( ) );
 
  305       updateValues( 
value( ) );
 
  320         QString attributeName( formFields.
names().at( 
fieldIdx() ) );
 
  342   if ( 
context().attributeFormMode() != QgsAttributeEditorContext::Mode::MultiEditMode
 
  344        && ! mCache.isEmpty()
 
  345        && ! 
config( QStringLiteral( 
"AllowNull" ) ).toBool( ) )
 
  349     QTimer::singleShot( 0, 
this, [ 
this ]
 
  351       if ( ! mCache.isEmpty() )
 
  353         updateValues( formFeature().attribute( fieldIdx() ).isValid() ? formFeature().attribute( fieldIdx() ) : mCache.at( 0 ).key );
 
  359 int QgsValueRelationWidgetWrapper::columnCount()
 const 
  361   return std::max( 1, 
config( QStringLiteral( 
"NofColumns" ) ).toInt() );
 
  365 QVariant::Type QgsValueRelationWidgetWrapper::fkType()
 const 
  374       return fields.
at( idx ).
type();
 
  377   return QVariant::Type::Invalid;
 
  380 void QgsValueRelationWidgetWrapper::populate( )
 
  386     if ( 
context().parentFormFeature().isValid() )
 
  395   else if ( mCache.empty() )
 
  403     if ( 
config( QStringLiteral( 
"AllowNull" ) ).toBool( ) )
 
  405       whileBlocking( mComboBox )->addItem( tr( 
"(no selection)" ), QVariant( 
field().type( ) ) );
 
  410       whileBlocking( mComboBox )->addItem( element.value, element.key );
 
  411       if ( !element.description.isEmpty() )
 
  412         mComboBox->setItemData( mComboBox->count() - 1, element.description, Qt::ToolTipRole );
 
  416   else if ( mTableWidget )
 
  418     const int nofColumns = columnCount();
 
  420     if ( ! mCache.empty() )
 
  422       mTableWidget->setRowCount( ( mCache.size() + nofColumns - 1 ) / nofColumns );
 
  425       mTableWidget->setRowCount( 1 );
 
  426     mTableWidget->setColumnCount( nofColumns );
 
  433       if ( column == nofColumns )
 
  438       QTableWidgetItem *item = 
nullptr;
 
  439       item = 
new QTableWidgetItem( element.value );
 
  440       item->setData( Qt::UserRole, element.key );
 
  446   else if ( mLineEdit )
 
  449     values.reserve( mCache.size() );
 
  454     QStringListModel *m = 
new QStringListModel( values, mLineEdit );
 
  455     QCompleter *completer = 
new QCompleter( m, mLineEdit );
 
  456     completer->setCaseSensitivity( Qt::CaseInsensitive );
 
  457     mLineEdit->setCompleter( completer );
 
  463   const int nofColumns = columnCount();
 
  467     for ( 
int j = 0; j < mTableWidget->rowCount(); j++ )
 
  469       for ( 
int i = 0; i < nofColumns; ++i )
 
  471         whileBlocking( mTableWidget )->item( j, i )->setCheckState( Qt::PartiallyChecked );
 
  475   else if ( mComboBox )
 
  479   else if ( mLineEdit )
 
  487   if ( mEnabled == enabled )
 
  494     auto signalBlockedTableWidget = 
whileBlocking( mTableWidget );
 
  495     Q_UNUSED( signalBlockedTableWidget )
 
  497     for ( 
int j = 0; j < mTableWidget->rowCount(); j++ )
 
  499       for ( 
int i = 0; i < mTableWidget->columnCount(); ++i )
 
  501         QTableWidgetItem *item = mTableWidget->item( j, i );
 
  504           item->setFlags( enabled ? item->flags() | Qt::ItemIsEnabled : item->flags() & ~Qt::ItemIsEnabled );
 
  520   ctx.setParentFormFeature( feature );
 
  525        && ( 
config( QStringLiteral( 
"Value" ) ).toString() == attribute ||
 
  526             config( QStringLiteral( 
"Key" ) ).toString() == attribute ||
 
  535 void QgsValueRelationWidgetWrapper::emitValueChangedInternal( 
const QString &value )