Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsfieldmodel.cpp
3 : : --------------------------------------
4 : : Date : 01.04.2014
5 : : Copyright : (C) 2014 Denis Rouzaud
6 : : Email : denis.rouzaud@gmail.com
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 <QFont>
17 : : #include <QIcon>
18 : :
19 : : #include "qgsfieldmodel.h"
20 : : #include "qgsmaplayermodel.h"
21 : : #include "qgsmaplayerproxymodel.h"
22 : : #include "qgslogger.h"
23 : : #include "qgsapplication.h"
24 : : #include "qgsvectorlayer.h"
25 : : #include "qgsvectorlayerjoinbuffer.h"
26 : :
27 : 0 : QgsFieldModel::QgsFieldModel( QObject *parent )
28 : 0 : : QAbstractItemModel( parent )
29 : 0 : {
30 : 0 : }
31 : :
32 : 0 : QModelIndex QgsFieldModel::indexFromName( const QString &fieldName )
33 : : {
34 : 0 : QString fldName( fieldName ); // we may need a copy
35 : :
36 : : // only non-empty names should be used here, as by default all fields
37 : : // have no aliases set and calling key() fill return just first value
38 : : // from the aliases map
39 : 0 : if ( mLayer && !fldName.isEmpty() )
40 : : {
41 : : // the name could be an alias
42 : : // it would be better to have "display name" directly in QgsFields
43 : : // rather than having to consult layer in various places in code!
44 : 0 : QString fieldNameWithAlias = mLayer->attributeAliases().key( fldName );
45 : 0 : if ( !fieldNameWithAlias.isNull() )
46 : 0 : fldName = fieldNameWithAlias;
47 : 0 : }
48 : :
49 : 0 : if ( mAllowEmpty && fieldName.isEmpty() )
50 : 0 : return index( 0, 0 );
51 : :
52 : 0 : int r = mFields.lookupField( fldName );
53 : 0 : if ( r >= 0 )
54 : : {
55 : 0 : if ( mAllowEmpty )
56 : 0 : r++;
57 : :
58 : 0 : QModelIndex idx = index( r, 0 );
59 : 0 : if ( idx.isValid() )
60 : : {
61 : 0 : return idx;
62 : : }
63 : 0 : }
64 : :
65 : 0 : if ( mAllowExpression )
66 : : {
67 : 0 : int exprIdx = mExpression.indexOf( fldName );
68 : 0 : if ( exprIdx != -1 )
69 : : {
70 : 0 : return index( ( mAllowEmpty ? 1 : 0 ) + mFields.count() + exprIdx, 0 );
71 : : }
72 : 0 : }
73 : :
74 : 0 : return QModelIndex();
75 : 0 : }
76 : :
77 : 0 : bool QgsFieldModel::isField( const QString &expression ) const
78 : : {
79 : 0 : int index = mFields.indexFromName( expression );
80 : 0 : return index >= 0;
81 : : }
82 : :
83 : 0 : void QgsFieldModel::setLayer( QgsVectorLayer *layer )
84 : : {
85 : 0 : if ( mLayer )
86 : : {
87 : 0 : disconnect( mLayer, &QgsVectorLayer::updatedFields, this, &QgsFieldModel::updateModel );
88 : 0 : disconnect( mLayer, &QObject::destroyed, this, &QgsFieldModel::layerDeleted );
89 : 0 : }
90 : :
91 : 0 : mLayer = layer;
92 : :
93 : 0 : if ( mLayer )
94 : : {
95 : 0 : connect( mLayer, &QgsVectorLayer::updatedFields, this, &QgsFieldModel::updateModel );
96 : 0 : connect( mLayer, &QObject::destroyed, this, &QgsFieldModel::layerDeleted );
97 : 0 : }
98 : :
99 : 0 : updateModel();
100 : 0 : }
101 : :
102 : 0 : void QgsFieldModel::layerDeleted()
103 : : {
104 : 0 : mLayer = nullptr;
105 : 0 : updateModel();
106 : 0 : }
107 : :
108 : 0 : void QgsFieldModel::updateModel()
109 : : {
110 : 0 : int offset = mAllowEmpty ? 1 : 0;
111 : 0 : if ( mLayer )
112 : : {
113 : 0 : QgsFields newFields = mLayer->fields();
114 : 0 : if ( mFields.toList() != newFields.toList() )
115 : : {
116 : : // Try to handle two special cases: addition of a new field and removal of a field.
117 : : // It would be better to listen directly to attributeAdded/attributeDeleted
118 : : // so we would not have to check for addition/removal here.
119 : :
120 : 0 : if ( mFields.count() == newFields.count() - 1 )
121 : : {
122 : 0 : QgsFields tmpNewFields = newFields;
123 : 0 : tmpNewFields.remove( tmpNewFields.count() - 1 );
124 : 0 : if ( mFields.toList() == tmpNewFields.toList() )
125 : : {
126 : : // the only change is a new field at the end
127 : 0 : beginInsertRows( QModelIndex(), mFields.count() + offset, mFields.count() + offset );
128 : 0 : mFields = newFields;
129 : 0 : endInsertRows();
130 : 0 : return;
131 : : }
132 : 0 : }
133 : :
134 : 0 : if ( mFields.count() == newFields.count() + 1 )
135 : : {
136 : 0 : QgsFields tmpOldFields = mFields;
137 : 0 : tmpOldFields.remove( tmpOldFields.count() - 1 );
138 : 0 : if ( tmpOldFields.toList() == newFields.toList() )
139 : : {
140 : : // the only change is a field removed at the end
141 : 0 : beginRemoveRows( QModelIndex(), mFields.count() - 1 + offset, mFields.count() - 1 + offset );
142 : 0 : mFields = newFields;
143 : 0 : endRemoveRows();
144 : 0 : return;
145 : : }
146 : :
147 : 0 : for ( int i = 0; i < newFields.count(); ++i )
148 : : {
149 : 0 : if ( mFields.at( i ) != newFields.at( i ) )
150 : : {
151 : 0 : QgsFields tmpOldFields = mFields;
152 : 0 : tmpOldFields.remove( i );
153 : 0 : if ( tmpOldFields.toList() != newFields.toList() )
154 : 0 : break; // the change is more complex - go with general case
155 : :
156 : : // the only change is a field removed at index i
157 : 0 : beginRemoveRows( QModelIndex(), i + offset, i + offset );
158 : 0 : mFields = newFields;
159 : 0 : endRemoveRows();
160 : 0 : return;
161 : 0 : }
162 : 0 : }
163 : 0 : }
164 : :
165 : : // general case with reset - not good - resets selections
166 : 0 : beginResetModel();
167 : 0 : mFields = mLayer->fields();
168 : 0 : endResetModel();
169 : 0 : }
170 : : else
171 : 0 : emit dataChanged( index( 0 + offset, 0 ), index( rowCount(), 0 ) );
172 : 0 : }
173 : : else
174 : : {
175 : 0 : beginResetModel();
176 : 0 : mFields = QgsFields();
177 : 0 : endResetModel();
178 : : }
179 : 0 : }
180 : :
181 : 0 : void QgsFieldModel::setAllowExpression( bool allowExpression )
182 : : {
183 : 0 : if ( allowExpression == mAllowExpression )
184 : 0 : return;
185 : :
186 : 0 : mAllowExpression = allowExpression;
187 : :
188 : 0 : if ( !mAllowExpression )
189 : : {
190 : 0 : int start = mFields.count();
191 : 0 : int end = start + mExpression.count() - 1;
192 : 0 : beginRemoveRows( QModelIndex(), start, end );
193 : 0 : mExpression = QList<QString>();
194 : 0 : endRemoveRows();
195 : 0 : }
196 : 0 : }
197 : :
198 : 0 : void QgsFieldModel::setAllowEmptyFieldName( bool allowEmpty )
199 : : {
200 : 0 : if ( allowEmpty == mAllowEmpty )
201 : 0 : return;
202 : :
203 : 0 : if ( allowEmpty )
204 : : {
205 : 0 : beginInsertRows( QModelIndex(), 0, 0 );
206 : 0 : mAllowEmpty = true;
207 : 0 : endInsertRows();
208 : 0 : }
209 : : else
210 : : {
211 : 0 : beginRemoveRows( QModelIndex(), 0, 0 );
212 : 0 : mAllowEmpty = false;
213 : 0 : endRemoveRows();
214 : : }
215 : 0 : }
216 : :
217 : :
218 : 0 : void QgsFieldModel::setExpression( const QString &expression )
219 : : {
220 : 0 : if ( !mAllowExpression )
221 : 0 : return;
222 : :
223 : 0 : QModelIndex idx = indexFromName( expression );
224 : 0 : if ( idx.isValid() )
225 : 0 : return;
226 : :
227 : 0 : beginResetModel();
228 : 0 : mExpression = QList<QString>();
229 : 0 : if ( !expression.isEmpty() )
230 : 0 : mExpression << expression;
231 : 0 : endResetModel();
232 : 0 : }
233 : :
234 : 0 : void QgsFieldModel::removeExpression()
235 : : {
236 : 0 : beginResetModel();
237 : 0 : mExpression = QList<QString>();
238 : 0 : endResetModel();
239 : 0 : }
240 : :
241 : 0 : QModelIndex QgsFieldModel::index( int row, int column, const QModelIndex &parent ) const
242 : : {
243 : 0 : if ( hasIndex( row, column, parent ) )
244 : : {
245 : 0 : return createIndex( row, column, row );
246 : : }
247 : :
248 : 0 : return QModelIndex();
249 : 0 : }
250 : :
251 : 0 : QModelIndex QgsFieldModel::parent( const QModelIndex &child ) const
252 : : {
253 : 0 : Q_UNUSED( child )
254 : 0 : return QModelIndex();
255 : : }
256 : :
257 : 0 : int QgsFieldModel::rowCount( const QModelIndex &parent ) const
258 : : {
259 : 0 : if ( parent.isValid() )
260 : : {
261 : 0 : return 0;
262 : : }
263 : :
264 : 0 : return ( mAllowEmpty ? 1 : 0 ) + ( mAllowExpression ? mFields.count() + mExpression.count() : mFields.count() );
265 : 0 : }
266 : :
267 : 0 : int QgsFieldModel::columnCount( const QModelIndex &parent ) const
268 : : {
269 : 0 : Q_UNUSED( parent )
270 : 0 : return 1;
271 : : }
272 : :
273 : 0 : QVariant QgsFieldModel::data( const QModelIndex &index, int role ) const
274 : : {
275 : 0 : if ( !index.isValid() )
276 : 0 : return QVariant();
277 : :
278 : 0 : int exprIdx = index.row() - mFields.count();
279 : 0 : if ( mAllowEmpty )
280 : 0 : exprIdx--;
281 : 0 : bool isEmpty = mAllowEmpty && index.row() == 0;
282 : 0 : int fieldOffset = mAllowEmpty ? 1 : 0;
283 : :
284 : 0 : switch ( role )
285 : : {
286 : : case FieldNameRole:
287 : : {
288 : 0 : if ( isEmpty || exprIdx >= 0 )
289 : : {
290 : 0 : return QString();
291 : : }
292 : 0 : QgsField field = mFields.at( index.row() - fieldOffset );
293 : 0 : return field.name();
294 : 0 : }
295 : :
296 : : case ExpressionRole:
297 : : {
298 : 0 : if ( exprIdx >= 0 )
299 : : {
300 : 0 : return mExpression.at( exprIdx );
301 : : }
302 : 0 : else if ( isEmpty )
303 : : {
304 : 0 : return QVariant();
305 : : }
306 : : else
307 : : {
308 : 0 : QgsField field = mFields.at( index.row() - fieldOffset );
309 : 0 : return field.name();
310 : 0 : }
311 : : }
312 : :
313 : : case FieldIndexRole:
314 : : {
315 : 0 : if ( isEmpty || exprIdx >= 0 )
316 : : {
317 : 0 : return QVariant();
318 : : }
319 : 0 : return index.row() - fieldOffset;
320 : : }
321 : :
322 : : case IsExpressionRole:
323 : : {
324 : 0 : return exprIdx >= 0;
325 : : }
326 : :
327 : : case ExpressionValidityRole:
328 : : {
329 : 0 : if ( exprIdx >= 0 )
330 : : {
331 : 0 : QgsExpression exp( mExpression.at( exprIdx ) );
332 : 0 : QgsExpressionContext context;
333 : 0 : if ( mLayer )
334 : 0 : context.setFields( mLayer->fields() );
335 : :
336 : 0 : exp.prepare( &context );
337 : 0 : return !exp.hasParserError();
338 : 0 : }
339 : 0 : return true;
340 : : }
341 : :
342 : : case FieldTypeRole:
343 : : {
344 : 0 : if ( exprIdx < 0 && !isEmpty )
345 : : {
346 : 0 : QgsField field = mFields.at( index.row() - fieldOffset );
347 : 0 : return static_cast< int >( field.type() );
348 : 0 : }
349 : 0 : return QVariant();
350 : : }
351 : :
352 : : case FieldOriginRole:
353 : : {
354 : 0 : if ( exprIdx < 0 && !isEmpty )
355 : : {
356 : 0 : return static_cast< int >( mFields.fieldOrigin( index.row() - fieldOffset ) );
357 : : }
358 : 0 : return QVariant();
359 : : }
360 : :
361 : : case IsEmptyRole:
362 : : {
363 : 0 : return isEmpty;
364 : : }
365 : :
366 : : case EditorWidgetType:
367 : : {
368 : 0 : if ( exprIdx < 0 && !isEmpty )
369 : : {
370 : 0 : return mFields.at( index.row() - fieldOffset ).editorWidgetSetup().type();
371 : : }
372 : 0 : return QVariant();
373 : : }
374 : :
375 : : case JoinedFieldIsEditable:
376 : : {
377 : 0 : if ( exprIdx < 0 && !isEmpty )
378 : : {
379 : 0 : if ( mLayer && mFields.fieldOrigin( index.row() - fieldOffset ) == QgsFields::OriginJoin )
380 : : {
381 : : int srcFieldIndex;
382 : 0 : const QgsVectorLayerJoinInfo *info = mLayer->joinBuffer()->joinForFieldIndex( index.row() - fieldOffset, mLayer->fields(), srcFieldIndex );
383 : :
384 : 0 : if ( !info || !info->isEditable() )
385 : 0 : return false;
386 : :
387 : 0 : return true;
388 : : }
389 : 0 : }
390 : 0 : return QVariant();
391 : : }
392 : :
393 : : case FieldIsWidgetEditable:
394 : : {
395 : 0 : return !( mLayer->editFormConfig().readOnly( index.row() - fieldOffset ) );
396 : : }
397 : :
398 : :
399 : : case Qt::DisplayRole:
400 : : case Qt::EditRole:
401 : : case Qt::ToolTipRole:
402 : : {
403 : 0 : if ( isEmpty )
404 : : {
405 : 0 : return QVariant();
406 : : }
407 : 0 : else if ( exprIdx >= 0 )
408 : : {
409 : 0 : return mExpression.at( exprIdx );
410 : : }
411 : 0 : else if ( role == Qt::EditRole )
412 : : {
413 : 0 : return mFields.at( index.row() - fieldOffset ).name();
414 : : }
415 : 0 : else if ( role == Qt::ToolTipRole )
416 : : {
417 : 0 : return fieldToolTip( mFields.at( index.row() - fieldOffset ) );
418 : : }
419 : 0 : else if ( mLayer )
420 : : {
421 : 0 : return mLayer->attributeDisplayName( index.row() - fieldOffset );
422 : : }
423 : 0 : else if ( mFields.size() > index.row() - fieldOffset )
424 : : {
425 : 0 : return mFields.field( index.row() - fieldOffset ).displayName();
426 : : }
427 : : else
428 : 0 : return QVariant();
429 : : }
430 : :
431 : : case Qt::ForegroundRole:
432 : : {
433 : 0 : if ( !isEmpty && exprIdx >= 0 )
434 : : {
435 : : // if expression, test validity
436 : 0 : QgsExpression exp( mExpression.at( exprIdx ) );
437 : 0 : QgsExpressionContext context;
438 : 0 : if ( mLayer )
439 : 0 : context.setFields( mLayer->fields() );
440 : :
441 : 0 : exp.prepare( &context );
442 : 0 : if ( exp.hasParserError() )
443 : : {
444 : 0 : return QBrush( QColor( Qt::red ) );
445 : : }
446 : 0 : }
447 : 0 : return QVariant();
448 : : }
449 : :
450 : : case Qt::FontRole:
451 : : {
452 : 0 : if ( !isEmpty && exprIdx >= 0 )
453 : : {
454 : : // if the line is an expression, set it as italic
455 : 0 : QFont font = QFont();
456 : 0 : font.setItalic( true );
457 : 0 : return font;
458 : 0 : }
459 : 0 : return QVariant();
460 : : }
461 : :
462 : : case Qt::DecorationRole:
463 : : {
464 : 0 : if ( !isEmpty && exprIdx < 0 )
465 : : {
466 : 0 : return mFields.iconForField( index.row() - fieldOffset );
467 : : }
468 : 0 : return QIcon();
469 : : }
470 : :
471 : : default:
472 : 0 : return QVariant();
473 : : }
474 : 0 : }
475 : :
476 : 0 : QString QgsFieldModel::fieldToolTip( const QgsField &field )
477 : : {
478 : 0 : QString toolTip;
479 : 0 : if ( !field.alias().isEmpty() )
480 : : {
481 : 0 : toolTip = QStringLiteral( "<b>%1</b> (%2)" ).arg( field.alias(), field.name() );
482 : 0 : }
483 : : else
484 : : {
485 : 0 : toolTip = QStringLiteral( "<b>%1</b>" ).arg( field.name() );
486 : : }
487 : :
488 : 0 : toolTip += QStringLiteral( "<br><font style='font-family:monospace; white-space: nowrap;'>%3</font>" ).arg( field.displayType( true ) );
489 : :
490 : 0 : QString comment = field.comment();
491 : :
492 : 0 : if ( ! comment.isEmpty() )
493 : : {
494 : 0 : toolTip += QStringLiteral( "<br><em>%1</em>" ).arg( comment );
495 : 0 : }
496 : :
497 : 0 : return toolTip;
498 : 0 : }
499 : :
500 : 0 : QString QgsFieldModel::fieldToolTipExtended( const QgsField &field, const QgsVectorLayer *layer )
501 : : {
502 : 0 : QString toolTip = QgsFieldModel::fieldToolTip( field );
503 : 0 : const QgsFields fields = layer->fields();
504 : 0 : int fieldIdx = fields.indexOf( field.name() );
505 : :
506 : 0 : if ( fieldIdx < 0 )
507 : 0 : return QString();
508 : :
509 : 0 : QString expressionString = fields.fieldOrigin( fieldIdx ) == QgsFields::OriginExpression
510 : 0 : ? layer->expressionField( fieldIdx )
511 : 0 : : QString();
512 : :
513 : 0 : if ( !expressionString.isEmpty() )
514 : : {
515 : 0 : toolTip += QStringLiteral( "<br><font style='font-family:monospace;'>%3</font>" ).arg( expressionString );
516 : 0 : }
517 : :
518 : 0 : return toolTip;
519 : 0 : }
520 : :
521 : 0 : void QgsFieldModel::setFields( const QgsFields &fields )
522 : : {
523 : 0 : setLayer( nullptr );
524 : 0 : beginResetModel();
525 : 0 : mFields = fields;
526 : 0 : endResetModel();
527 : 0 : }
528 : :
529 : 0 : QgsFields QgsFieldModel::fields() const
530 : : {
531 : 0 : return mFields;
532 : : }
|