QGIS API Documentation 4.1.0-Master (467af3bbe65)
Loading...
Searching...
No Matches
qgsvariantutils.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsvariantutils.h
3 ------------------
4 Date : January 2022
5 Copyright : (C) 2022 Nyall Dawson
6 Email : nyall dot dawson at gmail dot 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 "qgsvariantutils.h"
17
18#include "qgsapplication.h"
19#include "qgslogger.h"
20#include "qgsstringutils.h"
22
23#include <QBitArray>
24#include <QBitmap>
25#include <QBrush>
26#include <QColor>
27#include <QDate>
28#include <QDateTime>
29#include <QIcon>
30#include <QImage>
31#include <QLine>
32#include <QPixmap>
33#include <QQuaternion>
34#include <QRect>
35#include <QString>
36#include <QTime>
37#include <QUuid>
38#include <QVector2D>
39#include <QVector3D>
40#include <QVector4D>
41
42using namespace Qt::StringLiterals;
43
44QString QgsVariantUtils::typeToDisplayString( QMetaType::Type type, QMetaType::Type subType )
45{
46 switch ( type )
47 {
48 case QMetaType::Type::UnknownType:
49 break;
50 case QMetaType::Type::Bool:
51 return QObject::tr( "Boolean" );
52 case QMetaType::Type::Int:
53 return QObject::tr( "Integer (32 bit)" );
54 case QMetaType::Type::UInt:
55 return QObject::tr( "Integer (unsigned 32 bit)" );
56 case QMetaType::Type::LongLong:
57 return QObject::tr( "Integer (64 bit)" );
58 case QMetaType::Type::ULongLong:
59 return QObject::tr( "Integer (unsigned 64 bit)" );
60 case QMetaType::Type::Double:
61 return QObject::tr( "Decimal (double)" );
62 case QMetaType::Type::QChar:
63 return QObject::tr( "Character" );
64 case QMetaType::Type::QVariantMap:
65 return QObject::tr( "Map" );
66 case QMetaType::Type::QVariantList:
67 {
68 switch ( subType )
69 {
70 case QMetaType::Type::Int:
71 return QObject::tr( "Integer List" );
72 case QMetaType::Type::LongLong:
73 return QObject::tr( "Integer (64 bit) List" );
74 case QMetaType::Type::Double:
75 return QObject::tr( "Decimal (double) List" );
76 default:
77 return QObject::tr( "List" );
78 }
79 }
80 case QMetaType::Type::QString:
81 return QObject::tr( "Text (string)" );
82 case QMetaType::Type::QStringList:
83 return QObject::tr( "String List" );
84 case QMetaType::Type::QByteArray:
85 return QObject::tr( "Binary Object (BLOB)" );
86 case QMetaType::Type::QBitArray:
87 return QObject::tr( "Bit Array" );
88 case QMetaType::Type::QDate:
89 return QObject::tr( "Date" );
90 case QMetaType::Type::QTime:
91 return QObject::tr( "Time" );
92 case QMetaType::Type::QDateTime:
93 return QObject::tr( "Date & Time" );
94 case QMetaType::Type::QUrl:
95 return QObject::tr( "URL" );
96 case QMetaType::Type::QLocale:
97 return QObject::tr( "Locale" );
98 case QMetaType::Type::QRect:
99 case QMetaType::Type::QRectF:
100 return QObject::tr( "Rectangle" );
101 case QMetaType::Type::QSize:
102 case QMetaType::Type::QSizeF:
103 return QObject::tr( "Size" );
104 case QMetaType::Type::QLine:
105 case QMetaType::Type::QLineF:
106 return QObject::tr( "Line" );
107 case QMetaType::Type::QPoint:
108 case QMetaType::Type::QPointF:
109 return QObject::tr( "Point" );
110 case QMetaType::Type::QRegularExpression:
111 return QObject::tr( "Regular Expression" );
112 case QMetaType::Type::QVariantHash:
113 return QObject::tr( "Hash" );
114 case QMetaType::Type::QEasingCurve:
115 return QObject::tr( "Easing Curve" );
116 case QMetaType::Type::QUuid:
117 return QObject::tr( "UUID" );
118 case QMetaType::Type::QModelIndex:
119 case QMetaType::Type::QPersistentModelIndex:
120 return QObject::tr( "Model Index" );
121 case QMetaType::Type::QFont:
122 return QObject::tr( "Font" );
123 case QMetaType::Type::QPixmap:
124 return QObject::tr( "Pixmap" );
125 case QMetaType::Type::QBrush:
126 return QObject::tr( "Brush" );
127 case QMetaType::Type::QColor:
128 return QObject::tr( "Color" );
129 case QMetaType::Type::QPalette:
130 return QObject::tr( "Palette" );
131 case QMetaType::Type::QImage:
132 return QObject::tr( "Image" );
133 case QMetaType::Type::QPolygon:
134 case QMetaType::Type::QPolygonF:
135 return QObject::tr( "Polygon" );
136 case QMetaType::Type::QRegion:
137 return QObject::tr( "Region" );
138 case QMetaType::Type::QBitmap:
139 return QObject::tr( "Bitmap" );
140 case QMetaType::Type::QCursor:
141 return QObject::tr( "Cursor" );
142 case QMetaType::Type::QKeySequence:
143 return QObject::tr( "Key Sequence" );
144 case QMetaType::Type::QPen:
145 return QObject::tr( "Pen" );
146 case QMetaType::Type::QTextLength:
147 return QObject::tr( "Text Length" );
148 case QMetaType::Type::QTextFormat:
149 return QObject::tr( "Text Format" );
150 case QMetaType::Type::QMatrix4x4:
151 return QObject::tr( "Matrix" );
152 case QMetaType::Type::QTransform:
153 return QObject::tr( "Transform" );
154 case QMetaType::Type::QVector2D:
155 case QMetaType::Type::QVector3D:
156 case QMetaType::Type::QVector4D:
157 return QObject::tr( "Vector" );
158 case QMetaType::Type::QQuaternion:
159 return QObject::tr( "Quaternion" );
160 case QMetaType::Type::QIcon:
161 return QObject::tr( "Icon" );
162 case QMetaType::Type::QSizePolicy:
163 return QObject::tr( "Size Policy" );
164
165 default:
166 break;
167 }
168 return QString();
169}
170
171QString QgsVariantUtils::typeToDisplayString( QVariant::Type type, QVariant::Type subType )
172{
174}
175
176bool QgsVariantUtils::isNull( const QVariant &variant, bool silenceNullWarnings )
177{
178#ifndef QGISDEBUG
179 ( void ) silenceNullWarnings;
180#endif
181
182 if ( variant.isNull() || !variant.isValid() )
183 return true;
184
185 switch ( variant.userType() )
186 {
187 case QMetaType::Type::UnknownType:
188 case QMetaType::Type::Bool:
189 case QMetaType::Type::Int:
190 case QMetaType::Type::UInt:
191 case QMetaType::Type::LongLong:
192 case QMetaType::Type::ULongLong:
193 case QMetaType::Type::Double:
194 case QMetaType::Type::QVariantMap:
195 case QMetaType::Type::QVariantList:
196 case QMetaType::Type::QStringList:
197 case QMetaType::Type::QUrl:
198 case QMetaType::Type::QLocale:
199 case QMetaType::Type::QRegularExpression:
200 case QMetaType::Type::QVariantHash:
201 case QMetaType::Type::QEasingCurve:
202 case QMetaType::Type::QModelIndex:
203 case QMetaType::Type::QPersistentModelIndex:
204
205 return false;
206
207 case QMetaType::Type::QDate:
208 if ( variant.toDate().isNull() )
209 {
210 if ( !silenceNullWarnings )
211 {
212 QgsDebugError( u"NULL QDateTime was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
213 }
214 return true;
215 }
216 return false;
217 case QMetaType::Type::QTime:
218 if ( variant.toTime().isNull() )
219 {
220 if ( !silenceNullWarnings )
221 {
222 QgsDebugError( u"NULL QTime was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
223 }
224 return true;
225 }
226 return false;
227 case QMetaType::Type::QDateTime:
228 if ( variant.toDate().isNull() )
229 {
230 if ( !silenceNullWarnings )
231 {
232 QgsDebugError( u"NULL QDate was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
233 }
234 return true;
235 }
236 return false;
237 case QMetaType::Type::QChar:
238 if ( variant.toChar().isNull() )
239 {
240 if ( !silenceNullWarnings )
241 {
242 QgsDebugError( u"NULL QChar was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
243 }
244 return true;
245 }
246 return false;
247 case QMetaType::Type::QString:
248 if ( variant.toString().isNull() )
249 {
250 if ( !silenceNullWarnings )
251 {
252 QgsDebugError( u"NULL QString was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
253 }
254 return true;
255 }
256 return false;
257 case QMetaType::Type::QByteArray:
258 if ( variant.toByteArray().isNull() )
259 {
260 if ( !silenceNullWarnings )
261 {
262 QgsDebugError( u"NULL QByteArray was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
263 }
264 return true;
265 }
266 return false;
267 case QMetaType::Type::QBitArray:
268 if ( variant.toBitArray().isNull() )
269 {
270 if ( !silenceNullWarnings )
271 {
272 QgsDebugError( u"NULL QBitArray was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
273 }
274 return true;
275 }
276 return false;
277 case QMetaType::Type::QRect:
278 if ( variant.toRect().isNull() )
279 {
280 if ( !silenceNullWarnings )
281 {
282 QgsDebugError( u"NULL QRect was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
283 }
284 return true;
285 }
286 return false;
287 case QMetaType::Type::QRectF:
288 if ( variant.toRectF().isNull() )
289 {
290 if ( !silenceNullWarnings )
291 {
292 QgsDebugError( u"NULL QRectF was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
293 }
294 return true;
295 }
296 return false;
297 case QMetaType::Type::QSize:
298 if ( variant.toSize().isNull() )
299 {
300 if ( !silenceNullWarnings )
301 {
302 QgsDebugError( u"NULL QSize was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
303 }
304 return true;
305 }
306 return false;
307 case QMetaType::Type::QSizeF:
308 if ( variant.toSizeF().isNull() )
309 {
310 if ( !silenceNullWarnings )
311 {
312 QgsDebugError( u"NULL QSizeF was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
313 }
314 return true;
315 }
316 return false;
317 case QMetaType::Type::QLine:
318 if ( variant.toLine().isNull() )
319 {
320 if ( !silenceNullWarnings )
321 {
322 QgsDebugError( u"NULL QLine was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
323 }
324 return true;
325 }
326 return false;
327 case QMetaType::Type::QLineF:
328 if ( variant.toLineF().isNull() )
329 {
330 if ( !silenceNullWarnings )
331 {
332 QgsDebugError( u"NULL QLineF was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
333 }
334 return true;
335 }
336 return false;
337 case QMetaType::Type::QPoint:
338 if ( variant.toPoint().isNull() )
339 {
340 if ( !silenceNullWarnings )
341 {
342 QgsDebugError( u"NULL QPoint was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
343 }
344 return true;
345 }
346 return false;
347 case QMetaType::Type::QPointF:
348 if ( variant.toPointF().isNull() )
349 {
350 if ( !silenceNullWarnings )
351 {
352 QgsDebugError( u"NULL QPointF was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
353 }
354 return true;
355 }
356 return false;
357 case QMetaType::Type::QUuid:
358 if ( variant.toUuid().isNull() )
359 {
360 if ( !silenceNullWarnings )
361 {
362 QgsDebugError( u"NULL QUuid was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
363 }
364 return true;
365 }
366 return false;
367 case QMetaType::Type::QPixmap:
368 if ( variant.value< QPixmap >().isNull() )
369 {
370 if ( !silenceNullWarnings )
371 {
372 QgsDebugError( u"NULL QPixmap was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
373 }
374 return true;
375 }
376 return false;
377 case QMetaType::Type::QImage:
378 if ( variant.value< QImage >().isNull() )
379 {
380 if ( !silenceNullWarnings )
381 {
382 QgsDebugError( u"NULL QImage was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
383 }
384 return true;
385 }
386 return false;
387 case QMetaType::Type::QRegion:
388 if ( variant.value< QRegion >().isNull() )
389 {
390 if ( !silenceNullWarnings )
391 {
392 QgsDebugError( u"NULL QRegion was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
393 }
394 return true;
395 }
396 return false;
397 case QMetaType::Type::QBitmap:
398 if ( variant.value< QBitmap >().isNull() )
399 {
400 if ( !silenceNullWarnings )
401 {
402 QgsDebugError( u"NULL QBitmap was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
403 }
404 return true;
405 }
406 return false;
407 case QMetaType::Type::QIcon:
408 if ( variant.value< QIcon >().isNull() )
409 {
410 if ( !silenceNullWarnings )
411 {
412 QgsDebugError( u"NULL QIcon was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
413 }
414 return true;
415 }
416 return false;
417 case QMetaType::Type::QVector2D:
418 if ( variant.value< QVector2D >().isNull() )
419 {
420 if ( !silenceNullWarnings )
421 {
422 QgsDebugError( u"NULL QVector2D was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
423 }
424 return true;
425 }
426 return false;
427 case QMetaType::Type::QVector3D:
428 if ( variant.value< QVector3D >().isNull() )
429 {
430 if ( !silenceNullWarnings )
431 {
432 QgsDebugError( u"NULL QVector3D was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
433 }
434 return true;
435 }
436 return false;
437 case QMetaType::Type::QVector4D:
438 if ( variant.value< QVector4D >().isNull() )
439 {
440 if ( !silenceNullWarnings )
441 {
442 QgsDebugError( u"NULL QVector4D was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
443 }
444 return true;
445 }
446 return false;
447 case QMetaType::Type::QQuaternion:
448 if ( variant.value< QQuaternion >().isNull() )
449 {
450 if ( !silenceNullWarnings )
451 {
452 QgsDebugError( u"NULL QQuaternion was stored in a QVariant -- stop it! Always use an invalid QVariant() instead."_s );
453 }
454 return true;
455 }
456 return false;
457
458 case QMetaType::Type::QColor:
459 case QMetaType::Type::QFont:
460 case QMetaType::Type::QBrush:
461 case QMetaType::Type::QPolygon:
462 case QMetaType::Type::QPalette:
463 case QMetaType::Type::QCursor:
464 case QMetaType::Type::QKeySequence:
465 case QMetaType::Type::QPen:
466 case QMetaType::Type::QTextLength:
467 case QMetaType::Type::QPolygonF:
468 case QMetaType::Type::QTextFormat:
469 case QMetaType::Type::QTransform:
470 case QMetaType::Type::QMatrix4x4:
471 case QMetaType::Type::QSizePolicy:
472 case QMetaType::Type::User:
473 default:
474 break;
475 }
476
477 return false;
478}
479
480bool QgsVariantUtils::isNumericType( QMetaType::Type metaType )
481{
482 switch ( metaType )
483 {
484 case QMetaType::Type::Int:
485 case QMetaType::Type::UInt:
486 case QMetaType::Type::LongLong:
487 case QMetaType::Type::ULongLong:
488 case QMetaType::Type::Double:
489 case QMetaType::Type::Float:
490 case QMetaType::Type::Short:
491 case QMetaType::Type::UShort:
492 case QMetaType::Type::Char:
493 case QMetaType::Type::UChar:
494 case QMetaType::Type::SChar:
495 return true;
496 default:
497 return false;
498 }
499}
500
501QMetaType::Type QgsVariantUtils::variantTypeToMetaType( QVariant::Type variantType )
502{
503 // variant types can be directly mapped to meta types
504 return static_cast< QMetaType::Type >( variantType );
505}
506
507QVariant::Type QgsVariantUtils::metaTypeToVariantType( QMetaType::Type metaType )
508{
509 // NOLINTBEGIN(bugprone-branch-clone)
510 switch ( metaType )
511 {
512 // exact mapping, these are identical:
513 case QMetaType::Bool:
514 case QMetaType::Int:
515 case QMetaType::UInt:
516 case QMetaType::LongLong:
517 case QMetaType::ULongLong:
518 case QMetaType::Double:
519 case QMetaType::QChar:
520 case QMetaType::QVariantMap:
521 case QMetaType::QVariantList:
522 case QMetaType::QString:
523 case QMetaType::QStringList:
524 case QMetaType::QByteArray:
525 case QMetaType::QBitArray:
526 case QMetaType::QDate:
527 case QMetaType::QTime:
528 case QMetaType::QDateTime:
529 case QMetaType::QUrl:
530 case QMetaType::QLocale:
531 case QMetaType::QRect:
532 case QMetaType::QRectF:
533 case QMetaType::QSize:
534 case QMetaType::QSizeF:
535 case QMetaType::QLine:
536 case QMetaType::QLineF:
537 case QMetaType::QPoint:
538 case QMetaType::QPointF:
539 case QMetaType::QRegularExpression:
540 case QMetaType::QVariantHash:
541 case QMetaType::QEasingCurve:
542 case QMetaType::QUuid:
543 case QMetaType::QModelIndex:
544 case QMetaType::QPersistentModelIndex:
545 case QMetaType::QFont:
546 case QMetaType::QPixmap:
547 case QMetaType::QBrush:
548 case QMetaType::QColor:
549 case QMetaType::QPalette:
550 case QMetaType::QImage:
551 case QMetaType::QPolygon:
552 case QMetaType::QRegion:
553 case QMetaType::QBitmap:
554 case QMetaType::QCursor:
555 case QMetaType::QKeySequence:
556 case QMetaType::QPen:
557 case QMetaType::QTextLength:
558 case QMetaType::QTextFormat:
559 case QMetaType::QTransform:
560 case QMetaType::QMatrix4x4:
561 case QMetaType::QVector2D:
562 case QMetaType::QVector3D:
563 case QMetaType::QVector4D:
564 case QMetaType::QQuaternion:
565 case QMetaType::QPolygonF:
566 case QMetaType::QIcon:
567 case QMetaType::QSizePolicy:
568 case QMetaType::UnknownType:
569 case QMetaType::User:
570 return static_cast< QVariant::Type >( metaType );
571
572 // lossy, not exact mappings. We prefer to "expand" types
573 // to avoid truncation
574 case QMetaType::Long:
575 return QVariant::Type::LongLong;
576
577 case QMetaType::ULong:
578 return QVariant::Type::ULongLong;
579
580 case QMetaType::Char:
581 case QMetaType::Char16:
582 case QMetaType::Char32:
583 case QMetaType::Short:
584 case QMetaType::SChar:
585 return QVariant::Type::Int;
586
587 case QMetaType::UShort:
588 case QMetaType::UChar:
589 return QVariant::Type::UInt;
590
591 case QMetaType::Float:
592#if QT_VERSION >= QT_VERSION_CHECK( 6, 5, 0 )
593 case QMetaType::Float16:
594#endif
595 return QVariant::Type::Double;
596
597 // no mapping possible:
598 case QMetaType::Nullptr:
599 case QMetaType::QCborSimpleType:
600 case QMetaType::Void:
601 case QMetaType::VoidStar:
602 case QMetaType::QVariant:
603 case QMetaType::QJsonValue:
604 case QMetaType::QJsonObject:
605 case QMetaType::QJsonArray:
606 case QMetaType::QJsonDocument:
607 case QMetaType::QCborValue:
608 case QMetaType::QCborArray:
609 case QMetaType::QCborMap:
610 case QMetaType::QObjectStar:
611 case QMetaType::QVariantPair:
612 case QMetaType::QByteArrayList:
613 case QMetaType::QColorSpace:
614 break;
615
616 default:
617 break;
618 }
619 // NOLINTEND(bugprone-branch-clone)
620 return QVariant::Type::UserType;
621}
622
623bool QgsVariantUtils::isUnsetAttributeValue( const QVariant &variant )
624{
625 return variant.userType() == qMetaTypeId< QgsUnsetAttributeValue >();
626}
627
628QVariant QgsVariantUtils::createNullVariant( QMetaType::Type metaType )
629{
630 return QVariant( QMetaType( metaType ) );
631}
632
633QString QgsVariantUtils::displayString( const QVariant &variant, int precision )
634{
635 auto _displayString = []( const QVariant &variant, int precision ) -> QString {
636 if ( QgsVariantUtils::isNull( variant ) )
637 {
639 }
640
641 // Special treatment for numeric types if group separator is set or decimalPoint is not a dot
642 if ( variant.userType() == QMetaType::Type::Double )
643 {
644 // Locales with decimal point != '.' or that require group separator: use QLocale
645 if ( QLocale().decimalPoint() != '.' || !( QLocale().numberOptions() & QLocale::NumberOption::OmitGroupSeparator ) )
646 {
647 if ( precision > 0 )
648 {
649 if ( -1 < variant.toDouble() && variant.toDouble() < 1 )
650 {
651 return QLocale().toString( variant.toDouble(), 'g', precision );
652 }
653 else
654 {
655 return QLocale().toString( variant.toDouble(), 'f', precision );
656 }
657 }
658 else
659 {
660 // Precision is not set, let's guess it from the
661 // standard conversion to string
662 const QString str( variant.toString() );
663 const int dotPosition( static_cast<int>( str.indexOf( '.' ) ) );
664 int precision;
665 if ( dotPosition < 0 && str.indexOf( 'e', 0, Qt::CaseInsensitive ) < 0 )
666 {
667 precision = 0;
668 return QLocale().toString( variant.toDouble(), 'f', precision );
669 }
670 else
671 {
672 if ( dotPosition < 0 )
673 precision = 0;
674 else
675 precision = static_cast<int>( str.length() ) - dotPosition - 1;
676
677 if ( -1 < variant.toDouble() && variant.toDouble() < 1 )
678 {
679 return QLocale().toString( variant.toDouble(), 'g', precision );
680 }
681 else
682 {
683 return QLocale().toString( variant.toDouble(), 'f', precision );
684 }
685 }
686 }
687 }
688 // Default for doubles with precision
689 else if ( precision > 0 )
690 {
691 if ( -1 < variant.toDouble() && variant.toDouble() < 1 )
692 {
693 return QString::number( variant.toDouble(), 'g', precision );
694 }
695 else
696 {
697 return QString::number( variant.toDouble(), 'f', precision );
698 }
699 }
700 }
701 // Other numeric types than doubles
702 else if ( QgsVariantUtils::isNumericType( static_cast< QMetaType::Type >( variant.userType() ) ) && !( QLocale().numberOptions() & QLocale::NumberOption::OmitGroupSeparator ) )
703 {
704 bool ok;
705 const qlonglong converted( variant.toLongLong( &ok ) );
706 if ( ok )
707 return QLocale().toString( converted );
708 }
709 else if ( variant.userType() == QMetaType::Type::QByteArray )
710 {
711 return QObject::tr( "BLOB" );
712 }
713
714 // Fallback if special rules do not apply
715 return variant.toString();
716 };
717
718 if ( variant.userType() == QMetaType::Type::QStringList || variant.userType() == QMetaType::Type::QVariantList )
719 {
720 QString result;
721 const QVariantList list = variant.toList();
722 for ( const QVariant &var : list )
723 {
724 if ( !result.isEmpty() )
725 {
726 result.append( ';' );
727 }
728 result.append( _displayString( var, precision ) );
729 }
730 return result;
731 }
732 else
733 {
734 return _displayString( variant, precision );
735 }
736}
737
738QString QgsVariantUtils::variantToHtml( const QVariantMap &variantMap, const QString &title = QString() )
739{
740 QString result;
741 if ( !title.isEmpty() )
742 {
743 result += u"<tr><td class=\"highlight\">%1</td><td></td></tr>"_s.arg( title );
744 }
745 for ( auto it = variantMap.constBegin(); it != variantMap.constEnd(); ++it )
746 {
747 if ( ( it.value().type() == QVariant::List || it.value().type() == QVariant::StringList ) )
748 {
749 const QVariantList childList = it.value().toList();
750 result += u"<tr><td class=\"highlight\">%1</td><td><ul>"_s.arg( it.key() );
751 for ( const QVariant &v : childList )
752 {
753 if ( v.type() == QVariant::Map )
754 {
755 const QVariantMap grandChildMap = v.toMap();
756 result += u"<li><table>%1</table></li>"_s.arg( variantToHtml( grandChildMap ) );
757 }
758 else
759 {
760 result += u"<li>%1</li>"_s.arg( QgsStringUtils::insertLinks( v.toString() ) );
761 }
762 }
763 result += "</ul></td></tr>"_L1;
764 }
765 else if ( it.value().type() == QVariant::Map )
766 {
767 const QVariantMap childMap = it.value().toMap();
768 result += u"<tr><td class=\"highlight\">%1</td><td><table>%2</table></td></tr>"_s.arg( it.key(), variantToHtml( childMap ) );
769 }
770 else
771 {
772 result += u"<tr><td class=\"highlight\">%1</td><td>%2</td></tr>"_s.arg( it.key(), QgsStringUtils::insertLinks( it.value().toString() ) );
773 }
774 }
775 return result;
776}
static QString nullRepresentation()
Returns the string used to represent the value NULL throughout QGIS.
static QString insertLinks(const QString &string, bool *foundLinks=nullptr)
Returns a string with any URL (e.g., http(s)/ftp) and mailto: text converted to valid HTML <a ....
static QMetaType::Type variantTypeToMetaType(QVariant::Type variantType)
Converts a QVariant::Type to a QMetaType::Type.
static QString displayString(const QVariant &variant, int precision=-1)
Returns a localized representation of value with the given precision, if precision is -1 then precisi...
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
static QString typeToDisplayString(QMetaType::Type type, QMetaType::Type subType=QMetaType::Type::UnknownType)
Returns a user-friendly translated string representing a QVariant type.
static QVariant createNullVariant(QMetaType::Type metaType)
Helper method to properly create a null QVariant from a metaType Returns the created QVariant.
static bool isNumericType(QMetaType::Type metaType)
Returns true if the specified metaType is a numeric type.
static bool isUnsetAttributeValue(const QVariant &variant)
Check if the variant is a QgsUnsetAttributeValue.
static QVariant::Type metaTypeToVariantType(QMetaType::Type metaType)
Converts a QMetaType::Type to a QVariant::Type.
static QString variantToHtml(const QVariantMap &variant, const QString &title)
Exports a variant map to a HTML formatted representation.
#define QgsDebugError(str)
Definition qgslogger.h:59