QGIS API Documentation  3.4.15-Madeira (e83d02e274)
qgsvaluemapconfigdlg.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvaluemapconfigdlg.cpp
3  --------------------------------------
4  Date : 5.1.2014
5  Copyright : (C) 2014 Matthias Kuhn
6  Email : matthias at opengis dot ch
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsvaluemapconfigdlg.h"
17 
20 #include "qgsapplication.h"
21 #include "qgssettings.h"
22 
23 #include <QFileDialog>
24 #include <QMessageBox>
25 #include <QTextStream>
26 #include <QClipboard>
27 #include <QKeyEvent>
28 
29 QgsValueMapConfigDlg::QgsValueMapConfigDlg( QgsVectorLayer *vl, int fieldIdx, QWidget *parent )
30  : QgsEditorConfigWidget( vl, fieldIdx, parent )
31 {
32  setupUi( this );
33 
34  tableWidget->insertRow( 0 );
35 
36  tableWidget->horizontalHeader()->setClickable( true );
37  tableWidget->setSortingEnabled( true );
38 
39  connect( addNullButton, &QAbstractButton::clicked, this, &QgsValueMapConfigDlg::addNullButtonPushed );
40  connect( removeSelectedButton, &QAbstractButton::clicked, this, &QgsValueMapConfigDlg::removeSelectedButtonPushed );
41  connect( loadFromLayerButton, &QAbstractButton::clicked, this, &QgsValueMapConfigDlg::loadFromLayerButtonPushed );
42  connect( loadFromCSVButton, &QAbstractButton::clicked, this, &QgsValueMapConfigDlg::loadFromCSVButtonPushed );
43  connect( tableWidget, &QTableWidget::cellChanged, this, &QgsValueMapConfigDlg::vCellChanged );
44  tableWidget->installEventFilter( this );
45 }
46 
48 {
49  QList<QVariant> valueList;
50 
51  //store data to map
52  for ( int i = 0; i < tableWidget->rowCount() - 1; i++ )
53  {
54  QTableWidgetItem *ki = tableWidget->item( i, 0 );
55  QTableWidgetItem *vi = tableWidget->item( i, 1 );
56 
57  if ( !ki )
58  continue;
59 
60  QString ks = ki->text();
61  if ( ( ks == QgsApplication::nullRepresentation() ) && !( ki->flags() & Qt::ItemIsEditable ) )
63 
64  QVariantMap value;
65 
66  if ( !vi || vi->text().isNull() )
67  {
68  value.insert( ks, ks );
69  }
70  else
71  {
72  value.insert( vi->text(), ks );
73  }
74  valueList.append( value );
75  }
76 
77  QVariantMap cfg;
78  cfg.insert( QStringLiteral( "map" ), valueList );
79  return cfg;
80 }
81 
82 void QgsValueMapConfigDlg::setConfig( const QVariantMap &config )
83 {
84  tableWidget->clearContents();
85  for ( int i = tableWidget->rowCount() - 1; i > 0; i-- )
86  {
87  tableWidget->removeRow( i );
88  }
89 
90  QList<QVariant> valueList = config.value( QStringLiteral( "map" ) ).toList();
91 
92  if ( valueList.count() > 0 )
93  {
94  for ( int i = 0, row = 0; i < valueList.count(); i++, row++ )
95  {
96  setRow( row, valueList[i].toMap().constBegin().value().toString(), valueList[i].toMap().constBegin().key() );
97  }
98  }
99  else
100  {
101  int row = 0;
102  QVariantMap values = config.value( QStringLiteral( "map" ) ).toMap();
103  for ( QVariantMap::ConstIterator mit = values.constBegin(); mit != values.constEnd(); mit++, row++ )
104  {
105  if ( mit.value().isNull() )
106  setRow( row, mit.key(), QString() );
107  else
108  setRow( row, mit.value().toString(), mit.key() );
109  }
110  }
111 }
112 
113 void QgsValueMapConfigDlg::vCellChanged( int row, int column )
114 {
115  Q_UNUSED( column );
116  if ( row == tableWidget->rowCount() - 1 )
117  {
118  tableWidget->insertRow( row + 1 );
119  } //else check type
120 
121  emit changed();
122 }
123 
124 void QgsValueMapConfigDlg::removeSelectedButtonPushed()
125 {
126  QList<QTableWidgetItem *> list = tableWidget->selectedItems();
127  QSet<int> rowsToRemove;
128  int removed = 0;
129  int i;
130  for ( i = 0; i < list.size(); i++ )
131  {
132  if ( list[i]->column() == 0 )
133  {
134  int row = list[i]->row();
135  if ( !rowsToRemove.contains( row ) )
136  {
137  rowsToRemove.insert( row );
138  }
139  }
140  }
141  for ( i = 0; i < rowsToRemove.size(); i++ )
142  {
143  tableWidget->removeRow( rowsToRemove.values().at( i ) - removed );
144  removed++;
145  }
146  emit changed();
147 }
148 
149 void QgsValueMapConfigDlg::updateMap( const QMap<QString, QVariant> &map, bool insertNull )
150 {
151  tableWidget->clearContents();
152  for ( int i = tableWidget->rowCount() - 1; i > 0; i-- )
153  {
154  tableWidget->removeRow( i );
155  }
156  int row = 0;
157 
158  if ( insertNull )
159  {
160  setRow( row, QgsValueMapFieldFormatter::NULL_VALUE, QStringLiteral( "<NULL>" ) );
161  ++row;
162  }
163 
164  for ( QMap<QString, QVariant>::const_iterator mit = map.begin(); mit != map.end(); ++mit, ++row )
165  {
166  if ( mit.value().isNull() )
167  setRow( row, mit.key(), QString() );
168  else
169  setRow( row, mit.key(), mit.value().toString() );
170  }
171 }
172 
173 void QgsValueMapConfigDlg::populateComboBox( QComboBox *comboBox, const QVariantMap &config, bool skipNull )
174 {
175  const QList<QVariant> valueList = config.value( QStringLiteral( "map" ) ).toList();
176 
177  if ( !valueList.empty() )
178  {
179  for ( const QVariant &value : valueList )
180  {
181  const QVariantMap valueMap = value.toMap();
182 
183  if ( skipNull && valueMap.constBegin().value() == QgsValueMapFieldFormatter::NULL_VALUE )
184  continue;
185 
186  comboBox->addItem( valueMap.constBegin().key(), valueMap.constBegin().value() );
187  }
188  }
189  else
190  {
191  const QVariantMap map = config.value( QStringLiteral( "map" ) ).toMap();
192  for ( auto it = map.constBegin(); it != map.constEnd(); ++it )
193  {
194  if ( skipNull && it.value() == QgsValueMapFieldFormatter::NULL_VALUE )
195  continue;
196 
197  comboBox->addItem( it.key(), it.value() );
198  }
199  }
200 }
201 
202 bool QgsValueMapConfigDlg::eventFilter( QObject *watched, QEvent *event )
203 {
204  Q_UNUSED( watched )
205  if ( event->type() == QEvent::KeyPress )
206  {
207  QKeyEvent *keyEvent = static_cast<QKeyEvent *>( event );
208  if ( keyEvent->matches( QKeySequence::Copy ) )
209  {
210  copySelectionToClipboard();
211  event->accept();
212  return true;
213  }
214  }
215  return false;
216 }
217 
218 void QgsValueMapConfigDlg::setRow( int row, const QString &value, const QString &description )
219 {
220  QgsSettings settings;
221  QTableWidgetItem *valueCell = nullptr;
222  QTableWidgetItem *descriptionCell = new QTableWidgetItem( description );
223  tableWidget->insertRow( row );
225  {
226  QFont cellFont;
227  cellFont.setItalic( true );
228  valueCell = new QTableWidgetItem( QgsApplication::nullRepresentation() );
229  valueCell->setFont( cellFont );
230  valueCell->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
231  descriptionCell->setFont( cellFont );
232  }
233  else
234  {
235  valueCell = new QTableWidgetItem( value );
236  }
237  tableWidget->setItem( row, 0, valueCell );
238  tableWidget->setItem( row, 1, descriptionCell );
239 }
240 
241 void QgsValueMapConfigDlg::copySelectionToClipboard()
242 {
243  QAbstractItemModel *model = tableWidget->model();
244  QItemSelectionModel *selection = tableWidget->selectionModel();
245  const QModelIndexList indexes = selection->selectedIndexes();
246 
247  QString clipboardText;
248  QModelIndex previous = indexes.first();
249  std::unique_ptr<QMimeData> mimeData = qgis::make_unique<QMimeData>();
250  for ( const QModelIndex &current : indexes )
251  {
252  const QString text = model->data( current ).toString();
253  if ( current.row() != previous.row() )
254  {
255  clipboardText.append( '\n' );
256  }
257  else if ( current.column() != previous.column() )
258  {
259  clipboardText.append( '\t' );
260  }
261  clipboardText.append( text );
262  previous = current;
263  }
264  mimeData->setData( QStringLiteral( "text/plain" ), clipboardText.toUtf8() );
265  QApplication::clipboard()->setMimeData( mimeData.release() );
266 }
267 
268 void QgsValueMapConfigDlg::addNullButtonPushed()
269 {
270  setRow( tableWidget->rowCount() - 1, QgsValueMapFieldFormatter::NULL_VALUE, QStringLiteral( "<NULL>" ) );
271 }
272 
273 void QgsValueMapConfigDlg::loadFromLayerButtonPushed()
274 {
275  QgsAttributeTypeLoadDialog layerDialog( layer() );
276  if ( !layerDialog.exec() )
277  return;
278 
279  updateMap( layerDialog.valueMap(), layerDialog.insertNull() );
280 }
281 
282 void QgsValueMapConfigDlg::loadFromCSVButtonPushed()
283 {
284  QgsSettings settings;
285 
286  QString fileName = QFileDialog::getOpenFileName( nullptr, tr( "Select a File" ), QDir::homePath() );
287  if ( fileName.isNull() )
288  return;
289 
290  QFile f( fileName );
291 
292  if ( !f.open( QIODevice::ReadOnly ) )
293  {
294  QMessageBox::information( nullptr,
295  tr( "Load Value Map from File" ),
296  tr( "Could not open file %1\nError was: %2" ).arg( fileName, f.errorString() ),
297  QMessageBox::Cancel );
298  return;
299  }
300 
301  QTextStream s( &f );
302  s.setAutoDetectUnicode( true );
303 
304  QRegExp re0( "^([^;]*);(.*)$" );
305  re0.setMinimal( true );
306  QRegExp re1( "^([^,]*),(.*)$" );
307  re1.setMinimal( true );
308  QMap<QString, QVariant> map;
309 
310  s.readLine();
311 
312  while ( !s.atEnd() )
313  {
314  QString l = s.readLine().trimmed();
315 
316  QString key, val;
317  if ( re0.indexIn( l ) >= 0 && re0.captureCount() == 2 )
318  {
319  key = re0.cap( 1 ).trimmed();
320  val = re0.cap( 2 ).trimmed();
321  }
322  else if ( re1.indexIn( l ) >= 0 && re1.captureCount() == 2 )
323  {
324  key = re1.cap( 1 ).trimmed();
325  val = re1.cap( 2 ).trimmed();
326  }
327  else
328  continue;
329 
330  if ( ( key.startsWith( '\"' ) && key.endsWith( '\"' ) ) ||
331  ( key.startsWith( '\'' ) && key.endsWith( '\'' ) ) )
332  {
333  key = key.mid( 1, key.length() - 2 );
334  }
335 
336  if ( ( val.startsWith( '\"' ) && val.endsWith( '\"' ) ) ||
337  ( val.startsWith( '\'' ) && val.endsWith( '\'' ) ) )
338  {
339  val = val.mid( 1, val.length() - 2 );
340  }
341 
342  if ( key == QgsApplication::nullRepresentation() )
344 
345  map[ key ] = val;
346  }
347 
348  updateMap( map, false );
349 }
void updateMap(const QMap< QString, QVariant > &map, bool insertNull)
QgsVectorLayer * layer()
Returns the layer for which this configuration widget applies.
This class should be subclassed for every configurable editor widget type.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
QgsValueMapConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent)
bool eventFilter(QObject *watched, QEvent *event) override
void setConfig(const QVariantMap &config) override
Update the configuration widget to represent the given configuration.
QMap< QString, QVariant > & valueMap()
Returns the value map which is currently active.
QVariantMap config() override
Create a configuration from the current GUI state.
bool insertNull()
Returns true if the "Add NULL value" checkbox has been checked.
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
void changed()
Emitted when the configuration of the widget is changed.
Represents a vector layer which manages a vector based data sets.
static const QString NULL_VALUE
Will be saved in the configuration when a value is NULL.
static void populateComboBox(QComboBox *comboBox, const QVariantMap &configuration, bool skipNull)
Populates a comboBox with the appropriate entries based on a value map configuration.