1 /***************************************************************************
2     qgsdatetimeedit.h
3      --------------------------------------
4     Date                 : 08.2014
5     Copyright            : (C) 2014 Denis Rouzaud
6     Email                : denis.rouzaud@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 
16 #ifndef QGSDATETIMEEDIT_H
17 #define QGSDATETIMEEDIT_H
18 
19 #include <QDateTimeEdit>
20 #include "qgis_sip.h"
21 #include "qgis_gui.h"
22 
23 /**
24  * \ingroup gui
25  * \brief The QgsDateTimeEdit class is a QDateTimeEdit with the capability of setting/reading null date/times.
26  *
27  * \warning You should use the signal valueChanged of this subclass
28  * rather than QDateTimeEdit::dateTimeChanged. (If you consequently connect parent's
29  * dateTimeChanged signal and call dateTime() afterwards there is no guarantee that
30  * NULL values will be correctly handled).
31  *
32  * \see QgsDateEdit
33  * \see QgsTimeEdit
34  *
35  */
36 class GUI_EXPORT QgsDateTimeEdit : public QDateTimeEdit
37 {
38     Q_OBJECT
39     Q_PROPERTY( bool allowNull READ allowNull WRITE setAllowNull )
40 
41   public:
42 
43     /**
44      * Constructor for QgsDateTimeEdit.
45      * The current date and time is used by default.
46      * The widget is allowing null by default.
47      * If allow null is disabled, you should check allowNull before getting values from the widget.
48      */
49     explicit QgsDateTimeEdit( QWidget *parent SIP_TRANSFERTHIS = nullptr );
50 
51     /**
52      * Determines if the widget allows setting null date/time.
53      * \see allowNull
54      */
55     void setAllowNull( bool allowNull );
56 
57     /**
58      * If the widget allows setting null date/time.
59      * \see setAllowNull
60      */
allowNull()61     bool allowNull() const {return mAllowNull;}
62 
63     /**
64      * \brief Set the date time in the widget and handles null date times.
65      * \note Since QDateTimeEdit::setDateTime() is not virtual, setDateTime must be called for QgsDateTimeEdit.
66      */
67     void setDateTime( const QDateTime &dateTime );
68 
69     /**
70      * \brief Returns the date time which can be a null date/time.
71      * \note Before QGIS 3.10, you mustn't call date() or time() because they can't return a NULL value.
72      * \note Since QDateTimeEdit::dateTime() is not virtual, dateTime must be called for QgsDateTimeEdit.
73      */
74     QDateTime dateTime() const;
75 
76     /**
77      * \brief Returns the time which can be a null time.
78      * \since QGIS 3.10
79      */
80     QTime time() const;
81 
82     /**
83      * \brief Returns the date which can be a null date.
84      * \since QGIS 3.10
85      */
86     QDate date() const;
87 
88     /**
89      * Set the current date as NULL.
90      * \note If the widget is not configured to accept NULL dates, this will have no effect.
91      */
92     void clear() override;
93 
94     /**
95      * Resets the widget to show no value (ie, an "unknown" state).
96      * \since QGIS 2.16
97      */
98     void setEmpty();
99 
100     /**
101      * Returns the widget's NULL representation, which defaults
102      * to QgsApplication::nullRepresentation().
103      *
104      * \see setNullRepresentation()
105      * \since QGIS 3.14
106      */
107     QString nullRepresentation() const;
108 
109     /**
110      * Sets the widget's \a null representation, which defaults
111      * to QgsApplication::nullRepresentation().
112      *
113      * \see nullRepresentation()
114      * \since QGIS 3.14
115      */
116     void setNullRepresentation( const QString &null );
117 
118   signals:
119 
120     /**
121      * Signal emitted whenever the value changes.
122      * \param date The new date/time value.
123      */
124     void valueChanged( const QDateTime &date );
125 
126   protected:
127     void mousePressEvent( QMouseEvent *event ) override;
128     void focusOutEvent( QFocusEvent *event ) override;
129     void focusInEvent( QFocusEvent *event ) override;
130     void wheelEvent( QWheelEvent *event ) override;
131     void showEvent( QShowEvent *event ) override;
132 
133 #ifndef SIP_RUN
134 ///@cond PRIVATE
135     QgsDateTimeEdit( const QVariant &var, QVariant::Type parserType, QWidget *parent );
136 ///@endcond
137 #endif
138 
139     //! TRUE if the widget is empty
140     bool mIsEmpty = false;
141 
142     //! Block change signals if TRUE
143     int mBlockChangedSignal = 0;
144 
145     /**
146     * write the null value representation to the line edit without changing the value
147     * \param updateCalendar Flag if calendar is open and minimum date needs to be set
148     */
149     void displayNull( bool updateCalendar = false );
150 
151     /**
152      * Emits the widget's correct value changed signal.
153      */
154     virtual void emitValueChanged( const QVariant &value );
155 
156     /**
157      * Returns TRUE if the widget is currently set to a null value
158      */
159     bool isNull() const;
160 
161   protected slots:
162 #ifndef SIP_RUN
163     ///@cond PRIVATE
164     void changed( const QVariant &dateTime );
165     ///@endcond
166 #endif
167 
168 
169   private:
170     bool mCurrentPressEvent = false;
171 
172     QString mOriginalStyleSheet = QString();
173     QAction *mClearAction;
174     QString mNullRepresentation;
175 
176     //! TRUE if the widget allows null values
177     bool mAllowNull = true;
178 
179     //! TRUE if the widget is currently set to a null value
180     bool mIsNull = false;
181 
182     /**
183     * write the current date into the line edit without changing the value
184     */
185     void displayCurrentDate();
186 
187     //! reset the value to current date time
188     void resetBeforeChange( int delta );
189 
190     /**
191      * Set the lowest Date that can be stored in a Shapefile or Geopackage Date field
192      *
193      * - uses QDateTimeEdit::setDateTimeRange (since Qt 4.4)
194      *
195      * \note
196      *
197      * - QDate and QDateTime does not support minus years for the Qt::ISODate format
198      *   -> returns empty (toString) or invalid (fromString) values
199     *
200     * \note not available in Python bindings
201     * \since QGIS 3.0
202     */
setMinimumEditDateTime()203     void setMinimumEditDateTime()
204     {
205       setDateTimeRange( QDateTime( QDate( 1, 1, 1 ), QTime( 0, 0, 0 ) ), maximumDateTime() );
206     }
207 
208     friend class TestQgsDateTimeEdit;
209 };
210 
211 
212 /**
213  * \ingroup gui
214  * \brief The QgsTimeEdit class is a QTimeEdit widget with the capability of setting/reading null date/times.
215  *
216  * \warning You should use the signal valueChanged of this subclass
217  * rather than QDateTimeEdit::timeChanged. (If you consequently connect parent's
218  * timeChanged signal and call time() afterwards there is no guarantee that
219  * NULL values will be correctly handled).
220  *
221  * \see QgsDateTimeEdit
222  * \see QgsDateEdit
223  *
224  * \since QGIS 3.14
225  */
226 class GUI_EXPORT QgsTimeEdit : public QgsDateTimeEdit
227 {
228     Q_OBJECT
229 
230   public:
231 
232     /**
233      * Constructor for QgsTimeEdit.
234      * The current time is used by default.
235      * The widget is allowing null by default.
236      * If allow null is disabled, you should check allowNull before getting values from the widget.
237      */
238     explicit QgsTimeEdit( QWidget *parent SIP_TRANSFERTHIS = nullptr );
239 
240     /**
241      * Sets the \a time for the widget and handles null times.
242      * \note Since QDateTimeEdit::setTime() is not virtual, setTime must be called for QgsTimeEdit.
243      */
244     void setTime( const QTime &time );
245 
246   signals:
247 
248     /**
249      * Signal emitted whenever the time changes.
250      */
251     void timeValueChanged( const QTime &time );
252 
253   protected:
254     void emitValueChanged( const QVariant &value ) override;
255 
256 };
257 
258 /**
259  * \ingroup gui
260  * \brief The QgsDateEdit class is a QDateEdit widget with the capability of setting/reading null dates.
261  *
262  * \warning You should use the signal valueChanged of this subclass
263  * rather than QDateTimeEdit::dateChanged. (If you consequently connect parent's
264  * dateChanged signal and call date() afterwards there is no guarantee that
265  * NULL values will be correctly handled).
266  *
267  * \see QgsDateTimeEdit
268  * \see QgsTimeEdit
269  *
270  * \since QGIS 3.14
271  */
272 class GUI_EXPORT QgsDateEdit : public QgsDateTimeEdit
273 {
274     Q_OBJECT
275 
276   public:
277 
278     /**
279      * Constructor for QgsDateEdit.
280      * The current time is used by default.
281      * The widget is allowing null by default.
282      * If allow null is disabled, you should check allowNull before getting values from the widget.
283      */
284     explicit QgsDateEdit( QWidget *parent SIP_TRANSFERTHIS = nullptr );
285 
286     /**
287      * Sets the \a date for the widget and handles null dates.
288      * \note Since QDateTimeEdit::setDate() is not virtual, setDate must be called for QgsDateEdit.
289      */
290     void setDate( const QDate &date );
291 
292   signals:
293 
294     /**
295      * Signal emitted whenever the date changes.
296      */
297     void dateValueChanged( const QDate &date );
298 
299   protected:
300     void emitValueChanged( const QVariant &value ) override;
301 
302 };
303 
304 #endif // QGSDATETIMEEDIT_H
305