QGIS API Documentation 4.3.0-Master (149067ad0b9)
Loading...
Searching...
No Matches
qgsdatetimewithtimezonewidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsdatetimewithtimezonewidget.cpp
3 --------------------------------------
4 Date : October 2026
5 Copyright : (C) 2026 Nyall Dawson
6 Email : nyall.dawson@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
17
18#include <mutex>
19
20#include "qgsapplication.h"
21#include "qgsdatetimeedit.h"
22#include "qgsfilterlineedit.h"
23#include "qgsgui.h"
24#include "qgspanelwidget.h"
25
26#include <QComboBox>
27#include <QDialogButtonBox>
28#include <QHBoxLayout>
29#include <QListView>
30#include <QString>
31#include <QTimeZone>
32#include <QToolButton>
33
34#include "moc_qgsdatetimewithtimezonewidget.cpp"
35
36using namespace Qt::StringLiterals;
37
38//
39// QgsTimeZoneItemModel
40//
41
42std::vector< QgsTimeZoneItemModel::TimeZoneItem > QgsTimeZoneItemModel::sItems;
43
45 : QAbstractItemModel( parent )
46{
47 static std::once_flag initialized;
48 std::call_once( initialized, [] {
49 const QDateTime now = QDateTime::currentDateTime();
50 const QList<QByteArray> zones = QTimeZone::availableTimeZoneIds();
51 sItems.reserve( zones.size() );
52 for ( const QByteArray &zoneId : std::as_const( zones ) )
53 {
54 const QTimeZone timeZone( zoneId );
55 if ( !timeZone.isValid() )
56 continue;
57
58 const int offset = timeZone.offsetFromUtc( now );
59 const QString displayString = displayStringForTimeZone( timeZone );
60
61 TimeZoneItem item { zoneId, displayString, timeZone, offset };
62 sItems.emplace_back( item );
63 }
64 } );
65}
66
67int QgsTimeZoneItemModel::rowCount( const QModelIndex &parent ) const
68{
69 if ( parent.isValid() )
70 return 0;
71
72 return static_cast< int>( sItems.size() );
73}
74
75int QgsTimeZoneItemModel::columnCount( const QModelIndex & ) const
76{
77 return 1;
78}
79
80QVariant QgsTimeZoneItemModel::data( const QModelIndex &index, int role ) const
81{
82 if ( !index.isValid() )
83 return QVariant();
84
85 if ( index.row() < 0 || index.row() >= static_cast< int >( sItems.size() ) )
86 return QVariant();
87
88 const TimeZoneItem &item = sItems[index.row()];
89 switch ( role )
90 {
91 case Qt::DisplayRole:
92 case Qt::ToolTipRole:
93 return item.displayString;
94
95 case static_cast< int >( CustomRole::TimeZoneId ):
96 return item.id;
97
98 case static_cast< int >( CustomRole::TimeZone ):
99 return QVariant::fromValue( item.timeZone );
100
101 case static_cast< int >( CustomRole::UtcOffset ):
102 return item.utcOffset;
103
104 default:
105 break;
106 }
107
108 return QVariant();
109}
110
111QModelIndex QgsTimeZoneItemModel::index( int row, int column, const QModelIndex &parent ) const
112{
113 if ( column < 0 || column >= columnCount() )
114 {
115 return QModelIndex();
116 }
117
118 if ( !parent.isValid() )
119 {
120 return createIndex( row, column, nullptr );
121 }
122
123 return QModelIndex();
124}
125
126QModelIndex QgsTimeZoneItemModel::parent( const QModelIndex &index ) const
127{
128 Q_UNUSED( index )
129 return QModelIndex();
130}
131
132QModelIndex QgsTimeZoneItemModel::indexFromTimeZone( const QTimeZone &timeZone ) const
133{
134 if ( !timeZone.isValid() )
135 return QModelIndex();
136 const QString id = timeZone.id();
137 const QModelIndex startIndex = index( 0, 0 );
138 const QModelIndexList matches = match( startIndex, static_cast< int >( CustomRole::TimeZoneId ), id, 1 );
139 return matches.isEmpty() ? QModelIndex() : matches.at( 0 );
140}
141
142QString QgsTimeZoneItemModel::displayStringForTimeZone( const QTimeZone &timeZone, QTimeZone::NameType nameType )
143{
144 const QDateTime now = QDateTime::currentDateTime();
145 const int offset = timeZone.offsetFromUtc( now );
146
147 return u"%1: %2 (%3)"_s.arg( offsetToString( offset ), QString( timeZone.id() ), timeZone.displayName( now, nameType ) );
148}
149
150QString QgsTimeZoneItemModel::offsetToString( int seconds )
151{
152 const int offsetInMinutes = std::abs( seconds ) / 60;
153 const int hours = offsetInMinutes / 60;
154 const int minutes = offsetInMinutes % 60;
155 return tr( "UTC%1%2:%3" ).arg( seconds >= 0 ? '+' : '-' ).arg( hours, 2, 10, '0' ).arg( minutes, 2, 10, '0' );
156}
157
158//
159// QgsTimeZoneSortFilterModel
160//
161
163 : QSortFilterProxyModel( parent )
164 , mSourceModel( source )
165{
166 setSourceModel( mSourceModel );
167 setDynamicSortFilter( true );
168 sort( 0 );
169}
170
171QModelIndex QgsTimeZoneSortFilterModel::indexFromTimeZone( const QTimeZone &timeZone ) const
172{
173 return mapFromSource( mSourceModel->indexFromTimeZone( timeZone ) );
174}
175
177{
178 mFilterString = filter;
179 invalidateFilter();
180}
181
182bool QgsTimeZoneSortFilterModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
183{
184 const QString itemText = sourceModel()->data( sourceModel()->index( sourceRow, 0, sourceParent ) ).toString();
185
186 if ( !mFilterString.trimmed().isEmpty() )
187 {
188 if ( !itemText.contains( mFilterString, Qt::CaseInsensitive ) )
189 return false;
190 }
191
192 return true;
193}
194
195bool QgsTimeZoneSortFilterModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
196{
197 const int leftOffset = sourceModel()->data( left, static_cast< int >( QgsTimeZoneItemModel::CustomRole::UtcOffset ) ).toInt();
198 const int rightOffset = sourceModel()->data( right, static_cast< int >( QgsTimeZoneItemModel::CustomRole::UtcOffset ) ).toInt();
199 if ( leftOffset != rightOffset )
200 {
201 return leftOffset < rightOffset;
202 }
203
204 const QString leftText = sourceModel()->data( left, Qt::DisplayRole ).toString();
205 const QString rightText = sourceModel()->data( right, Qt::DisplayRole ).toString();
206 if ( leftText.isEmpty() )
207 return true;
208 if ( rightText.isEmpty() )
209 return false;
210
211 return QString::localeAwareCompare( leftText, rightText ) < 0;
212}
213
214//
215// QgsTimeZoneWidget
216//
217
219 : QgsPanelWidget( parent )
220{
221 mModel = new QgsTimeZoneItemModel( this );
222 mProxyModel = new QgsTimeZoneSortFilterModel( mModel, this );
223
224 mFilterEdit = new QgsFilterLineEdit();
225 mFilterEdit->setShowClearButton( true );
226 mFilterEdit->setShowSearchIcon( true );
227 mFilterEdit->setPlaceholderText( "Search…" );
228
229 mListView = new QListView();
230 mListView->setModel( mProxyModel );
231 mListView->setUniformItemSizes( true );
232
233 auto layout = new QVBoxLayout();
234 layout->setContentsMargins( 0, 0, 0, 0 );
235 layout->addWidget( mFilterEdit );
236 layout->addWidget( mListView, 1 );
237
238 setLayout( layout );
239
240 connect( mFilterEdit, &QgsFilterLineEdit::textEdited, mProxyModel, &QgsTimeZoneSortFilterModel::setFilterString );
241 connect( mListView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [this] { emit timeZoneChanged( timeZone() ); } );
242
243 connect( mListView, &QListView::doubleClicked, this, &QgsTimeZoneWidget::itemDoubleClicked );
244}
245
247{
248 const QModelIndexList list = mListView->selectionModel()->selectedIndexes().toList();
249 if ( list.isEmpty() )
250 return QTimeZone();
251
252 const QModelIndex currentIndex = list.at( 0 );
253 if ( !currentIndex.isValid() )
254 return QTimeZone();
255
256 return mProxyModel->data( currentIndex, static_cast< int>( QgsTimeZoneItemModel::CustomRole::TimeZone ) ).value< QTimeZone >();
257}
258
259void QgsTimeZoneWidget::setTimeZone( const QTimeZone &zone )
260{
261 const QModelIndex index = mProxyModel->indexFromTimeZone( zone );
262 if ( !index.isValid() )
263 {
264 mListView->clearSelection();
265 }
266 else
267 {
268 mListView->selectionModel()->select( index, QItemSelectionModel::SelectionFlag::ClearAndSelect );
269 mListView->scrollTo( index );
270 }
271}
272
273void QgsTimeZoneWidget::itemDoubleClicked( const QModelIndex &index )
274{
275 emit timeZoneDoubleClicked( mProxyModel->data( index, static_cast< int>( QgsTimeZoneItemModel::CustomRole::TimeZone ) ).value< QTimeZone >() );
276}
277
279
280//
281// StandardTimeZoneModel
282//
283
284StandardTimeZoneModel::StandardTimeZoneModel( QObject *parent )
285 : QAbstractItemModel( parent )
286{}
287
288QVariant StandardTimeZoneModel::data( const QModelIndex &index, int role ) const
289{
290 if ( !index.isValid() )
291 return QVariant();
292
293 if ( index.row() < 0 || index.row() >= rowCount() )
294 return QVariant();
295
296 const QgsTimeZoneComboBox::StandardItem item = itemForIndex( index );
297 switch ( role )
298 {
299 case Qt::DisplayRole:
300 case Qt::ToolTipRole:
301 switch ( item )
302 {
304 return tr( "Not set" );
305
307 return QgsTimeZoneItemModel::displayStringForTimeZone( mCurrentTimeZone, QTimeZone::NameType::ShortName );
308
310 return tr( "System: %1" ).arg( QgsTimeZoneItemModel::displayStringForTimeZone( QTimeZone::systemTimeZone(), QTimeZone::NameType::ShortName ) );
311 }
312 break;
313
314 case static_cast< int >( StandardTimeZoneModel::CustomRole::TimeZone ):
315 switch ( item )
316 {
318 return QVariant::fromValue( QTimeZone() );
319
321 return QVariant::fromValue( mCurrentTimeZone );
322
324 return QVariant::fromValue( QTimeZone::systemTimeZone() );
325 }
326 break;
327
328 default:
329 break;
330 }
331
332 return QVariant();
333}
334
335int StandardTimeZoneModel::rowCount( const QModelIndex &parent ) const
336{
337 if ( parent.isValid() )
338 return 0;
339
340 return 3;
341}
342
343int StandardTimeZoneModel::columnCount( const QModelIndex & ) const
344{
345 return 1;
346}
347
348QModelIndex StandardTimeZoneModel::index( int row, int column, const QModelIndex &parent ) const
349{
350 if ( row < 0 || row >= rowCount() || column != 0 || parent.isValid() )
351 return QModelIndex();
352
353 return createIndex( row, column );
354}
355
356QModelIndex StandardTimeZoneModel::parent( const QModelIndex & ) const
357{
358 return QModelIndex();
359}
360
361QgsTimeZoneComboBox::StandardItem StandardTimeZoneModel::itemForIndex( const QModelIndex &index ) const
362{
363 switch ( index.row() )
364 {
365 case 0:
367
368 case 1:
370
371 case 2:
373
374 default:
376 }
377}
378
379QModelIndex StandardTimeZoneModel::indexForItem( QgsTimeZoneComboBox::StandardItem item ) const
380{
381 switch ( item )
382 {
384 return index( 0, 0, QModelIndex() );
386 return index( 1, 0, QModelIndex() );
388 return index( 2, 0, QModelIndex() );
389 }
391}
392
393void StandardTimeZoneModel::setCurrentTimeZone( const QTimeZone &timeZone )
394{
395 mCurrentTimeZone = timeZone;
396 emit dataChanged( index( 1, 0, QModelIndex() ), index( 1, 0, QModelIndex() ) );
397}
398
399//
400// StandardTimeZoneProxyModel
401//
402StandardTimeZoneProxyModel::StandardTimeZoneProxyModel( QObject *parent )
403 : QSortFilterProxyModel( parent )
404{
405 mModel = new StandardTimeZoneModel( this );
407
408 setSourceModel( mModel );
409 setDynamicSortFilter( true );
410}
411
412void StandardTimeZoneProxyModel::setDisplayedItems( QgsTimeZoneComboBox::StandardItems items )
413{
414 mItems = items;
415 invalidateFilter();
416}
417
418void StandardTimeZoneProxyModel::setCurrentTimeZone( const QTimeZone &timeZone )
419{
420 mModel->setCurrentTimeZone( timeZone );
421 mItems.setFlag( QgsTimeZoneComboBox::StandardItem::Current, timeZone.isValid() );
422 invalidateFilter();
423}
424
425QModelIndex StandardTimeZoneProxyModel::indexForItem( QgsTimeZoneComboBox::StandardItem item ) const
426{
427 return mapFromSource( mModel->indexForItem( item ) );
428}
429
430bool StandardTimeZoneProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
431{
432 const QgsTimeZoneComboBox::StandardItem item = mModel->itemForIndex( mModel->index( sourceRow, 0, sourceParent ) );
433 return mItems.testFlag( item );
434}
435
436
438
439//
440// QgsTimeZoneComboBox
441//
442
444 : QWidget( parent )
445 , mDialogTitle( tr( "Time Zone Selector" ) )
446{
447 mComboBox = new QComboBox();
448 mTimeZoneModel = new StandardTimeZoneProxyModel( this );
449 mComboBox->setModel( mTimeZoneModel );
450
451 QHBoxLayout *layout = new QHBoxLayout();
452 layout->setContentsMargins( 0, 0, 0, 0 );
453
454 layout->addWidget( mComboBox, 1 );
455
456 mButton = new QToolButton( this );
457 mButton->setIcon( QgsApplication::getThemeIcon( u"mActionSetTimeZone.svg"_s ) );
458 mButton->setToolTip( tr( "Select Time Zone" ) );
459 layout->addWidget( mButton );
460
461 setFocusPolicy( Qt::StrongFocus );
462 setFocusProxy( mButton );
463
464 setLayout( layout );
465
466 connect( mComboBox, qOverload< int >( &QComboBox::currentIndexChanged ), this, [this] {
467 if ( !mBlockSignals )
468 {
469 emit timeZoneChanged( timeZone() );
470 }
471 } );
472
473 connect( mButton, &QToolButton::clicked, this, &QgsTimeZoneComboBox::selectTimeZone );
474}
475
477{
478 return mTimeZoneModel->data( mTimeZoneModel->index( mComboBox->currentIndex(), 0 ), static_cast< int >( StandardTimeZoneModel::CustomRole::TimeZone ) ).value< QTimeZone >();
479}
480
481void QgsTimeZoneComboBox::setDialogTitle( const QString &title )
482{
483 mDialogTitle = title;
484}
485
487{
488 return mDialogTitle;
489}
490
491void QgsTimeZoneComboBox::setTimeZone( const QTimeZone &zone )
492{
493 const QTimeZone oldTimeZone = timeZone();
494 mBlockSignals++;
495 mTimeZoneModel->setCurrentTimeZone( zone );
496 if ( zone.isValid() )
497 {
498 mComboBox->setCurrentIndex( mTimeZoneModel->indexForItem( QgsTimeZoneComboBox::StandardItem::Current ).row() );
499 }
500 else
501 {
502 mComboBox->setCurrentIndex( mTimeZoneModel->indexForItem( QgsTimeZoneComboBox::StandardItem::Invalid ).row() );
503 }
504 mBlockSignals--;
505 if ( timeZone() != oldTimeZone )
506 {
507 emit timeZoneChanged( timeZone() );
508 }
509}
510
511void QgsTimeZoneComboBox::selectTimeZone()
512{
514
515 if ( panel && panel->dockMode() )
516 {
517 mActivePanel = new QgsTimeZoneWidget( this );
518 mActivePanel->setTimeZone( timeZone() );
519 mActivePanel->setPanelTitle( mDialogTitle );
520
521 connect( mActivePanel, &QgsTimeZoneWidget::timeZoneChanged, this, [this] {
522 if ( mIgnorePanelSignals )
523 return;
524
525 const QTimeZone timeZone = mActivePanel->timeZone();
526
527 mIgnorePanelSignals++;
529 mIgnorePanelSignals--;
530
532 } );
533 panel->openPanel( mActivePanel );
534 }
535 else
536 {
537 QgsTimeZoneDialog dlg( this, QgsGuiUtils::ModalDialogFlags );
538 dlg.setWindowTitle( mDialogTitle );
539 dlg.setTimeZone( timeZone() );
540 if ( dlg.exec() )
541 {
542 setTimeZone( dlg.timeZone() );
543 }
544 }
545}
546
547//
548// QgsTimeZoneDialog
549//
550
551QgsTimeZoneDialog::QgsTimeZoneDialog( QWidget *parent, Qt::WindowFlags fl )
552 : QDialog( parent, fl )
553{
554 QVBoxLayout *vlayout = new QVBoxLayout();
555
556 mWidget = new QgsTimeZoneWidget();
557 vlayout->addWidget( mWidget, 1 );
558
559 mButtonBox = new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Ok );
560 connect( mButtonBox, &QDialogButtonBox::accepted, this, &QgsTimeZoneDialog::accept );
561 connect( mButtonBox, &QDialogButtonBox::rejected, this, &QgsTimeZoneDialog::reject );
562
563 vlayout->addWidget( mButtonBox );
564
565 setLayout( vlayout );
566
568
569 //apply selected time zone upon double-click on item
570 connect( mWidget, &QgsTimeZoneWidget::timeZoneDoubleClicked, this, &QgsTimeZoneDialog::accept );
571}
572
574{
575 return mWidget->timeZone();
576}
577
578void QgsTimeZoneDialog::setTimeZone( const QTimeZone &zone )
579{
580 mWidget->setTimeZone( zone );
581}
582
583//
584// QgsDateTimeWithTimeZoneWidget
585//
586
588 : QWidget( parent )
589{
590 auto layout = new QHBoxLayout();
591 layout->setContentsMargins( 0, 0, 0, 0 );
592 mDateTimeEdit = new QgsDateTimeEdit();
593 layout->addWidget( mDateTimeEdit, 1 );
594 mTimeZoneCombo = new QgsTimeZoneComboBox();
595 layout->addWidget( mTimeZoneCombo, 2 );
596 setLayout( layout );
597
598 connect( mTimeZoneCombo, &QgsTimeZoneComboBox::timeZoneChanged, this, [this] {
599 if ( mBlockSignals )
600 return;
601
602 emit dateTimeChanged( dateTime() );
603 } );
604
605 connect( mDateTimeEdit, &QgsDateTimeEdit::dateTimeChanged, this, [this] {
606 if ( mBlockSignals )
607 return;
608
609 emit dateTimeChanged( dateTime() );
610 } );
611}
612
617
622
624{
625 mTimeZoneCombo->setDialogTitle( title );
626}
627
629{
630 return mTimeZoneCombo->dialogTitle();
631}
632
634{
635 QDateTime res = mDateTimeEdit->dateTime();
636 res.setTimeZone( mTimeZoneCombo->timeZone() );
637 return res;
638}
639
641{
642 const QDateTime current = QgsDateTimeWithTimeZoneWidget::dateTime();
643 mBlockSignals++;
644 mDateTimeEdit->setDateTime( dateTime );
645 mTimeZoneCombo->setTimeZone( dateTime.timeZone() );
646 mBlockSignals--;
647 if ( current != dateTime )
648 {
650 }
651}
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
A QDateTimeEdit with the capability of setting/reading null date/times.
QgsDateTimeEdit * dateTimeEdit()
Returns the date time edit portion of the widget.
QgsDateTimeWithTimeZoneWidget(QWidget *parent=nullptr)
Constructor for QgsDateTimeWithTimeZoneWidget, with the specified parent widget.
void setDateTime(const QDateTime &dateTime)
Sets the date time to show in the widget.
QgsTimeZoneComboBox * timeZoneComboBox()
Returns the time zone combo box portion of the widget.
void dateTimeChanged(const QDateTime &dateTime)
Emitted whenever the date time shown in the widget is changed.
void setDialogTitle(const QString &title)
Sets the title for the time zone selector dialog window.
QDateTime dateTime() const
Returns the date time shown in the widget, with corresponding time zone set.
QString dialogTitle() const
Returns the title for the time zone selector dialog window.
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
Definition qgsgui.cpp:225
Base class for any widget that can be shown as an inline panel.
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
bool dockMode() const
Returns the dock mode state.
QgsPanelWidget(QWidget *parent=nullptr)
Base class for any widget that can be shown as an inline panel.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget.
A combo box widget for selection of available time zones.
void setTimeZone(const QTimeZone &zone)
Sets the current time zone to select in the widget.
QString dialogTitle() const
Returns the title for the time zone selector dialog window.
void timeZoneChanged(const QTimeZone &zone)
Emitted when the selected time zone is changed.
QFlags< StandardItem > StandardItems
Standard time zone options.
QgsTimeZoneComboBox(QWidget *parent=nullptr)
Constructor for QgsTimeZoneComboBox, with the specified parent widget.
QTimeZone timeZone() const
Returns the selected time zone.
void setDialogTitle(const QString &title)
Sets the title for the time zone selector dialog window.
StandardItem
Standard time zone options.
QTimeZone timeZone() const
Returns the selected time zone.
QgsTimeZoneDialog(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)
Constructor for QgsTimeZoneDialog.
void setTimeZone(const QTimeZone &zone)
Sets the current time zone to select in the dialog.
A custom model for display of available time zones.
QVariant data(const QModelIndex &index, int role) const override
static QString displayStringForTimeZone(const QTimeZone &timeZone, QTimeZone::NameType nameType=QTimeZone::NameType::DefaultName)
Returns a friendly display string for a time zone.
QModelIndex indexFromTimeZone(const QTimeZone &timeZone) const
Returns the model index corresponding to a time zone.
int columnCount(const QModelIndex &parent=QModelIndex()) const override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QgsTimeZoneItemModel(QObject *parent=nullptr)
Constructor for a QgsTimeZoneItemModel with the specified parent object.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QModelIndex parent(const QModelIndex &index) const override
A sort filter model for display of available time zones.
QgsTimeZoneSortFilterModel(QgsTimeZoneItemModel *source, QObject *parent=nullptr)
Constructor for a QgsTimeZoneSortFilterModel with the specified parent object and source model.
void setFilterString(const QString &filter)
Sets a filter string, such that only time zones with names containing the specified string will be sh...
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
QModelIndex indexFromTimeZone(const QTimeZone &timeZone) const
Returns the proxy model index corresponding to a time zone.
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
A widget for selection of available time zones.
QgsTimeZoneWidget(QWidget *parent=nullptr)
Constructor for QgsTimeZoneWidget, with the specified parent widget.
void timeZoneDoubleClicked(const QTimeZone &zone)
Emitted when a time zone is double-clicked in the widget.
void setTimeZone(const QTimeZone &zone)
Sets the current time zone to select in the widget.
QTimeZone timeZone() const
Returns the selected time zone.
void timeZoneChanged(const QTimeZone &zone)
Emitted when the selected time zone is changed.
#define BUILTIN_UNREACHABLE
Definition qgis.h:8397