29#include <QRegularExpression> 
   36  tableWidget->insertRow( 0 );
 
   38  tableWidget->horizontalHeader()->setSectionsClickable( 
true );
 
   39  tableWidget->setSortingEnabled( 
true );
 
   41  connect( addNullButton, &QAbstractButton::clicked, 
this, &QgsValueMapConfigDlg::addNullButtonPushed );
 
   42  connect( removeSelectedButton, &QAbstractButton::clicked, 
this, &QgsValueMapConfigDlg::removeSelectedButtonPushed );
 
   43  connect( loadFromLayerButton, &QAbstractButton::clicked, 
this, &QgsValueMapConfigDlg::loadFromLayerButtonPushed );
 
   44  connect( loadFromCSVButton, &QAbstractButton::clicked, 
this, &QgsValueMapConfigDlg::loadFromCSVButtonPushed );
 
   45  connect( tableWidget, &QTableWidget::cellChanged, 
this, &QgsValueMapConfigDlg::vCellChanged );
 
   46  tableWidget->installEventFilter( 
this );
 
 
   51  QList<QVariant> valueList;
 
   54  for ( 
int i = 0; i < tableWidget->rowCount() - 1; i++ )
 
   56    QTableWidgetItem *ki = tableWidget->item( i, 0 );
 
   57    QTableWidgetItem *vi = tableWidget->item( i, 1 );
 
   62    QString ks = ki->text();
 
   68    if ( !vi || vi->text().isNull() )
 
   70      value.insert( ks, ks );
 
   74      value.insert( vi->text(), ks );
 
   76    valueList.append( value );
 
   80  cfg.insert( QStringLiteral( 
"map" ), valueList );
 
 
   86  tableWidget->clearContents();
 
   87  for ( 
int i = tableWidget->rowCount() - 1; i > 0; i-- )
 
   89    tableWidget->removeRow( i );
 
   92  QList<QVariant> valueList = 
config.value( QStringLiteral( 
"map" ) ).toList();
 
   94  if ( valueList.count() > 0 )
 
   96    for ( 
int i = 0, row = 0; i < valueList.count(); i++, row++ )
 
   98      setRow( row, valueList[i].toMap().constBegin().value().toString(), valueList[i].toMap().constBegin().key() );
 
  104    const QVariantMap values = 
config.value( QStringLiteral( 
"map" ) ).toMap();
 
  105    for ( QVariantMap::ConstIterator mit = values.constBegin(); mit != values.constEnd(); mit++, row++ )
 
  108        setRow( row, mit.key(), QString() );
 
  110        setRow( row, mit.value().toString(), mit.key() );
 
 
  115void QgsValueMapConfigDlg::vCellChanged( 
int row, 
int column )
 
  118  if ( row == tableWidget->rowCount() - 1 )
 
  120    tableWidget->insertRow( row + 1 );
 
  126void QgsValueMapConfigDlg::removeSelectedButtonPushed()
 
  128  QList<QTableWidgetItem *> list = tableWidget->selectedItems();
 
  129  QSet<int> rowsToRemove;
 
  132  for ( i = 0; i < list.size(); i++ )
 
  134    if ( list[i]->column() == 0 )
 
  136      const int row = list[i]->row();
 
  137      if ( !rowsToRemove.contains( row ) )
 
  139        rowsToRemove.insert( row );
 
  143  for ( 
const int rowToRemoved : rowsToRemove )
 
  145    tableWidget->removeRow( rowToRemoved - removed );
 
  153  QList<QPair<QString, QVariant>> orderedMap;
 
  154  const auto end = map.constEnd();
 
  155  for ( 
auto it = map.constBegin(); it != end; ++it )
 
  157    orderedMap.append( qMakePair( it.key(), it.value() ) );
 
 
  165  tableWidget->clearContents();
 
  166  for ( 
int i = tableWidget->rowCount() - 1; i > 0; i-- )
 
  168    tableWidget->removeRow( i );
 
  178  for ( 
const auto &pair : list )
 
  181      setRow( row, pair.first, QString() );
 
  183      setRow( row, pair.first, pair.second.toString() );
 
 
  190  const QList<QVariant> valueList = 
config.value( QStringLiteral( 
"map" ) ).toList();
 
  192  if ( !valueList.empty() )
 
  194    for ( 
const QVariant &value : valueList )
 
  196      const QVariantMap valueMap = value.toMap();
 
  201      comboBox->addItem( valueMap.constBegin().key(), valueMap.constBegin().value() );
 
  206    const QVariantMap map = 
config.value( QStringLiteral( 
"map" ) ).toMap();
 
  207    for ( 
auto it = map.constBegin(); it != map.constEnd(); ++it )
 
  212      comboBox->addItem( it.key(), it.value() );
 
 
  220  if ( event->type() == QEvent::KeyPress )
 
  222    QKeyEvent *keyEvent = 
