QGIS API Documentation  3.2.0-Bonn (bc43194)
qgsdatetimeedit.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsdatetimeedit.cpp
3  --------------------------------------
4  Date : 08.2014
5  Copyright : (C) 2014 Denis Rouzaud
6  Email : [email protected]
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 <QAction>
17 #include <QCalendarWidget>
18 #include <QLineEdit>
19 #include <QMouseEvent>
20 #include <QStyle>
21 #include <QStyleOptionSpinBox>
22 
23 
24 #include "qgsdatetimeedit.h"
25 
26 #include "qgsapplication.h"
27 #include "qgslogger.h"
28 
29 
30 
32  : QDateTimeEdit( parent )
33 {
34  QIcon clearIcon = QgsApplication::getThemeIcon( "/mIconClearText.svg" );
35  mClearAction = new QAction( clearIcon, tr( "clear" ), this );
36  mClearAction->setCheckable( false );
37  lineEdit()->addAction( mClearAction, QLineEdit::TrailingPosition );
38  mClearAction->setVisible( mAllowNull );
39  connect( mClearAction, &QAction::triggered, this, &QgsDateTimeEdit::clear );
40 
41  connect( this, &QDateTimeEdit::dateTimeChanged, this, &QgsDateTimeEdit::changed );
42 
43  // enable calendar widget by default so it's already created
44  setCalendarPopup( true );
45 
46  setMinimumEditDateTime();
47 
48  // init with current time so mIsNull is properly initialized
49  QDateTimeEdit::setDateTime( QDateTime::currentDateTime() );
50 }
51 
53 {
54  mAllowNull = allowNull;
55  mClearAction->setVisible( mAllowNull && ( !mIsNull || mIsEmpty ) );
56 }
57 
58 
60 {
61  if ( mAllowNull )
62  {
63  displayNull();
64 
65  changed( QDateTime() );
66 
67  // emit signal of QDateTime::dateTimeChanged with an invalid date
68  // anyway, using parent's signal should be avoided
69  // If you consequently connect parent's dateTimeChanged signal
70  // and call dateTime() afterwards there is no warranty to
71  // have a proper NULL value handling
72  disconnect( this, &QDateTimeEdit::dateTimeChanged, this, &QgsDateTimeEdit::changed );
73  emit dateTimeChanged( QDateTime() );
74  connect( this, &QDateTimeEdit::dateTimeChanged, this, &QgsDateTimeEdit::changed );
75 
76  // otherwise, NULL is not displayed in the line edit
77  // this might not be the right way to do it
78  clearFocus();
79  }
80 }
81 
83 {
84  mClearAction->setVisible( mAllowNull );
85  mIsEmpty = true;
86 }
87 
88 void QgsDateTimeEdit::mousePressEvent( QMouseEvent *event )
89 {
90  // catch mouse press on the button (when the current value is null)
91  // in non-calendar mode: modifiy the date so it leads to showing current date (don't bother about time)
92  // in calendar mode: be sure NULL is displayed when needed and show page of current date in calendar widget
93 
94  bool updateCalendar = false;
95 
96  if ( mIsNull )
97  {
98  QStyle::SubControl control;
99  if ( calendarPopup() )
100  {
101  QStyleOptionComboBox optCombo;
102  optCombo.init( this );
103  optCombo.editable = true;
104  optCombo.subControls = QStyle::SC_All;
105  control = style()->hitTestComplexControl( QStyle::CC_ComboBox, &optCombo, event->pos(), this );
106 
107  if ( control == QStyle::SC_ComboBoxArrow && calendarWidget() )
108  {
109  mCurrentPressEvent = true;
110  // ensure the line edit still displays NULL
111  updateCalendar = true;
112  displayNull( updateCalendar );
113  mCurrentPressEvent = false;
114  }
115  }
116  else
117  {
118  QStyleOptionSpinBox opt;
119  this->initStyleOption( &opt );
120  control = style()->hitTestComplexControl( QStyle::CC_SpinBox, &opt, event->pos(), this );
121 
122  if ( control == QStyle::SC_SpinBoxDown || control == QStyle::SC_SpinBoxUp )
123  {
124  mCurrentPressEvent = true;
125  disconnect( this, &QDateTimeEdit::dateTimeChanged, this, &QgsDateTimeEdit::changed );
126  resetBeforeChange( control == QStyle::SC_SpinBoxDown ? -1 : 1 );
127  connect( this, &QDateTimeEdit::dateTimeChanged, this, &QgsDateTimeEdit::changed );
128  mCurrentPressEvent = false;
129  }
130  }
131  }
132 
133  QDateTimeEdit::mousePressEvent( event );
134 
135  if ( updateCalendar )
136  {
137  // set calendar page to current date to avoid going to minimal date page when value is null
138  calendarWidget()->setCurrentPage( QDate::currentDate().year(), QDate::currentDate().month() );
139  }
140 }
141 
142 void QgsDateTimeEdit::focusOutEvent( QFocusEvent *event )
143 {
144  if ( mAllowNull && mIsNull && !mCurrentPressEvent )
145  {
146  QAbstractSpinBox::focusOutEvent( event );
147  if ( lineEdit()->text() != QgsApplication::nullRepresentation() )
148  {
149  displayNull();
150  }
151  emit editingFinished();
152  }
153  else
154  {
155  QDateTimeEdit::focusOutEvent( event );
156  }
157 }
158 
159 void QgsDateTimeEdit::wheelEvent( QWheelEvent *event )
160 {
161  // dateTime might have been set to minimum in calendar mode
162  if ( mAllowNull && mIsNull )
163  {
164  resetBeforeChange( -event->delta() );
165  }
166  QDateTimeEdit::wheelEvent( event );
167 }
168 
169 void QgsDateTimeEdit::showEvent( QShowEvent *event )
170 {
171  QDateTimeEdit::showEvent( event );
172  if ( mAllowNull && mIsNull &&
173  lineEdit()->text() != QgsApplication::nullRepresentation() )
174  {
175  displayNull();
176  }
177 }
178 
179 void QgsDateTimeEdit::changed( const QDateTime &dateTime )
180 {
181  mIsEmpty = false;
182  bool isNull = dateTime.isNull();
183  if ( isNull != mIsNull )
184  {
185  mIsNull = isNull;
186  if ( mIsNull )
187  {
188  if ( mOriginalStyleSheet.isNull() )
189  {
190  mOriginalStyleSheet = lineEdit()->styleSheet();
191  }
192  lineEdit()->setStyleSheet( QStringLiteral( "QLineEdit { font-style: italic; color: grey; }" ) );
193  }
194  else
195  {
196  lineEdit()->setStyleSheet( mOriginalStyleSheet );
197  }
198  }
199 
200  mClearAction->setVisible( mAllowNull && !mIsNull );
201 
202  emit QgsDateTimeEdit::valueChanged( dateTime );
203 }
204 
205 void QgsDateTimeEdit::displayNull( bool updateCalendar )
206 {
207  disconnect( this, &QDateTimeEdit::dateTimeChanged, this, &QgsDateTimeEdit::changed );
208  if ( updateCalendar )
209  {
210  // set current time to minimum date time to avoid having
211  // a date selected in calendar widget
212  QDateTimeEdit::setDateTime( minimumDateTime() );
213  }
214  lineEdit()->setText( QgsApplication::nullRepresentation() );
215  connect( this, &QDateTimeEdit::dateTimeChanged, this, &QgsDateTimeEdit::changed );
216 }
217 
218 void QgsDateTimeEdit::resetBeforeChange( int delta )
219 {
220  QDateTime dt = QDateTime::currentDateTime();
221  switch ( currentSection() )
222  {
223  case QDateTimeEdit::DaySection:
224  dt = dt.addDays( delta );
225  break;
226  case QDateTimeEdit::MonthSection:
227  dt = dt.addMonths( delta );
228  break;
229  case QDateTimeEdit::YearSection:
230  dt = dt.addYears( delta );
231  break;
232  default:
233  break;
234  }
235  if ( dt < minimumDateTime() )
236  {
237  dt = minimumDateTime();
238  }
239  else if ( dt > maximumDateTime() )
240  {
241  dt = maximumDateTime();
242  }
243  QDateTimeEdit::setDateTime( dt );
244 }
245 
246 void QgsDateTimeEdit::setDateTime( const QDateTime &dateTime )
247 {
248  mIsEmpty = false;
249 
250  // set an undefined date
251  if ( !dateTime.isValid() || dateTime.isNull() )
252  {
253  clear();
254  }
255  else
256  {
257  QDateTimeEdit::setDateTime( dateTime );
258  changed( dateTime );
259  }
260 }
261 
262 QDateTime QgsDateTimeEdit::dateTime() const
263 {
264  if ( mAllowNull && mIsNull )
265  {
266  return QDateTime();
267  }
268  else
269  {
270  return QDateTimeEdit::dateTime();
271  }
272 }
bool allowNull() const
void showEvent(QShowEvent *event) override
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
void focusOutEvent(QFocusEvent *event) override
void wheelEvent(QWheelEvent *event) override
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
void valueChanged(const QDateTime &date)
signal emitted whenever the value changes.
void setEmpty()
Resets the widget to show no value (ie, an "unknown" state).
void setAllowNull(bool allowNull)
Determines if the widget allows setting null date/time.
QgsDateTimeEdit(QWidget *parent=nullptr)
Constructor for QgsDateTimeEdit.
void setDateTime(const QDateTime &dateTime)
setDateTime set the date time in the widget and handles null date times.
void clear() override
Set the current date as NULL.
QDateTime dateTime() const
dateTime returns the date time which can eventually be a null date/time
void mousePressEvent(QMouseEvent *event) override