ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
QtCompat.h
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 // Qt5/Qt6 Compatibility Layer
9 //
10 // This header provides compatibility wrappers for APIs that differ between Qt5
11 // and Qt6. Include this header instead of directly using Qt headers for
12 // compatibility-sensitive APIs.
13 //
14 // SUPPORTED COMPATIBILITY FEATURES:
15 //
16 // 1. Regular Expressions:
17 // - QRegExp (Qt5) / QRegularExpression (Qt6)
18 // - Type alias: QtCompatRegExp
19 // - Functions: qtCompatRegExp(), qtCompatSplit(), qtCompatSplitRegex(),
20 // qtCompatReplace(), qtCompatRegExpMatch(),
21 // qtCompatRegExpIndexIn(), qtCompatRegExpPos(),
22 // qtCompatRegExpCap(), qtCompatRegExpMatchedLength()
23 // - Class: QtCompatRegExpWrapper (for QRegExp-style API)
24 //
25 // 2. String References:
26 // - QStringRef (Qt5) / QStringView (Qt6)
27 // - Type alias: QtCompatStringRef, QtCompatStringRefList
28 // - Functions: qtCompatStringRef(), qtCompatStringRefToString(),
29 // qtCompatSplitRef(), qtCompatSplitRefChar()
30 //
31 // 3. Split Behavior:
32 // - QString::SkipEmptyParts (Qt5) / Qt::SkipEmptyParts (Qt6)
33 // - Namespace: QtCompat::SkipEmptyParts, QtCompat::KeepEmptyParts
34 //
35 // 4. Font Metrics:
36 // - QFontMetrics::width() (Qt5) / horizontalAdvance() (Qt6)
37 // - Macro: QTCOMPAT_FONTMETRICS_WIDTH(fm, text)
38 //
39 // 5. Text Codec:
40 // - QTextCodec (Qt5) / QStringConverter (Qt6)
41 // - Type alias: QtCompatQTextCodec
42 // - Functions: qtCompatCodecForLocale(), qtCompatCodecForName()
43 //
44 // 6. Text Stream:
45 // - QTextStream::endl (Qt5) / Qt::endl (Qt6)
46 // - Namespace: QtCompat::endl
47 // - Macro: QTCOMPAT_ENDL
48 //
49 // 7. Wheel Events:
50 // - QWheelEvent::delta() / pos() (Qt5) / angleDelta() / position() (Qt6)
51 // - Functions: qtCompatWheelEventDelta(), qtCompatWheelEventPos()
52 //
53 // 8. Mouse Events:
54 // - QMouseEvent::pos() / globalPos() (Qt5) / position() / globalPosition()
55 // (Qt6)
56 // - Functions: qtCompatMouseEventPos(), qtCompatMouseEventGlobalPos(),
57 // qtCompatMouseEventPosInt(), qtCompatMouseEventGlobalPosInt()
58 //
59 // 9. Drop Events:
60 // - QDropEvent::pos() (Qt5) / position() (Qt6)
61 // - Functions: qtCompatDropEventPos(), qtCompatDropEventPosInt()
62 //
63 // 10. Map Operations:
64 // - QMap::insertMulti() / unite() (Qt5) / removed in Qt6
65 // - Functions: qtCompatMapInsertMulti(), qtCompatMapUnite()
66 //
67 // 11. QVariant Type:
68 // - QVariant::type() (Qt5) / typeId() (Qt6)
69 // - Type alias: QtCompatVariantType
70 // - Functions: qtCompatVariantType(), qtCompatVariantIsValid(),
71 // qtCompatVariantIsNull(), qtCompatVariantIsString(),
72 // qtCompatVariantIsInt(), qtCompatVariantIsDouble(),
73 // qtCompatVariantIsBool(), qtCompatVariantIsList(),
74 // qtCompatVariantIsMap()
75 //
76 // 12. Plain Text Edit:
77 // - QPlainTextEdit::setTabStopWidth() (Qt5) / setTabStopDistance() (Qt6)
78 // - Function: qtCompatSetTabStopWidth()
79 //
80 // 13. Container Iterators:
81 // - QSet<T>(begin, end) and QVector<T>(begin, end) constructors
82 // - Qt5.0-5.14: Not supported, use manual loops
83 // - Qt5.15+: Supported via iterator range constructors
84 // - Qt6: Supported via iterator range constructors
85 // - Functions: qtCompatQSetFromVector(), qtCompatQVectorFromSet()
86 //
87 // USAGE EXAMPLES:
88 //
89 // Regular Expression:
90 // Old: QStringList parts = str.split(QRegExp("\\s+"),
91 // QString::SkipEmptyParts); New: QStringList parts = qtCompatSplitRegex(str,
92 // "\\s+", QtCompat::SkipEmptyParts);
93 //
94 // Old: static const QRegExp filter("pattern");
95 // text.replace(filter, "");
96 // New: static const QtCompatRegExp filter("pattern"); // Efficient: compiled
97 // once
98 // qtCompatReplace(text, filter, ""); // Or: text.replace(filter, "");
99 //
100 // Font Metrics:
101 // Old: int w = fm.width(text);
102 // New: int w = QTCOMPAT_FONTMETRICS_WIDTH(fm, text);
103 //
104 // String References:
105 // Old: QStringRef ref = str.midRef(0, 10);
106 // New: QtCompatStringRef ref = qtCompatStringRef(str, 0, 10);
107 //
108 // Text Codec:
109 // Old: QTextCodec* codec = QTextCodec::codecForLocale();
110 // QString text = codec->toUnicode(data);
111 // New: QtCompatQTextCodec* codec = qtCompatCodecForLocale();
112 // QString text = codec->toUnicode(data);
113 //
114 // Text Stream:
115 // Old: stream << QTextStream::endl;
116 // New: stream << QtCompat::endl;
117 // Or: stream << QTCOMPAT_ENDL;
118 //
119 // Mouse Events:
120 // Old: QPoint pos = event->pos();
121 // New: QPointF pos = qtCompatMouseEventPos(event);
122 // Or for integer: QPoint pos = qtCompatMouseEventPosInt(event);
123 //
124 // Drop Events:
125 // Old: QPoint pos = event->pos();
126 // New: QPointF pos = qtCompatDropEventPos(event);
127 //
128 // QVariant Type:
129 // Old: if (var.type() == QVariant::String) { ... }
130 // New: if (qtCompatVariantIsString(var)) { ... }
131 //
132 // See QtCompat.example.cpp for more detailed usage examples.
133 // ----------------------------------------------------------------------------
134 
135 #pragma once
136 
137 #include <QMap>
138 #include <QMultiMap>
139 #include <QPoint>
140 #include <QPointF>
141 #include <QSet>
142 #include <QString>
143 #include <QStringList>
144 #include <QTextStream>
145 #include <QVector>
146 #include <QtGlobal>
147 
148 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
149 // Qt6 includes
150 #include <QRegularExpression>
151 #include <QStringView>
152 #include <Qt>
153 #else
154 // Qt5 includes
155 #include <QChar>
156 #include <QRegExp>
157 #include <QStringRef>
158 #include <QVector>
159 #endif
160 
161 // ----------------------------------------------------------------------------
162 // QRegExp / QRegularExpression Compatibility
163 // ----------------------------------------------------------------------------
164 // Qt5: QRegExp
165 // Qt6: QRegularExpression (QRegExp removed)
166 // ----------------------------------------------------------------------------
167 
168 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
169 // Qt6: Use QRegularExpression
170 using QtCompatRegExp = QRegularExpression;
171 
172 // Qt6 RegExp options
174 constexpr QRegularExpression::PatternOption CaseInsensitive =
175  QRegularExpression::CaseInsensitiveOption;
176 constexpr QRegularExpression::PatternOption DotMatchesEverything =
177  QRegularExpression::DotMatchesEverythingOption;
178 constexpr QRegularExpression::PatternOption Multiline =
179  QRegularExpression::MultilineOption;
180 } // namespace QtCompatRegExpOption
181 
182 // Helper function to convert QRegExp pattern to QRegularExpression
183 inline QRegularExpression qtCompatRegExp(const QString& pattern) {
184  return QRegularExpression(pattern);
185 }
186 
187 // Helper function for QString::split with QRegularExpression
188 inline QStringList qtCompatSplit(
189  const QString& str,
190  const QRegularExpression& regex,
191  Qt::SplitBehavior behavior = Qt::KeepEmptyParts) {
192  return str.split(regex, behavior);
193 }
194 #else
195 // Qt5: Use QRegExp
196 using QtCompatRegExp = QRegExp;
197 
198 // Qt5 RegExp options (using Qt namespace values)
199 namespace QtCompatRegExpOption {
200 constexpr Qt::CaseSensitivity CaseInsensitive = Qt::CaseInsensitive;
201 constexpr Qt::CaseSensitivity CaseSensitive = Qt::CaseSensitive;
202 } // namespace QtCompatRegExpOption
203 
204 // Helper function for Qt5 compatibility
205 inline QRegExp qtCompatRegExp(const QString& pattern) {
206  return QRegExp(pattern);
207 }
208 
209 // Helper function for QString::split with QRegExp
210 inline QStringList qtCompatSplit(
211  const QString& str,
212  const QRegExp& regex,
213  QString::SplitBehavior behavior = QString::KeepEmptyParts) {
214  return str.split(regex, behavior);
215 }
216 #endif
217 
218 // ----------------------------------------------------------------------------
219 // QStringRef / QStringView Compatibility
220 // ----------------------------------------------------------------------------
221 // Qt5: QStringRef, QVector<QStringRef>
222 // Qt6: QStringView (QStringRef removed), QList<QStringView>
223 // ----------------------------------------------------------------------------
224 
225 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
226 // Qt6: Use QStringView
227 using QtCompatStringRef = QStringView;
228 using QtCompatStringRefList = QList<QStringView>;
229 
230 // Helper to create QStringView from QString
231 inline QStringView qtCompatStringRef(const QString& str) noexcept {
232  return QStringView(str);
233 }
234 
235 // Helper to convert QStringView to QString
236 inline QString qtCompatStringRefToString(const QStringView& view) {
237  return view.toString();
238 }
239 
240 // Helper to create QStringView from QString with range
241 inline QStringView qtCompatStringRef(const QString& str,
242  int pos,
243  int n = -1) noexcept {
244  if (n < 0) {
245  return QStringView(str).mid(pos);
246  }
247  return QStringView(str).mid(pos, n);
248 }
249 
250 // Helper for QString::splitRef (Qt6 uses split with QStringView)
251 inline QtCompatStringRefList qtCompatSplitRef(const QString& str, QChar sep) {
253  QStringView view(str);
254  qsizetype start = 0;
255  while (start < view.length()) {
256  qsizetype end = view.indexOf(sep, start);
257  if (end < 0) {
258  result.append(view.mid(start));
259  break;
260  }
261  result.append(view.mid(start, end - start));
262  start = end + 1;
263  }
264  return result;
265 }
266 #else
267 // Qt5: Use QStringRef
268 using QtCompatStringRef = QStringRef;
269 using QtCompatStringRefList = QVector<QStringRef>;
270 
271 // Helper to create QStringRef from QString
272 inline QStringRef qtCompatStringRef(const QString& str) {
273  return QStringRef(&str);
274 }
275 
276 // Helper to convert QStringRef to QString
277 inline QString qtCompatStringRefToString(const QStringRef& ref) {
278  return ref.toString();
279 }
280 
281 // Helper to create QStringRef from QString with range
282 inline QStringRef qtCompatStringRef(const QString& str, int pos, int n = -1) {
283  return QStringRef(&str, pos, n < 0 ? str.length() - pos : n);
284 }
285 
286 // Helper for QString::splitRef (Qt5 native)
287 inline QtCompatStringRefList qtCompatSplitRef(const QString& str, QChar sep) {
288  return str.splitRef(sep);
289 }
290 #endif
291 
292 // ----------------------------------------------------------------------------
293 // QString::SplitBehavior / Qt::SplitBehavior Compatibility
294 // ----------------------------------------------------------------------------
295 // Qt5: QString::SkipEmptyParts, QString::KeepEmptyParts
296 // Qt6: Qt::SkipEmptyParts, Qt::KeepEmptyParts (moved to Qt namespace)
297 // ----------------------------------------------------------------------------
298 
299 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
300 // Qt6: Use Qt namespace
301 namespace QtCompat {
302 constexpr Qt::SplitBehavior SkipEmptyParts = Qt::SkipEmptyParts;
303 constexpr Qt::SplitBehavior KeepEmptyParts = Qt::KeepEmptyParts;
304 } // namespace QtCompat
305 
306 // Helper function for QString::split with regex pattern
307 // This is the most common pattern in the codebase
308 inline QStringList qtCompatSplitRegex(
309  const QString& str,
310  const QString& pattern,
311  Qt::SplitBehavior behavior = Qt::KeepEmptyParts) {
312  return str.split(QRegularExpression(pattern), behavior);
313 }
314 #else
315 // Qt5: Use QString namespace
316 namespace QtCompat {
317 constexpr QString::SplitBehavior SkipEmptyParts = QString::SkipEmptyParts;
318 constexpr QString::SplitBehavior KeepEmptyParts = QString::KeepEmptyParts;
319 } // namespace QtCompat
320 
321 // Helper function for QString::split with regex pattern
322 inline QStringList qtCompatSplitRegex(
323  const QString& str,
324  const QString& pattern,
325  QString::SplitBehavior behavior = QString::KeepEmptyParts) {
326  return str.split(QRegExp(pattern), behavior);
327 }
328 #endif
329 
330 // ----------------------------------------------------------------------------
331 // QFontMetrics::width() / horizontalAdvance() Compatibility
332 // ----------------------------------------------------------------------------
333 // Qt5: QFontMetrics::width() (deprecated in Qt5.11+)
334 // Qt6: QFontMetrics::horizontalAdvance() (width() removed)
335 // ----------------------------------------------------------------------------
336 
337 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
338 // Qt6: Only horizontalAdvance() exists
339 #define QTCOMPAT_FONTMETRICS_WIDTH(fm, text) (fm).horizontalAdvance(text)
340 #else
341 // Qt5: Prefer horizontalAdvance() if available (Qt5.11+), fallback to width()
342 #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
343 #define QTCOMPAT_FONTMETRICS_WIDTH(fm, text) (fm).horizontalAdvance(text)
344 #else
345 #define QTCOMPAT_FONTMETRICS_WIDTH(fm, text) (fm).width(text)
346 #endif
347 #endif
348 
349 // ----------------------------------------------------------------------------
350 // QString::replace() with QRegExp / QRegularExpression Compatibility
351 // ----------------------------------------------------------------------------
352 // Qt5: QString::replace(const QRegExp&, ...)
353 // Qt6: QString::replace(const QRegularExpression&, ...)
354 // ----------------------------------------------------------------------------
355 
356 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
357 // Qt6: Use QRegularExpression
358 
359 // Overload 1: Accept pre-compiled regex object (more efficient for repeated
360 // use)
361 inline QString& qtCompatReplace(QString& str,
362  const QRegularExpression& regex,
363  const QString& after) {
364  return str.replace(regex, after);
365 }
366 
367 inline QString qtCompatReplace(const QString& str,
368  const QRegularExpression& regex,
369  const QString& after) {
370  QString result = str;
371  result.replace(regex, after);
372  return result;
373 }
374 
375 // Overload 2: Accept pattern string (convenient but less efficient)
376 inline QString& qtCompatReplace(QString& str,
377  const QString& pattern,
378  const QString& after) {
379  return str.replace(QRegularExpression(pattern), after);
380 }
381 
382 inline QString qtCompatReplace(const QString& str,
383  const QString& pattern,
384  const QString& after) {
385  QString result = str;
386  result.replace(QRegularExpression(pattern), after);
387  return result;
388 }
389 #else
390 // Qt5: Use QRegExp
391 
392 // Overload 1: Accept pre-compiled regex object (more efficient for repeated
393 // use)
394 inline QString& qtCompatReplace(QString& str,
395  const QRegExp& regex,
396  const QString& after) {
397  return str.replace(regex, after);
398 }
399 
400 inline QString qtCompatReplace(const QString& str,
401  const QRegExp& regex,
402  const QString& after) {
403  QString result = str;
404  result.replace(regex, after);
405  return result;
406 }
407 
408 // Overload 2: Accept pattern string (convenient but less efficient)
409 inline QString& qtCompatReplace(QString& str,
410  const QString& pattern,
411  const QString& after) {
412  return str.replace(QRegExp(pattern), after);
413 }
414 
415 inline QString qtCompatReplace(const QString& str,
416  const QString& pattern,
417  const QString& after) {
418  QString result = str;
419  result.replace(QRegExp(pattern), after);
420  return result;
421 }
422 #endif
423 
424 // ----------------------------------------------------------------------------
425 // Additional Convenience Functions
426 // ----------------------------------------------------------------------------
427 
428 // For QString::splitRef with character separator
429 // Usage: qtCompatSplitRefChar(str, '.')
430 inline QtCompatStringRefList qtCompatSplitRefChar(const QString& str,
431  QChar sep) {
432  return qtCompatSplitRef(str, sep);
433 }
434 
435 // ----------------------------------------------------------------------------
436 // QRegExp / QRegularExpression Match Compatibility
437 // ----------------------------------------------------------------------------
438 // Qt5: QRegExp::indexIn() returns match position or -1
439 // Qt6: QRegularExpression::match() returns QRegularExpressionMatch
440 // ----------------------------------------------------------------------------
441 
442 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
443 // Qt6: Use QRegularExpression::match()
444 #include <QRegularExpressionMatch>
445 
446 inline bool qtCompatRegExpMatch(const QRegularExpression& regex,
447  const QString& str) {
448  return regex.match(str).hasMatch();
449 }
450 
451 // Compatibility wrapper for QRegExp::indexIn() - returns match position or -1
452 inline int qtCompatRegExpIndexIn(const QRegularExpression& regex,
453  const QString& str,
454  int offset = 0) {
455  QRegularExpressionMatch match = regex.match(str, offset);
456  return match.hasMatch() ? match.capturedStart() : -1;
457 }
458 
459 // Compatibility wrapper for QRegExp::pos() - returns position of captured group
460 inline int qtCompatRegExpPos(const QRegularExpressionMatch& match,
461  int nth = 0) noexcept {
462  return match.capturedStart(nth);
463 }
464 
465 // Compatibility wrapper for QRegExp::cap() - returns captured text
466 inline QString qtCompatRegExpCap(const QRegularExpressionMatch& match,
467  int nth = 0) {
468  return match.captured(nth);
469 }
470 
471 // Compatibility wrapper for QRegExp::matchedLength() - returns length of match
473  const QRegularExpressionMatch& match) noexcept {
474  return match.capturedLength();
475 }
476 
477 // Helper class to wrap QRegularExpression for Qt5 QRegExp-style API
478 // This allows code to use QRegExp-like API that works with both Qt5 and Qt6
480 private:
481  QRegularExpression m_regex;
482  mutable QRegularExpressionMatch m_lastMatch;
483 
484 public:
486 
487  QtCompatRegExpWrapper(const QRegularExpression& regex) : m_regex(regex) {}
488 
489  QtCompatRegExpWrapper(const QString& pattern) : m_regex(pattern) {}
490 
491  // QRegExp::indexIn() compatibility
492  int indexIn(const QString& str, int offset = 0) const {
493  m_lastMatch = m_regex.match(str, offset);
494  return m_lastMatch.hasMatch() ? m_lastMatch.capturedStart() : -1;
495  }
496 
497  // QRegExp::pos() compatibility - returns position of captured group
498  int pos(int nth = 0) const noexcept {
499  return m_lastMatch.capturedStart(nth);
500  }
501 
502  // QRegExp::cap() compatibility - returns captured text
503  QString cap(int nth = 0) const { return m_lastMatch.captured(nth); }
504 
505  // QRegExp::matchedLength() compatibility
506  int matchedLength() const noexcept { return m_lastMatch.capturedLength(); }
507 
508  // Get the underlying QRegularExpression (Qt6) or convert to QRegExp (Qt5)
509  const QRegularExpression& regex() const noexcept { return m_regex; }
510 
511  // Allow implicit conversion to QRegularExpression for Qt6
512  operator const QRegularExpression&() const noexcept { return m_regex; }
513 };
514 
515 #else
516 // Qt5: Use QRegExp::indexIn()
517 inline bool qtCompatRegExpMatch(const QRegExp& regex, const QString& str) {
518  return regex.indexIn(str) >= 0;
519 }
520 
521 // Qt5: Direct passthrough functions
522 inline int qtCompatRegExpIndexIn(const QRegExp& regex,
523  const QString& str,
524  int offset = 0) {
525  return regex.indexIn(str, offset);
526 }
527 
528 inline int qtCompatRegExpPos(const QRegExp& regex, int nth = 0) noexcept {
529  return regex.pos(nth);
530 }
531 
532 inline QString qtCompatRegExpCap(const QRegExp& regex, int nth = 0) {
533  return regex.cap(nth);
534 }
535 
536 inline int qtCompatRegExpMatchedLength(const QRegExp& regex) noexcept {
537  return regex.matchedLength();
538 }
539 
540 // Qt5: QRegExp wrapper that provides the same interface
541 class QtCompatRegExpWrapper {
542 private:
543  mutable QRegExp m_regex;
544 
545 public:
546  QtCompatRegExpWrapper() = default;
547 
548  QtCompatRegExpWrapper(const QRegExp& regex) : m_regex(regex) {}
549 
550  QtCompatRegExpWrapper(const QString& pattern) : m_regex(pattern) {}
551 
552  int indexIn(const QString& str, int offset = 0) const {
553  return m_regex.indexIn(str, offset);
554  }
555 
556  int pos(int nth = 0) const noexcept { return m_regex.pos(nth); }
557 
558  QString cap(int nth = 0) const { return m_regex.cap(nth); }
559 
560  int matchedLength() const noexcept { return m_regex.matchedLength(); }
561 
562  const QRegExp& regex() const noexcept { return m_regex; }
563 
564  operator const QRegExp&() const noexcept { return m_regex; }
565 };
566 #endif
567 
568 // ----------------------------------------------------------------------------
569 // QTextCodec Compatibility
570 // ----------------------------------------------------------------------------
571 // Qt5: QTextCodec (available)
572 // Qt6: QTextCodec removed, use QStringConverter instead
573 // ----------------------------------------------------------------------------
574 
575 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
576 // Qt6: QTextCodec is removed, use QStringConverter
577 #include <QByteArray>
578 #include <QStringConverter>
579 
580 // Forward declaration for compatibility wrapper
581 class QtCompatTextCodec;
582 
583 // Compatibility wrapper class for QTextCodec API
585 private:
586  QStringConverter::Encoding m_encoding;
587 
588 public:
590  QStringConverter::Encoding encoding = QStringConverter::System)
591  : m_encoding(encoding) {}
592 
593  // Convert from Unicode (QString) to encoding (QByteArray)
594  QByteArray fromUnicode(const QString& str) {
595  QStringEncoder encoder(m_encoding);
596  if (!encoder.isValid()) {
597  // Fallback to UTF-8 if encoding is not available
598  encoder = QStringEncoder(QStringConverter::Utf8);
599  }
600  auto result = encoder.encode(str);
601  if (encoder.hasError()) {
602  // If encoding fails, fallback to UTF-8
603  QStringEncoder utf8Encoder(QStringConverter::Utf8);
604  return utf8Encoder.encode(str);
605  }
606  return result;
607  }
608 
609  // Convert from encoding (const char*) to Unicode (QString)
610  QString toUnicode(const char* chars, int len = -1) {
611  QStringDecoder decoder(m_encoding);
612  if (!decoder.isValid()) {
613  // Fallback to UTF-8 if encoding is not available
614  decoder = QStringDecoder(QStringConverter::Utf8);
615  }
616  QByteArray ba;
617  if (len < 0) {
618  ba = QByteArray(chars);
619  } else {
620  ba = QByteArray(chars, len);
621  }
622  auto result = decoder.decode(ba);
623  if (decoder.hasError()) {
624  // If decoding fails, try UTF-8
625  QStringDecoder utf8Decoder(QStringConverter::Utf8);
626  return utf8Decoder.decode(ba);
627  }
628  return result;
629  }
630 
631  // Convert from encoding (QByteArray) to Unicode (QString)
632  QString toUnicode(const QByteArray& ba) {
633  QStringDecoder decoder(m_encoding);
634  if (!decoder.isValid()) {
635  // Fallback to UTF-8 if encoding is not available
636  decoder = QStringDecoder(QStringConverter::Utf8);
637  }
638  auto result = decoder.decode(ba);
639  if (decoder.hasError()) {
640  // If decoding fails, try UTF-8
641  QStringDecoder utf8Decoder(QStringConverter::Utf8);
642  return utf8Decoder.decode(ba);
643  }
644  return result;
645  }
646 };
647 
648 // Compatibility function to get codec for locale (similar to
649 // QTextCodec::codecForLocale())
651  static QtCompatTextCodec codec(QStringConverter::System);
652  return &codec;
653 }
654 
655 // Compatibility function to get codec by name (similar to
656 // QTextCodec::codecForName())
658  if (!name) {
659  return qtCompatCodecForLocale();
660  }
661 
662  QString nameStr = QString::fromLatin1(name).toLower();
663 
664  // Handle common encoding names
665  if (nameStr == "utf-8" || nameStr == "utf8") {
666  static QtCompatTextCodec utf8Codec(QStringConverter::Utf8);
667  return &utf8Codec;
668  } else if (nameStr == "utf-16" || nameStr == "utf16") {
669  static QtCompatTextCodec utf16Codec(QStringConverter::Utf16);
670  return &utf16Codec;
671  } else if (nameStr == "utf-16le" || nameStr == "utf16le") {
672  static QtCompatTextCodec utf16leCodec(QStringConverter::Utf16LE);
673  return &utf16leCodec;
674  } else if (nameStr == "utf-16be" || nameStr == "utf16be") {
675  static QtCompatTextCodec utf16beCodec(QStringConverter::Utf16BE);
676  return &utf16beCodec;
677  } else if (nameStr == "latin1" || nameStr == "iso-8859-1") {
678  static QtCompatTextCodec latin1Codec(QStringConverter::Latin1);
679  return &latin1Codec;
680  }
681 
682  // For other encodings, try to use system encoding or fallback to UTF-8
683  // In Qt6, QStringConverter doesn't support all encodings that QTextCodec
684  // did So we fallback to system encoding or UTF-8
685  return qtCompatCodecForLocale();
686 }
687 
688 // Type alias for compatibility
690 
691 #else
692 // Qt5: Use QTextCodec directly
693 #include <QTextCodec>
694 
695 // Type alias for compatibility
697 
698 // Compatibility functions
701 }
702 
703 inline QTextCodec* qtCompatCodecForName(const char* name) {
705 }
706 #endif
707 
708 // ----------------------------------------------------------------------------
709 // QTextStream::endl Compatibility
710 // ----------------------------------------------------------------------------
711 // Qt5: endl is a global function
712 // Qt6: Qt::endl (moved to Qt namespace)
713 // ----------------------------------------------------------------------------
714 
715 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
716 // Qt6: Use Qt::endl
717 namespace QtCompat {
718 inline QTextStream& endl(QTextStream& stream) { return Qt::endl(stream); }
719 } // namespace QtCompat
720 
721 #define QTCOMPAT_ENDL Qt::endl
722 #else
723 // Qt5: Implement endl directly to avoid conflicts with std::endl
724 // Qt's endl writes a newline and flushes the stream
725 namespace QtCompat {
726 inline QTextStream& endl(QTextStream& stream) {
727  stream << QLatin1Char('\n');
728  stream.flush();
729  return stream;
730 }
731 } // namespace QtCompat
732 
733 // Use QtCompat::endl for the macro to avoid std::endl conflicts
734 #define QTCOMPAT_ENDL QtCompat::endl
735 #endif
736 
737 // ----------------------------------------------------------------------------
738 // QWheelEvent Compatibility
739 // ----------------------------------------------------------------------------
740 // Qt5: QWheelEvent::delta() returns int, QWheelEvent::pos() returns QPoint
741 // Qt6: QWheelEvent::delta() removed, use angleDelta().y() (returns int),
742 // QWheelEvent::position() returns QPointF
743 // Compatibility functions return double and QPointF for consistency.
744 // Note: QWheelEvent is in QtWidgets module. Files using these functions must
745 // link QtWidgets.
746 // ----------------------------------------------------------------------------
747 
748 #include <QWheelEvent>
749 
750 // Compatibility function for QWheelEvent::delta() - returns double
751 inline double qtCompatWheelEventDelta(const QWheelEvent* event) noexcept {
752 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
753  return static_cast<double>(event->angleDelta().y());
754 #else
755  return static_cast<double>(event->delta());
756 #endif
757 }
758 
759 // Compatibility function for QWheelEvent::pos() - returns QPointF
760 inline QPointF qtCompatWheelEventPos(const QWheelEvent* event) noexcept {
761 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
762  return event->position();
763 #else
764  return QPointF(event->pos());
765 #endif
766 }
767 
768 // ----------------------------------------------------------------------------
769 // QMouseEvent Compatibility
770 // ----------------------------------------------------------------------------
771 // Qt5: QMouseEvent::pos() returns QPoint, globalPos() returns QPoint
772 // Qt6: QMouseEvent::pos() removed, use position() (returns QPointF),
773 // globalPos() removed, use globalPosition() (returns QPointF)
774 // ----------------------------------------------------------------------------
775 
776 #include <QMouseEvent>
777 
778 // Compatibility function for QMouseEvent::pos() - returns QPointF
779 inline QPointF qtCompatMouseEventPos(const QMouseEvent* event) noexcept {
780 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
781  return event->position();
782 #else
783  return QPointF(event->pos());
784 #endif
785 }
786 
787 // Compatibility function for QMouseEvent::globalPos() - returns QPointF
788 inline QPointF qtCompatMouseEventGlobalPos(const QMouseEvent* event) noexcept {
789 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
790  return event->globalPosition();
791 #else
792  return QPointF(event->globalPos());
793 #endif
794 }
795 
796 // Compatibility function for QMouseEvent::pos() - returns QPoint (integer)
797 inline QPoint qtCompatMouseEventPosInt(const QMouseEvent* event) noexcept {
798 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
799  return event->position().toPoint();
800 #else
801  return event->pos();
802 #endif
803 }
804 
805 // Compatibility function for QMouseEvent::globalPos() - returns QPoint
806 // (integer)
808  const QMouseEvent* event) noexcept {
809 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
810  return event->globalPosition().toPoint();
811 #else
812  return event->globalPos();
813 #endif
814 }
815 
816 // ----------------------------------------------------------------------------
817 // QDropEvent Compatibility
818 // ----------------------------------------------------------------------------
819 // Qt5: QDropEvent::pos() returns QPoint
820 // Qt6: QDropEvent::pos() removed, use position() (returns QPointF)
821 // ----------------------------------------------------------------------------
822 
823 #include <QDropEvent>
824 
825 // Compatibility function for QDropEvent::pos() - returns QPointF
826 inline QPointF qtCompatDropEventPos(const QDropEvent* event) noexcept {
827 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
828  return event->position();
829 #else
830  return QPointF(event->pos());
831 #endif
832 }
833 
834 // Compatibility function for QDropEvent::pos() - returns QPoint (integer)
835 inline QPoint qtCompatDropEventPosInt(const QDropEvent* event) noexcept {
836 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
837  return event->position().toPoint();
838 #else
839  return event->pos();
840 #endif
841 }
842 
843 // ----------------------------------------------------------------------------
844 // QMap::insertMulti() / QMultiMap Compatibility
845 // ----------------------------------------------------------------------------
846 // Qt5: QMap::insertMulti() allows multiple values per key
847 // Qt6: QMap::insertMulti() removed, use QMultiMap or insert() which replaces
848 // ----------------------------------------------------------------------------
849 
850 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
851 // Qt6: QMap::insertMulti() is removed, use QMultiMap
852 // For compatibility, we provide a template function that works with QMultiMap
853 template <typename Key, typename T>
854 void qtCompatMapInsertMulti(QMap<Key, T>* map, const Key& key, const T& value) {
855  // In Qt6, QMap doesn't support insertMulti, so we need to use QMultiMap
856  // But if the map is actually a QMultiMap, we can use insert
857  // For now, we'll use insert which in Qt6 QMap replaces the value
858  // If you need multi-value behavior, use QMultiMap explicitly
859  map->insert(key, value);
860 }
861 
862 // For QMultiMap, insert works correctly
863 template <typename Key, typename T>
864 void qtCompatMapInsertMulti(QMultiMap<Key, T>* map,
865  const Key& key,
866  const T& value) {
867  map->insert(key, value);
868 }
869 
870 // Compatibility for QMap::unite() - removed in Qt6
871 template <typename Key, typename T>
872 void qtCompatMapUnite(QMap<Key, T>* map, const QMap<Key, T>& other) {
873  // In Qt6, use insert() which accepts the entire map
874  map->insert(other);
875 }
876 
877 template <typename Key, typename T>
878 void qtCompatMapUnite(QMultiMap<Key, T>* map, const QMultiMap<Key, T>& other) {
879  // In Qt6, use insert() which accepts the entire map
880  map->insert(other);
881 }
882 #else
883 // Qt5: Direct passthrough functions
884 template <typename Key, typename T>
885 void qtCompatMapInsertMulti(QMap<Key, T>* map, const Key& key, const T& value) {
886  map->insertMulti(key, value);
887 }
888 
889 template <typename Key, typename T>
890 void qtCompatMapInsertMulti(QMultiMap<Key, T>* map,
891  const Key& key,
892  const T& value) {
893  map->insert(key, value);
894 }
895 
896 template <typename Key, typename T>
897 void qtCompatMapUnite(QMap<Key, T>* map, const QMap<Key, T>& other) {
898  map->unite(other);
899 }
900 
901 template <typename Key, typename T>
902 void qtCompatMapUnite(QMultiMap<Key, T>* map, const QMultiMap<Key, T>& other) {
903  map->unite(other);
904 }
905 #endif
906 
907 // ----------------------------------------------------------------------------
908 // QVariant Type Compatibility
909 // ----------------------------------------------------------------------------
910 // Qt5: QVariant::type() returns QVariant::Type enum
911 // Qt6: QVariant::type() removed, use typeId() which returns QMetaType::Type
912 // ----------------------------------------------------------------------------
913 
914 #include <QVariant>
915 
916 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
917 // Qt6: Use typeId() and QMetaType
918 using QtCompatVariantType = QMetaType::Type;
919 
920 inline QMetaType::Type qtCompatVariantType(const QVariant& var) noexcept {
921  return static_cast<QMetaType::Type>(var.typeId());
922 }
923 
924 inline bool qtCompatVariantIsValid(const QVariant& var) noexcept {
925  return var.isValid();
926 }
927 
928 inline bool qtCompatVariantIsNull(const QVariant& var) noexcept {
929  return var.isNull();
930 }
931 
932 // Type checking helpers
933 inline bool qtCompatVariantIsString(const QVariant& var) noexcept {
934  return var.typeId() == QMetaType::QString;
935 }
936 
937 inline bool qtCompatVariantIsInt(const QVariant& var) noexcept {
938  return var.typeId() == QMetaType::Int;
939 }
940 
941 inline bool qtCompatVariantIsDouble(const QVariant& var) noexcept {
942  return var.typeId() == QMetaType::Double;
943 }
944 
945 inline bool qtCompatVariantIsBool(const QVariant& var) noexcept {
946  return var.typeId() == QMetaType::Bool;
947 }
948 
949 inline bool qtCompatVariantIsList(const QVariant& var) noexcept {
950  return var.typeId() == QMetaType::QVariantList;
951 }
952 
953 inline bool qtCompatVariantIsMap(const QVariant& var) noexcept {
954  return var.typeId() == QMetaType::QVariantMap;
955 }
956 
957 #else
958 // Qt5: Use type() and QVariant::Type
959 using QtCompatVariantType = QVariant::Type;
960 
961 inline QVariant::Type qtCompatVariantType(const QVariant& var) noexcept {
962  return var.type();
963 }
964 
965 inline bool qtCompatVariantIsValid(const QVariant& var) noexcept {
966  return var.isValid();
967 }
968 
969 inline bool qtCompatVariantIsNull(const QVariant& var) noexcept {
970  return var.isNull();
971 }
972 
973 // Type checking helpers
974 inline bool qtCompatVariantIsString(const QVariant& var) noexcept {
975  return var.type() == QVariant::String;
976 }
977 
978 inline bool qtCompatVariantIsInt(const QVariant& var) noexcept {
979  return var.type() == QVariant::Int;
980 }
981 
982 inline bool qtCompatVariantIsDouble(const QVariant& var) noexcept {
983  return var.type() == QVariant::Double;
984 }
985 
986 inline bool qtCompatVariantIsBool(const QVariant& var) noexcept {
987  return var.type() == QVariant::Bool;
988 }
989 
990 inline bool qtCompatVariantIsList(const QVariant& var) noexcept {
991  return var.type() == QVariant::List;
992 }
993 
994 inline bool qtCompatVariantIsMap(const QVariant& var) noexcept {
995  return var.type() == QVariant::Map;
996 }
997 #endif
998 
999 // ----------------------------------------------------------------------------
1000 // QPlainTextEdit::setTabStopWidth() / setTabStopDistance() Compatibility
1001 // ----------------------------------------------------------------------------
1002 // Qt5: QPlainTextEdit::setTabStopWidth(int width) (deprecated in Qt5.10+)
1003 // Qt6: QPlainTextEdit::setTabStopDistance(qreal distance) (setTabStopWidth
1004 // removed)
1005 // ----------------------------------------------------------------------------
1006 
1007 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
1008 // Qt6: Use setTabStopDistance() which accepts qreal
1009 #include <QPlainTextEdit>
1010 inline void qtCompatSetTabStopWidth(QPlainTextEdit* edit, int width) {
1011  edit->setTabStopDistance(static_cast<qreal>(width));
1012 }
1013 #else
1014 // Qt5: Use setTabStopWidth() if available, otherwise use setTabStopDistance()
1015 #include <QPlainTextEdit>
1016 #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
1017 // Qt5.10+: setTabStopWidth is deprecated, prefer setTabStopDistance
1018 inline void qtCompatSetTabStopWidth(QPlainTextEdit* edit, int width) {
1019  edit->setTabStopDistance(static_cast<qreal>(width));
1020 }
1021 #else
1022 // Qt5.0-5.9: Use setTabStopWidth
1023 inline void qtCompatSetTabStopWidth(QPlainTextEdit* edit, int width) {
1024  edit->setTabStopWidth(width);
1025 }
1026 #endif
1027 #endif
1028 
1029 // ----------------------------------------------------------------------------
1030 // QSet / QVector Iterator Range Constructor Compatibility
1031 // ----------------------------------------------------------------------------
1032 // Qt5.0-5.14: QSet<T>(begin, end) and QVector<T>(begin, end) constructors not
1033 // supported Qt5.15+: Both support iterator range constructors Qt6: Both support
1034 // iterator range constructors
1035 // ----------------------------------------------------------------------------
1036 
1037 // Helper to create QSet from QVector (Qt5/Qt6 compatible)
1038 template <typename T>
1039 QSet<T> qtCompatQSetFromVector(const QVector<T>& vec) {
1040 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
1041  // Qt5.15+ and Qt6: Use iterator range constructor
1042  return QSet<T>(vec.begin(), vec.end());
1043 #else
1044  // Qt5.0-5.14: Manual insertion (iterator range constructor not available)
1045  QSet<T> result;
1046  result.reserve(vec.size());
1047  for (const T& item : vec) {
1048  result.insert(item);
1049  }
1050  return result;
1051 #endif
1052 }
1053 
1054 // Helper to create QVector from QSet (Qt5/Qt6 compatible)
1055 template <typename T>
1056 QVector<T> qtCompatQVectorFromSet(const QSet<T>& set) {
1057 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
1058  // Qt5.15+ and Qt6: Use iterator range constructor
1059  return QVector<T>(set.begin(), set.end());
1060 #else
1061  // Qt5.0-5.14: Manual conversion (iterator range constructor not available)
1062  QVector<T> result;
1063  result.reserve(set.size());
1064  for (const T& item : set) {
1065  result.append(item);
1066  }
1067  return result;
1068 #endif
1069 }
1070 
1071 // Backward compatibility aliases (for code already using these names)
1072 template <typename T>
1073 inline QSet<T> qSetFromVector(const QVector<T>& vec) {
1074  return qtCompatQSetFromVector(vec);
1075 }
1076 
1077 template <typename T>
1078 inline QVector<T> qVectorFromSet(const QSet<T>& set) {
1079  return qtCompatQVectorFromSet(set);
1080 }
MouseEvent event
int width
std::string name
int offset
void qtCompatSetTabStopWidth(QPlainTextEdit *edit, int width)
Definition: QtCompat.h:1010
QPointF qtCompatWheelEventPos(const QWheelEvent *event) noexcept
Definition: QtCompat.h:760
QStringList qtCompatSplitRegex(const QString &str, const QString &pattern, Qt::SplitBehavior behavior=Qt::KeepEmptyParts)
Definition: QtCompat.h:308
QtCompatTextCodec * qtCompatCodecForName(const char *name)
Definition: QtCompat.h:657
QPointF qtCompatDropEventPos(const QDropEvent *event) noexcept
Definition: QtCompat.h:826
QtCompatTextCodec * qtCompatCodecForLocale()
Definition: QtCompat.h:650
QList< QStringView > QtCompatStringRefList
Definition: QtCompat.h:228
bool qtCompatVariantIsNull(const QVariant &var) noexcept
Definition: QtCompat.h:928
QMetaType::Type QtCompatVariantType
Definition: QtCompat.h:918
QSet< T > qtCompatQSetFromVector(const QVector< T > &vec)
Definition: QtCompat.h:1039
int qtCompatRegExpIndexIn(const QRegularExpression &regex, const QString &str, int offset=0)
Definition: QtCompat.h:452
QtCompatStringRefList qtCompatSplitRef(const QString &str, QChar sep)
Definition: QtCompat.h:251
QString qtCompatRegExpCap(const QRegularExpressionMatch &match, int nth=0)
Definition: QtCompat.h:466
QString qtCompatStringRefToString(const QStringView &view)
Definition: QtCompat.h:236
QStringView QtCompatStringRef
Definition: QtCompat.h:227
void qtCompatMapInsertMulti(QMap< Key, T > *map, const Key &key, const T &value)
Definition: QtCompat.h:854
int qtCompatRegExpPos(const QRegularExpressionMatch &match, int nth=0) noexcept
Definition: QtCompat.h:460
QPoint qtCompatMouseEventPosInt(const QMouseEvent *event) noexcept
Definition: QtCompat.h:797
QString & qtCompatReplace(QString &str, const QRegularExpression &regex, const QString &after)
Definition: QtCompat.h:361
bool qtCompatVariantIsString(const QVariant &var) noexcept
Definition: QtCompat.h:933
QtCompatStringRefList qtCompatSplitRefChar(const QString &str, QChar sep)
Definition: QtCompat.h:430
QSet< T > qSetFromVector(const QVector< T > &vec)
Definition: QtCompat.h:1073
double qtCompatWheelEventDelta(const QWheelEvent *event) noexcept
Definition: QtCompat.h:751
QPointF qtCompatMouseEventPos(const QMouseEvent *event) noexcept
Definition: QtCompat.h:779
bool qtCompatVariantIsDouble(const QVariant &var) noexcept
Definition: QtCompat.h:941
int qtCompatRegExpMatchedLength(const QRegularExpressionMatch &match) noexcept
Definition: QtCompat.h:472
QMetaType::Type qtCompatVariantType(const QVariant &var) noexcept
Definition: QtCompat.h:920
QStringList qtCompatSplit(const QString &str, const QRegularExpression &regex, Qt::SplitBehavior behavior=Qt::KeepEmptyParts)
Definition: QtCompat.h:188
void qtCompatMapUnite(QMap< Key, T > *map, const QMap< Key, T > &other)
Definition: QtCompat.h:872
QVector< T > qVectorFromSet(const QSet< T > &set)
Definition: QtCompat.h:1078
QRegularExpression qtCompatRegExp(const QString &pattern)
Definition: QtCompat.h:183
QVector< T > qtCompatQVectorFromSet(const QSet< T > &set)
Definition: QtCompat.h:1056
QPoint qtCompatMouseEventGlobalPosInt(const QMouseEvent *event) noexcept
Definition: QtCompat.h:807
bool qtCompatVariantIsList(const QVariant &var) noexcept
Definition: QtCompat.h:949
QRegularExpression QtCompatRegExp
Definition: QtCompat.h:170
bool qtCompatVariantIsMap(const QVariant &var) noexcept
Definition: QtCompat.h:953
QStringView qtCompatStringRef(const QString &str) noexcept
Definition: QtCompat.h:231
QPointF qtCompatMouseEventGlobalPos(const QMouseEvent *event) noexcept
Definition: QtCompat.h:788
bool qtCompatVariantIsInt(const QVariant &var) noexcept
Definition: QtCompat.h:937
QPoint qtCompatDropEventPosInt(const QDropEvent *event) noexcept
Definition: QtCompat.h:835
bool qtCompatVariantIsBool(const QVariant &var) noexcept
Definition: QtCompat.h:945
bool qtCompatVariantIsValid(const QVariant &var) noexcept
Definition: QtCompat.h:924
bool qtCompatRegExpMatch(const QRegularExpression &regex, const QString &str)
Definition: QtCompat.h:446
core::Tensor result
Definition: VtkUtils.cpp:76
static QTextCodec * codecForName(const char *name)
Definition: quazip.h:50
static QTextCodec * codecForLocale()
Definition: quazip.h:44
int indexIn(const QString &str, int offset=0) const
Definition: QtCompat.h:492
QtCompatRegExpWrapper()=default
QString cap(int nth=0) const
Definition: QtCompat.h:503
QtCompatRegExpWrapper(const QString &pattern)
Definition: QtCompat.h:489
int pos(int nth=0) const noexcept
Definition: QtCompat.h:498
int matchedLength() const noexcept
Definition: QtCompat.h:506
const QRegularExpression & regex() const noexcept
Definition: QtCompat.h:509
QtCompatRegExpWrapper(const QRegularExpression &regex)
Definition: QtCompat.h:487
QString toUnicode(const char *chars, int len=-1)
Definition: QtCompat.h:610
QString toUnicode(const QByteArray &ba)
Definition: QtCompat.h:632
QtCompatTextCodec(QStringConverter::Encoding encoding=QStringConverter::System)
Definition: QtCompat.h:589
QByteArray fromUnicode(const QString &str)
Definition: QtCompat.h:594
constexpr QRegularExpression::PatternOption Multiline
Definition: QtCompat.h:178
constexpr QRegularExpression::PatternOption DotMatchesEverything
Definition: QtCompat.h:176
constexpr QRegularExpression::PatternOption CaseInsensitive
Definition: QtCompat.h:174
constexpr Qt::SplitBehavior SkipEmptyParts
Definition: QtCompat.h:302
QTextStream & endl(QTextStream &stream)
Definition: QtCompat.h:718
constexpr Qt::SplitBehavior KeepEmptyParts
Definition: QtCompat.h:303
unsigned Bool
Definition: sqlite3.c:20710