static_cast<QKeyEvent *
>( event );
 
  223    if ( keyEvent->matches( QKeySequence::Copy ) )
 
  225      copySelectionToClipboard();
 
 
  233void QgsValueMapConfigDlg::setRow( 
int row, 
const QString &value, 
const QString &description )
 
  236  QTableWidgetItem *valueCell = 
nullptr;
 
  237  QTableWidgetItem *descriptionCell = 
new QTableWidgetItem( description );
 
  238  tableWidget->insertRow( row );
 
  242    cellFont.setItalic( 
true );
 
  244    valueCell->setFont( cellFont );
 
  245    valueCell->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
 
  246    descriptionCell->setFont( cellFont );
 
  250    valueCell = 
new QTableWidgetItem( value );
 
  252  tableWidget->setItem( row, 0, valueCell );
 
  253  tableWidget->setItem( row, 1, descriptionCell );
 
  256void QgsValueMapConfigDlg::copySelectionToClipboard()
 
  258  QAbstractItemModel *model = tableWidget->model();
 
  259  QItemSelectionModel *selection = tableWidget->selectionModel();
 
  260  const QModelIndexList indexes = selection->selectedIndexes();
 
  262  QString clipboardText;
 
  263  QModelIndex previous = indexes.first();
 
  264  std::unique_ptr<QMimeData> mimeData = std::make_unique<QMimeData>();
 
  265  for ( 
const QModelIndex ¤t : indexes )
 
  267    const QString text = model->data( current ).toString();
 
  268    if ( current.row() != previous.row() )
 
  270      clipboardText.append( 
'\n' );
 
  272    else if ( current.column() != previous.column() )
 
  274      clipboardText.append( 
'\t' );
 
  276    clipboardText.append( text );
 
  279  mimeData->setData( QStringLiteral( 
"text/plain" ), clipboardText.toUtf8() );
 
  280  QApplication::clipboard()->setMimeData( mimeData.release() );
 
  283void QgsValueMapConfigDlg::addNullButtonPushed()
 
  288void QgsValueMapConfigDlg::loadFromLayerButtonPushed()
 
  291  if ( !layerDialog.exec() )
 
  294  updateMap( layerDialog.valueMap(), layerDialog.insertNull() );
 
  297void QgsValueMapConfigDlg::loadFromCSVButtonPushed()
 
  301  const QString fileName = QFileDialog::getOpenFileName( 
nullptr, tr( 
"Load Value Map from File" ), QDir::homePath() );
 
  302  if ( fileName.isNull() )
 
  311  if ( !f.open( QIODevice::ReadOnly ) )
 
  313    QMessageBox::information( 
nullptr,
 
  314                              tr( 
"Load Value Map from File" ),
 
  315                              tr( 
"Could not open file %1\nError was: %2" ).arg( filePath, f.errorString() ),
 
  316                              QMessageBox::Cancel );
 
  321  s.setAutoDetectUnicode( 
true );
 
  323  const thread_local QRegularExpression re( 
"(?:^\"|[;,]\")(\"\"|[\\w\\W]*?)(?=\"[;,]|\"$)|(?:^(?!\")|[;,](?!\"))([^;,]*?)(?=$|[;,])|(\\r\\n|\\n)" );
 
  324  QList<QPair<QString, QVariant>> map;
 
  327    const QString l = s.readLine().trimmed();
 
  328    QRegularExpressionMatchIterator matches = re.globalMatch( l );
 
  330    while ( matches.hasNext() && ceils.size() < 2 )
 
  332      const QRegularExpressionMatch match = matches.next();
 
  333      ceils << match.capturedTexts().last().trimmed().replace( QLatin1String( 
"\"\"" ), QLatin1String( 
"\"" ) );
 
  336    if ( ceils.size() != 2 )
 
  339    QString key = ceils[0];
 
  340    QString val = ceils[1];
 
  343    map.append( qMakePair( key, val ) );
 
 
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
This class is a composition of two QSettings instances:
void loadMapFromCSV(const QString &filePath)
Updates the displayed table with the values from a CSV file.
void setConfig(const QVariantMap &config) override
Update the configuration widget to represent the given configuration.
bool eventFilter(QObject *watched, QEvent *event) override
QgsValueMapConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent)
void updateMap(const QMap< QString, QVariant > &map, bool insertNull)
Updates the displayed table with the values from map.
static void populateComboBox(QComboBox *comboBox, const QVariantMap &configuration, bool skipNull)
Populates a comboBox with the appropriate entries based on a value map configuration.
QVariantMap config() override
Create a configuration from the current GUI state.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
Represents a vector layer which manages a vector based data sets.