swift
columnformatters.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include <QDate>
7 #include <QDateTime>
8 #include <QImage>
9 #include <QMetaType>
10 #include <QScopedPointer>
11 #include <QTime>
12 #include <QVariant>
13 
14 #include "misc/aviation/altitude.h"
16 #include "misc/iconlist.h"
17 #include "misc/icons.h"
18 #include "misc/rgbcolor.h"
19 #include "misc/variant.h"
20 
21 using namespace swift::misc;
22 using namespace swift::misc::aviation;
23 using namespace swift::misc::physical_quantities;
24 
25 namespace swift::gui::models
26 {
27  Qt::ItemFlags CDefaultFormatter::flags(Qt::ItemFlags flags, bool editable) const
28  {
29  return editable ? (flags | Qt::ItemIsEditable) : (flags & ~Qt::ItemIsEditable);
30  }
31 
32  CVariant CDefaultFormatter::displayRole(const CVariant &dataCVariant) const
33  {
34  return keepStandardTypesConvertToStringOtherwise(dataCVariant);
35  }
36 
37  CVariant CDefaultFormatter::editRole(const CVariant &dataCVariant) const
38  {
39  return keepStandardTypesConvertToStringOtherwise(dataCVariant);
40  }
41 
42  CVariant CDefaultFormatter::tooltipRole(const CVariant &value) const
43  {
44  if (static_cast<QMetaType::Type>(value.type()) == QMetaType::QString) { return value; }
45  return value.toQString(m_useI18n);
46  }
47 
48  CVariant CDefaultFormatter::decorationRole(const CVariant &dataCVariant) const
49  {
50  // direct return if type is already correct
51  const QMetaType::Type type = static_cast<QMetaType::Type>(dataCVariant.type());
52 
53  if (type == QMetaType::QPixmap) { return dataCVariant; }
54  if (type == QMetaType::QIcon) { return dataCVariant; }
55 
56  // convert to pixmap
57  if (type == QMetaType::QImage)
58  {
59  const QImage img = dataCVariant.value<QImage>();
60  return CVariant::from(QPixmap::fromImage(img));
61  }
62 
63  // Our CIcon class
64  if (dataCVariant.canConvert<CIcon>())
65  {
66  const CIcon i = dataCVariant.value<CIcon>();
67  return CVariant::from(i.toPixmap());
68  }
69 
70  // nope
71  return CVariant::from(QPixmap());
72  }
73 
74  CVariant CDefaultFormatter::alignmentRole() const
75  {
76  if (this->hasAlignment()) { return CVariant::from(m_alignment); }
77  return CVariant::from(alignDefault()); // default
78  }
79 
80  CVariant CDefaultFormatter::checkStateRole(const CVariant &value) const
81  {
82  bool b = value.toBool();
83  Qt::CheckState cs = b ? Qt::Checked : Qt::Unchecked;
84  return CVariant::fromValue(static_cast<int>(cs));
85  }
86 
87  bool CDefaultFormatter::supportsRole(int role) const
88  {
89  // generally supported?
90  if (role == Qt::TextAlignmentRole || role == Qt::UserRole) { return true; }
91 
92  // specific?
93  return m_supportedRoles.contains(role);
94  }
95 
96  CVariant CDefaultFormatter::data(int role, const CVariant &inputData) const
97  {
98  if (!this->supportsRole(role)) { return CVariant(); }
99  const Qt::ItemDataRole roleEnum = static_cast<Qt::ItemDataRole>(role);
100 
101  // always supported
102  if (roleEnum == Qt::TextAlignmentRole) return { alignmentRole() };
103 
104  // check
105  if (role == Qt::UserRole) { return CDefaultFormatter::displayRole(inputData); } // just as data provider
106  switch (roleEnum)
107  {
108  case Qt::DisplayRole: return displayRole(inputData); // formatted to standard types or string
109  case Qt::EditRole: return editRole(inputData); // formatted to standard types or string
110  case Qt::ToolTipRole: return tooltipRole(inputData); // formatted to string
111  case Qt::DecorationRole: return decorationRole(inputData); // formatted as pixmap, icon, or color
112  case Qt::CheckStateRole: return checkStateRole(inputData); // as Qt check state
113  default: break;
114  }
115  return CVariant();
116  }
117 
118  int CDefaultFormatter::alignDefault() { return alignLeftVCenter(); }
119 
120  CVariant CDefaultFormatter::keepStandardTypesConvertToStringOtherwise(const CVariant &inputData) const
121  {
122  if (static_cast<QMetaType::Type>(inputData.type()) == QMetaType::QString) { return inputData; }
123  if (static_cast<QMetaType::Type>(inputData.type()) == QMetaType::Bool) { return inputData; }
124  if (static_cast<QMetaType::Type>(inputData.type()) == QMetaType::Int) { return inputData; }
125  return inputData.toQString(m_useI18n);
126  }
127 
128  const CVariant &CDefaultFormatter::emptyStringVariant()
129  {
130  static const CVariant e = CVariant::from(QString());
131  return e;
132  }
133 
134  const CVariant &CDefaultFormatter::emptyPixmapVariant()
135  {
136  static const CVariant e = CVariant::from(QPixmap());
137  return e;
138  }
139 
140  CVariant CPixmapFormatter::displayRole(const CVariant &dataCVariant) const
141  {
142  Q_UNUSED(dataCVariant);
143  Q_ASSERT_X(false, "CPixmapFormatter", "this role should be disabled with pixmaps");
144  return {};
145  }
146 
147  CVariant CPixmapFormatter::tooltipRole(const CVariant &dataCVariant) const
148  {
149  if (dataCVariant.isNull()) { return {}; }
150  if (dataCVariant.canConvert<CIcon>())
151  {
152  const CIcon icon = dataCVariant.value<CIcon>();
153  return icon.getDescriptiveText();
154  }
155  return emptyStringVariant();
156  }
157 
158  CVariant CPixmapFormatter::decorationRole(const CVariant &dataCVariant) const
159  {
160  if (dataCVariant.isNull()) { return {}; }
161  if (m_maxWidth < 0 && m_maxHeight < 0) { return CDefaultFormatter::decorationRole(dataCVariant); }
162 
163  QPixmap pm;
164  if (dataCVariant.canConvert<CIcon>())
165  {
166  const CIcon icon = dataCVariant.value<CIcon>();
167  pm = icon.toPixmap();
168  }
169 
170  if (pm.isNull()) { return {}; }
171  const int pmw = pm.width();
172  const int pmh = pm.height();
173 
174  if (m_maxHeight >= 0 && m_maxHeight < pmh) { return CVariant::fromValue(pm.scaledToHeight(m_maxHeight)); }
175 
176  if (m_maxWidth >= 0 && m_maxWidth < pmw) { return CVariant::fromValue(pm.scaledToWidth(m_maxWidth)); }
177 
178  return CVariant::fromValue(pm);
179  }
180 
181  CVariant CValueObjectFormatter::displayRole(const CVariant &valueObject) const
182  {
183  return CVariant(valueObject.toQString(m_useI18n));
184  }
185 
186  CVariant CValueObjectFormatter::decorationRole(const CVariant &valueObject) const
187  {
188  return CVariant(valueObject.toPixmap());
189  }
190 
191  CDateTimeFormatter::CDateTimeFormatter(const QString &formatString, int alignment, bool i18n)
192  : CDefaultFormatter(alignment, i18n, { Qt::DisplayRole }), m_formatString(formatString)
193  {
194  // void
195  }
196 
198  {
199  if (dateTime.isNull()) return {};
200  if (static_cast<QMetaType::Type>(dateTime.type()) == QMetaType::QDateTime)
201  {
202  const QDateTime dt = dateTime.value<QDateTime>();
203  return dt.toString(m_formatString);
204  }
205  else if (static_cast<QMetaType::Type>(dateTime.type()) == QMetaType::QDate)
206  {
207  const QDate d = dateTime.value<QDate>();
208  return d.toString(m_formatString);
209  }
210  else if (static_cast<QMetaType::Type>(dateTime.type()) == QMetaType::QTime)
211  {
212  const QTime t = dateTime.value<QTime>();
213  return t.toString(m_formatString);
214  }
215  else if (dateTime.isIntegral())
216  {
217  const QDateTime t = QDateTime::fromMSecsSinceEpoch(dateTime.value<qint64>());
218  return t.toString(m_formatString);
219  }
220  else
221  {
222  Q_ASSERT_X(false, "formatQVariant", "No QDate, QTime or QDateTime");
223  return {};
224  }
225  }
226 
228  {
229  if (dataCVariant.canConvert<CLength>())
230  {
231  // special treatment for some cases
232  const CLength l = dataCVariant.value<CLength>();
233  const bool valid = !l.isNull() && (l.isPositiveWithEpsilonConsidered() || l.isZeroEpsilonConsidered());
234  return valid ? CPhysiqalQuantiyFormatter::displayRole(dataCVariant) : emptyStringVariant();
235  }
236  else
237  {
238  Q_ASSERT_X(false, "CAirspaceDistanceFormatter::formatQVariant", "No CLength class");
239  return emptyStringVariant();
240  }
241  }
242 
244  {
245  if (dataCVariant.canConvert<CFrequency>())
246  {
247  // special treatment for some cases
248  const CFrequency f = dataCVariant.value<CFrequency>();
249  if (CComSystem::isValidComFrequency(f)) { return CPhysiqalQuantiyFormatter::displayRole(dataCVariant); }
250  return emptyStringVariant();
251  }
252  else
253  {
254  Q_ASSERT_X(false, "CAviationComFrequencyFormatter::formatQVariant", "No CFrequency class");
255  return emptyStringVariant();
256  }
257  }
258 
260  {
261  // special treatment for some cases
262  const CSpeed s = dataCVariant.value<CSpeed>();
264  {
265  return CPhysiqalQuantiyFormatter::displayRole(dataCVariant);
266  }
267  return emptyStringVariant();
268  }
269 
271  {
272  if (dataCVariant.canConvert<QString>()) { return dataCVariant; }
273  if (!dataCVariant.isValid())
274  {
275  static const CVariant iv("invalid");
276  return iv;
277  }
278  return CVariant::from(QStringLiteral("Invalid type: '%1'").arg(dataCVariant.typeName()));
279  }
280 
281  Qt::ItemFlags CDelegateFormatter::flags(Qt::ItemFlags flags, bool editable) const
282  {
283  flags = CDefaultFormatter::flags(flags, editable);
284  return flags;
285  }
286 
288  {
289  if (dataCVariant.canConvert<bool>())
290  {
291  const bool v = dataCVariant.toBool();
293  }
294  Q_ASSERT_X(false, "CBoolTextFormatter", "no boolean value");
295  return CVariant();
296  }
297 
298  Qt::ItemFlags CBoolTextFormatter::flags(Qt::ItemFlags flags, bool editable) const
299  {
300  return CDefaultFormatter::flags(flags, editable);
301  }
302 
303  CBoolLedFormatter::CBoolLedFormatter(int alignment) : CBoolLedFormatter("on", "off", alignment) {}
304 
305  CBoolLedFormatter::CBoolLedFormatter(const QString &onName, const QString &offName, int alignment)
306  : CBoolTextFormatter(alignment, onName, offName, rolesDecorationAndToolTip())
307  {
308  // one time pixmap creation
309  QScopedPointer<CLedWidget> led(createLedDefault());
310  led->setOn(true);
311  m_pixmapOnLedVariant = CVariant::fromValue(led->asPixmap());
312  led->setOn(false);
313  m_pixmapOffLedVariant = CVariant::fromValue(led->asPixmap());
314  }
315 
317  {
318  Q_UNUSED(dataCVariant);
319  Q_ASSERT_X(false, Q_FUNC_INFO, "this role should be disabled with led boolean");
320  return CVariant();
321  }
322 
324  {
325  if (dataCVariant.canConvert<bool>())
326  {
327  const bool v = dataCVariant.toBool();
329  }
330  Q_ASSERT_X(false, "CBoolLedFormatter", "no boolean value");
331  return CVariant();
332  }
333 
335  : CBoolIconFormatter(CIcons::StandardIconTick16, CIcons::StandardIconCross16, "on", "off", alignment)
336  {}
337 
338  CBoolIconFormatter::CBoolIconFormatter(const QString &onName, const QString &offName, int alignment)
339  : CBoolIconFormatter(CIcons::StandardIconTick16, CIcons::StandardIconCross16, onName, offName, alignment)
340  {}
341 
343  const QString &offName, int alignment)
344  : CBoolIconFormatter(CIcon::iconByIndex(onIcon), CIcon::iconByIndex(offIcon), onName, offName, alignment)
345  {}
346 
347  CBoolIconFormatter::CBoolIconFormatter(const CIcon &onIcon, const CIcon &offIcon, const QString &onName,
348  const QString &offName, int alignment)
349  : CBoolTextFormatter(alignment, onName, offName, rolesDecorationAndToolTip()),
350  m_iconOnVariant(CVariant::fromValue(onIcon.toPixmap())),
351  m_iconOffVariant(CVariant::fromValue(offIcon.toPixmap()))
352  {}
353 
355  {
356  Q_UNUSED(dataCVariant)
357  Q_ASSERT_X(false, "CBoolIconFormatter", "this role should be disabled with icon boolean");
358  return CVariant();
359  }
360 
362  {
363  if (dataCVariant.canConvert<bool>())
364  {
365  const bool v = dataCVariant.toBool();
366  return v ? m_iconOnVariant : m_iconOffVariant;
367  }
368  Q_ASSERT_X(false, "CBoolIconFormatter", "no boolean value");
369  return CVariant();
370  }
371 
373  {
374  return CBoolTextFormatter::displayRole(dataCVariant);
375  }
376 
378  {
379  CAltitude alt(altitude.to<CAltitude>());
380  if (m_flightLevel) { alt.toFlightLevel(); }
381  else { alt.switchUnit(m_unit); }
382  return alt.toQString(m_useI18n);
383  }
384 
385  CColorFormatter::CColorFormatter(int alignment, bool i18n)
386  : CDefaultFormatter(alignment, i18n, rolesDecorationAndToolTip())
387  {}
388 
389  CVariant CColorFormatter::displayRole(const CVariant &dataCVariant) const
390  {
391  Q_UNUSED(dataCVariant)
392  Q_ASSERT_X(false, Q_FUNC_INFO, "this role should be disabled with RGB color");
393  return CVariant();
394  }
395 
397  {
398  const CRgbColor rgbColor(dataCVariant.to<CRgbColor>());
399  if (!rgbColor.isValid()) { return emptyPixmapVariant(); }
400  return CVariant::fromValue(rgbColor.toPixmap());
401  }
402 
403  CVariant CColorFormatter::tooltipRole(const CVariant &dataCVariant) const
404  {
405  static const CVariant empty(CVariant::fromValue(QPixmap()));
406  const CRgbColor rgbColor(dataCVariant.to<CRgbColor>());
407  if (!rgbColor.isValid()) { return emptyStringVariant(); }
408  return rgbColor.hex(true);
409  }
410 
411  CVariant CIntegerFormatter::displayRole(const CVariant &expectedInteger) const
412  {
413  bool ok = false;
414  switch (expectedInteger.type())
415  {
416  case QMetaType::LongLong:
417  {
418  const qlonglong ll = expectedInteger.toLongLong(&ok);
419  if (ok) { return QString::number(ll); }
420  break;
421  }
422  case QMetaType::ULongLong:
423  {
424  const qulonglong ll = expectedInteger.toULongLong(&ok);
425  if (ok) { return QString::number(ll); }
426  break;
427  }
428  default: break;
429  }
430 
431  const int i = expectedInteger.toInt(&ok);
432  if (ok) { return QString::number(i); }
433  return CVariant();
434  }
435 
436  CVariant CEmptyFormatter::displayRole(const CVariant &dataCVariant) const
437  {
438  Q_UNUSED(dataCVariant);
439  static const CVariant empty("");
440  return empty;
441  }
442 
444  {
445  Q_UNUSED(dataCVariant);
446  static const CVariant masked("******");
447  return masked;
448  }
449 
450 } // namespace swift::gui::models
virtual swift::misc::CVariant displayRole(const swift::misc::CVariant &dataCVariant) const
Value provided as CVariant, formatter converts to standard types or string. Used with Qt::DisplayRole...
virtual swift::misc::CVariant displayRole(const swift::misc::CVariant &altitude) const
Value provided as CVariant, formatter converts to standard types or string. Used with Qt::DisplayRole...
virtual swift::misc::CVariant tooltipRole(const swift::misc::CVariant &dataCVariant) const
Value provided as CVariant, formatter converts to QString. Used with Qt::ToolTipRole displaying a tex...
virtual swift::misc::CVariant decorationRole(const swift::misc::CVariant &dataCVariant) const
Display the icon.
CBoolIconFormatter(int alignment=alignCentered())
Constructor.
virtual swift::misc::CVariant displayRole(const swift::misc::CVariant &dataCVariant) const
Value provided as CVariant, formatter converts to standard types or string. Used with Qt::DisplayRole...
const swift::misc::CVariant m_iconOffVariant
Used when off.
const swift::misc::CVariant m_iconOnVariant
Used when on.
swift::misc::CVariant m_pixmapOnLedVariant
Pixmap used when on.
CBoolLedFormatter(int alignment=alignDefault())
Constructor.
virtual swift::misc::CVariant decorationRole(const swift::misc::CVariant &dataCVariant) const
Display the LED.
virtual swift::misc::CVariant displayRole(const swift::misc::CVariant &dataCVariant) const
Value provided as CVariant, formatter converts to standard types or string. Used with Qt::DisplayRole...
swift::misc::CVariant m_pixmapOffLedVariant
Pixmap used when off.
const swift::misc::CVariant m_trueNameVariant
displayed when true
const swift::misc::CVariant m_falseNameVariant
displayed when false
virtual Qt::ItemFlags flags(Qt::ItemFlags flags, bool editable) const
Flags.
virtual swift::misc::CVariant displayRole(const swift::misc::CVariant &dataCVariant) const
Value provided as CVariant, formatter converts to standard types or string. Used with Qt::DisplayRole...
CColorFormatter(int alignment=alignCentered(), bool i18n=true)
Constructor.
virtual swift::misc::CVariant displayRole(const swift::misc::CVariant &dataCVariant) const
Value provided as CVariant, formatter converts to standard types or string. Used with Qt::DisplayRole...
virtual swift::misc::CVariant decorationRole(const swift::misc::CVariant &dataCVariant) const
Display the icon.
virtual swift::misc::CVariant tooltipRole(const swift::misc::CVariant &dataCVariant) const
Value provided as CVariant, formatter converts to QString. Used with Qt::ToolTipRole displaying a tex...
virtual swift::misc::CVariant displayRole(const swift::misc::CVariant &dataCVariant) const
Value provided as CVariant, formatter converts to standard types or string. Used with Qt::DisplayRole...
virtual swift::misc::CVariant displayRole(const swift::misc::CVariant &dateTime) const
Value provided as CVariant, formatter converts to standard types or string. Used with Qt::DisplayRole...
Column formatter default implementation, also serving as interface.
virtual Qt::ItemFlags flags(Qt::ItemFlags flags, bool editable) const
Flags.
static const swift::misc::CVariant & emptyPixmapVariant()
Empty pixmap CVariant.
static const swift::misc::CVariant & emptyStringVariant()
Empty string CVariant.
virtual Qt::ItemFlags flags(Qt::ItemFlags flags, bool editable) const
Flags.
virtual swift::misc::CVariant displayRole(const swift::misc::CVariant &dataCVariant) const
Value provided as CVariant, formatter converts to standard types or string. Used with Qt::DisplayRole...
virtual swift::misc::CVariant displayRole(const swift::misc::CVariant &dataCVariant) const
Value provided as CVariant, formatter converts to standard types or string. Used with Qt::DisplayRole...
virtual swift::misc::CVariant displayRole(const swift::misc::CVariant &expectedInteger) const
Value provided as CVariant, formatter converts to standard types or string. Used with Qt::DisplayRole...
virtual swift::misc::CVariant displayRole(const swift::misc::CVariant &physicalQuantity) const
Value provided as CVariant, formatter converts to standard types or string. Used with Qt::DisplayRole...
virtual swift::misc::CVariant displayRole(const swift::misc::CVariant &dataCVariant) const
Value provided as CVariant, formatter converts to standard types or string. Used with Qt::DisplayRole...
virtual swift::misc::CVariant displayRole(const swift::misc::CVariant &dataCVariant) const
Value provided as CVariant, formatter converts to standard types or string. Used with Qt::DisplayRole...
Value object for icons. An icon is stored in the global icon repository and identified by its index....
Definition: icon.h:39
QPixmap toPixmap() const
Corresponding pixmap.
Definition: icon.cpp:34
const QString & getDescriptiveText() const
Constructor for generated icon.
Definition: icon.h:54
Standard icons.
Definition: icons.h:25
IconIndex
Index for each icon, allows to send them via DBus, efficiently store them, etc.
Definition: icons.h:32
QString hex(bool withHash=false) const
Hex value.
Definition: rgbcolor.cpp:100
QPixmap toPixmap() const
Icon as pixmap.
Definition: rgbcolor.cpp:30
bool isValid() const
Valid?
Definition: rgbcolor.cpp:140
Wrapper around QVariant which provides transparent access to CValueObject methods of the contained ob...
Definition: variant.h:66
T to() const
Synonym for value().
Definition: variant.h:176
static CVariant fromValue(T &&value)
Construct a variant from a value.
Definition: variant.h:139
T value() const
Return the value converted to the type T.
Definition: variant.h:169
bool isIntegral() const
True if this variant's type is an integral type.
bool isValid() const
True if this variant is valid.
Definition: variant.h:252
bool toBool() const
Convert this variant to a bool.
Definition: variant.h:222
qulonglong toULongLong(bool *ok=nullptr) const
Convert this variant to a unsigned longlong integer.
Definition: variant.h:231
const char * typeName() const
Return the typename of the value in this variant.
Definition: variant.h:258
QMetaType::Type type() const
Return the metatype ID of the value in this variant, or QMetaType::User if it is a user type.
Definition: variant.h:255
qlonglong toLongLong(bool *ok=nullptr) const
Convert this variant to a longlong integer.
Definition: variant.h:228
static CVariant from(T &&value)
Synonym for fromValue().
Definition: variant.h:147
int toInt(bool *ok=nullptr) const
Convert this variant to an integer.
Definition: variant.h:225
QPixmap toPixmap() const
Corresponding pixmap.
bool isNull() const
True if this variant is null.
Definition: variant.h:249
bool canConvert(int typeId) const
True if this variant can be converted to the type with the given metatype ID.
Altitude as used in aviation, can be AGL or MSL altitude.
Definition: altitude.h:52
bool toFlightLevel()
MSL to flightlevel.
Definition: altitude.cpp:105
CAltitude & switchUnit(const physical_quantities::CLengthUnit &newUnit)
Value in switched unit.
Definition: altitude.cpp:71
QString toQString(bool i18n=false) const
Cast as QString.
Definition: mixinstring.h:76
Physical unit length (length)
Definition: length.h:18
bool isPositiveWithEpsilonConsidered() const
Value >= 0 epsilon considered.
bool isZeroEpsilonConsidered() const
Quantity value <= epsilon.
Models to be used with views, mainly QTableView.
Free functions in swift::misc.