QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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 <QCalendarWidget>
17 #include <QLineEdit>
18 #include <QMouseEvent>
19 #include <QSettings>
20 #include <QStyle>
21 #include <QStyleOptionSpinBox>
22 #include <QToolButton>
23 
24 #include "qgsdatetimeedit.h"
25 
26 #include "qgsapplication.h"
27 #include "qgslogger.h"
28 
30  : QDateTimeEdit( parent )
31  , mAllowNull( true )
32  , mIsNull( true )
33  , mIsEmpty( false )
34 {
35  mClearButton = new QToolButton( this );
36  mClearButton->setIcon( QgsApplication::getThemeIcon( "/mIconClear.svg" ) );
37  mClearButton->setCursor( Qt::ArrowCursor );
38  mClearButton->setStyleSheet( "position: absolute; border: none; padding: 0px;" );
39  mClearButton->hide();
40  connect( mClearButton, SIGNAL( clicked() ), this, SLOT( clear() ) );
41 
42  setStyleSheet( QString( ".QWidget, QLineEdit, QToolButton { padding-right: %1px; }" ).arg( mClearButton->sizeHint().width() + spinButtonWidth() + frameWidth() + 1 ) );
43 
44  QSize msz = minimumSizeHint();
45  setMinimumSize( qMax( msz.width(), mClearButton->sizeHint().height() + frameWidth() * 2 + 2 ),
46  qMax( msz.height(), mClearButton->sizeHint().height() + frameWidth() * 2 + 2 ) );
47 
48  connect( this, SIGNAL( dateTimeChanged( QDateTime ) ), this, SLOT( changed( QDateTime ) ) );
49 
50  // enable calendar widget by default so it's already created
51  setCalendarPopup( true );
52 
53  // init with current time so mIsNull is properly initialized
55 }
56 
58 {
59  mAllowNull = allowNull;
60 
61  mClearButton->setVisible( mAllowNull && ( !mIsNull || mIsEmpty ) );
62 }
63 
64 
66 {
67  if ( mAllowNull )
68  {
69  displayNull();
70 
71  changed( QDateTime() );
72 
73  // avoid slot double activation
74  disconnect( this, SIGNAL( dateTimeChanged() ), this, SLOT( changed() ) );
75  emit dateTimeChanged( QDateTime() );
76  connect( this, SIGNAL( dateTimeChanged() ), this, SLOT( changed() ) );
77  }
78 }
79 
81 {
82  mClearButton->setVisible( mAllowNull );
83  mIsEmpty = true;
84 }
85 
87 {
88  // catch mouse press on the button
89  // in non-calendar mode: modifiy the date so it leads to showing current date (don't bother about time)
90  // in calendar mode: be sure NULL is displayed when needed and show page of current date in calendar widget
91 
92  bool updateCalendar = false;
93 
94  if ( mIsNull )
95  {
97  this->initStyleOption( &opt );
98  const QRect buttonUpRect = style()->subControlRect( QStyle::CC_SpinBox, &opt, QStyle::SC_SpinBoxUp );
99  const QRect buttonDownRect = style()->subControlRect( QStyle::CC_SpinBox, &opt, QStyle::SC_SpinBoxDown );
100  if ( buttonUpRect.contains( event->pos() ) || buttonDownRect.contains( event->pos() ) )
101  {
102  if ( calendarPopup() && calendarWidget() )
103  {
104  // ensure the line edit still displays NULL
105  displayNull( true );
106  updateCalendar = true;
107  }
108  else
109  {
110  blockSignals( true );
111  resetBeforeChange( buttonUpRect.contains( event->pos() ) ? -1 : 1 );
112  blockSignals( false );
113  }
114  }
115  }
116 
118 
119  if ( updateCalendar )
120  {
121  // set calendar page to current date to avoid going to minimal date page when value is null
123  }
124 }
125 
127 {
128  if ( mAllowNull && mIsNull )
129  {
130  if ( lineEdit()->text() != QSettings().value( "qgis/nullValue", "NULL" ).toString() )
131  {
132  displayNull();
133  }
134  QWidget::focusOutEvent( event );
135  emit editingFinished();
136  }
137  else
138  {
140  }
141 }
142 
144 {
145  // dateTime might have been set to minimum in calendar mode
146  if ( mAllowNull && mIsNull )
147  {
148  resetBeforeChange( -event->delta() );
149  }
150  QDateTimeEdit::wheelEvent( event );
151 }
152 
154 {
155  QDateTimeEdit::showEvent( event );
156  if ( mAllowNull && mIsNull &&
157  lineEdit()->text() != QSettings().value( "qgis/nullValue", "NULL" ).toString() )
158  {
159  displayNull();
160  }
161 }
162 
163 void QgsDateTimeEdit::changed( const QDateTime &dateTime )
164 {
165  mIsEmpty = false;
166  bool isNull = dateTime.isNull();
167  if ( isNull != mIsNull )
168  {
169  mIsNull = isNull;
170  if ( mIsNull )
171  {
172  if ( mOriginalStyleSheet.isNull() )
173  {
174  mOriginalStyleSheet = lineEdit()->styleSheet();
175  }
176  lineEdit()->setStyleSheet( "font-style: italic; color: grey; }" );
177  }
178  else
179  {
180  lineEdit()->setStyleSheet( mOriginalStyleSheet );
181  }
182  }
183  mClearButton->setVisible( mAllowNull && !mIsNull );
184 }
185 
186 void QgsDateTimeEdit::displayNull( bool updateCalendar )
187 {
188  blockSignals( true );
189  if ( updateCalendar )
190  {
191  // set current time to minimum date time to avoid having
192  // a date selected in calendar widget
194  }
195  lineEdit()->setText( QSettings().value( "qgis/nullValue", "NULL" ).toString() );
196  blockSignals( false );
197 }
198 
199 void QgsDateTimeEdit::resetBeforeChange( int delta )
200 {
202  switch ( currentSection() )
203  {
204  case QDateTimeEdit::DaySection:
205  dt = dt.addDays( delta );
206  break;
207  case QDateTimeEdit::MonthSection:
208  dt = dt.addMonths( delta );
209  break;
210  case QDateTimeEdit::YearSection:
211  dt = dt.addYears( delta );
212  break;
213  default:
214  break;
215  }
216  if ( dt < minimumDateTime() )
217  {
218  dt = minimumDateTime();
219  }
220  else if ( dt > maximumDateTime() )
221  {
222  dt = maximumDateTime();
223  }
225 }
226 
227 int QgsDateTimeEdit::spinButtonWidth() const
228 {
229  return calendarPopup() ? 25 : 18;
230 }
231 
232 int QgsDateTimeEdit::frameWidth() const
233 {
234  return style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
235 }
236 
237 
238 
240 {
241  mIsEmpty = false;
242 
243  // set an undefined date
244  if ( !dateTime.isValid() || dateTime.isNull() )
245  {
246  clear();
247  }
248  else
249  {
250  QDateTimeEdit::setDateTime( dateTime );
251  changed( dateTime );
252  }
253 }
254 
256 {
257  if ( mAllowNull && mIsNull )
258  {
259  return QDateTime();
260  }
261  else
262  {
263  return QDateTimeEdit::dateTime();
264  }
265 }
266 
268 {
270 
271  QSize sz = mClearButton->sizeHint();
272 
273 
274  mClearButton->move( rect().right() - frameWidth() - spinButtonWidth() - sz.width(),
275  ( rect().bottom() + 1 - sz.height() ) / 2 );
276 }
void setStyleSheet(const QString &styleSheet)
QDateTime addMonths(int nmonths) const
virtual void wheelEvent(QWheelEvent *event)
void dateTimeChanged(const QDateTime &datetime)
int width() const
void setCursor(const QCursor &)
virtual QSize sizeHint() const
QDateTime addYears(int nyears) const
bool allowNull() const
virtual QSize minimumSizeHint() const
void setText(const QString &)
void showEvent(QShowEvent *event) override
QDateTime minimumDateTime() const
QStyle * style() const
static QIcon getThemeIcon(const QString &theName)
Helper to get a theme icon.
virtual int pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const=0
virtual void setVisible(bool visible)
virtual QRect subControlRect(ComplexControl control, const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const=0
void focusOutEvent(QFocusEvent *event) override
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
void setIcon(const QIcon &icon)
virtual void focusOutEvent(QFocusEvent *event)
void initStyleOption(QStyleOptionSpinBox *option) const
QString text() const
void wheelEvent(QWheelEvent *event) override
bool isNull() const
void setMinimumSize(const QSize &)
void setCurrentPage(int year, int month)
virtual bool event(QEvent *event)
QLineEdit * lineEdit() const
void move(int x, int y)
Section currentSection() const
bool contains(const QPoint &point, bool proper) const
virtual void showEvent(QShowEvent *event)
void hide()
virtual void mousePressEvent(QMouseEvent *event)
QRect rect() const
bool blockSignals(bool block)
int delta() const
bool isValid() const
void setCalendarPopup(bool enable)
void setDateTime(const QDateTime &dateTime)
QCalendarWidget * calendarWidget() const
QDateTime currentDateTime()
void editingFinished()
bool isNull() const
virtual void resizeEvent(QResizeEvent *event)
QDate currentDate()
int height() const
int bottom() const
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.
QDateTime maximumDateTime() const
QgsDateTimeEdit(QWidget *parent=nullptr)
const QPoint & pos() const
void setDateTime(const QDateTime &dateTime)
setDateTime set the date time in the widget and handles null date times.
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
virtual void resizeEvent(QResizeEvent *event) override
QDateTime addDays(int ndays) const
virtual 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
bool isNull(const QVariant &v)
virtual void focusOutEvent(QFocusEvent *event)
void mousePressEvent(QMouseEvent *event) override