source: vendor/trolltech/current/src/widgets/qdatetimeedit.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 65.4 KB
Line 
1/****************************************************************************
2** $Id: qdatetimeedit.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of date and time edit classes
5**
6** Created : 001103
7**
8** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
9**
10** This file is part of the widgets module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition licenses may use this
22** file in accordance with the Qt Commercial License Agreement provided
23** with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qdatetimeedit.h"
39
40#ifndef QT_NO_DATETIMEEDIT
41
42#include "../kernel/qinternal_p.h"
43#include "../kernel/qrichtext_p.h"
44#include "qrangecontrol.h"
45#include "qapplication.h"
46#include "qpixmap.h"
47#include "qapplication.h"
48#include "qvaluelist.h"
49#include "qstring.h"
50#include "qstyle.h"
51
52#if defined(Q_WS_WIN)
53#include "qt_windows.h"
54#endif
55
56#define QDATETIMEEDIT_HIDDEN_CHAR '0'
57
58class Q_EXPORT QNumberSection
59{
60public:
61 QNumberSection( int selStart = 0, int selEnd = 0, bool separat = TRUE, int actual = -1 )
62 : selstart( selStart ), selend( selEnd ), act( actual ), sep( separat )
63 {}
64 int selectionStart() const { return selstart; }
65 void setSelectionStart( int s ) { selstart = s; }
66 int selectionEnd() const { return selend; }
67 void setSelectionEnd( int s ) { selend = s; }
68 int width() const { return selend - selstart; }
69 int index() const { return act; }
70 bool separator() const { return sep; }
71 Q_DUMMY_COMPARISON_OPERATOR( QNumberSection )
72private:
73 int selstart :12;
74 int selend :12;
75 int act :7;
76 bool sep :1;
77};
78
79static QString *lDateSep = 0;
80static QString *lTimeSep = 0;
81static bool lAMPM = FALSE;
82static QString *lAM = 0;
83static QString *lPM = 0;
84static QDateEdit::Order lOrder = QDateEdit::YMD;
85static int refcount = 0;
86
87static void cleanup()
88{
89 delete lDateSep;
90 lDateSep = 0;
91 delete lTimeSep;
92 lTimeSep = 0;
93 delete lAM;
94 lAM = 0;
95 delete lPM;
96 lPM = 0;
97}
98
99/*!
100\internal
101try to get the order of DMY and the date/time separator from the locale settings
102*/
103static void readLocaleSettings()
104{
105 int dpos, mpos, ypos;
106 cleanup();
107
108 lDateSep = new QString();
109 lTimeSep = new QString();
110
111#if defined(Q_WS_WIN)
112 QT_WA( {
113 TCHAR data[10];
114 GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_SDATE, data, 10 );
115 *lDateSep = QString::fromUcs2( (ushort*)data );
116 GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_STIME, data, 10 );
117 *lTimeSep = QString::fromUcs2( (ushort*)data );
118 GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_ITIME, data, 10 );
119 lAMPM = QString::fromUcs2( (ushort*)data ).toInt()==0;
120 GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_S1159, data, 10 );
121 QString am = QString::fromUcs2( (ushort*)data );
122 if ( !am.isEmpty() )
123 lAM = new QString( am );
124 GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_S2359, data, 10 );
125 QString pm = QString::fromUcs2( (ushort*)data );
126 if ( !pm.isEmpty() )
127 lPM = new QString( pm );
128 } , {
129 char data[10];
130 GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_SDATE, (char*)&data, 10 );
131 *lDateSep = QString::fromLocal8Bit( data );
132 GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_STIME, (char*)&data, 10 );
133 *lTimeSep = QString::fromLocal8Bit( data );
134 GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_ITIME, (char*)&data, 10 );
135 lAMPM = QString::fromLocal8Bit( data ).toInt()==0;
136 GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_S1159, (char*)&data, 10 );
137 QString am = QString::fromLocal8Bit( data );
138 if ( !am.isEmpty() )
139 lAM = new QString( am );
140 GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_S2359, (char*)&data, 10 );
141 QString pm = QString::fromLocal8Bit( data );
142 if ( !pm.isEmpty() )
143 lPM = new QString( pm );
144 } );
145#else
146 *lDateSep = "-";
147 *lTimeSep = ":";
148#endif
149 QString d = QDate( 1999, 11, 22 ).toString( Qt::LocalDate );
150 dpos = d.find( "22" );
151 mpos = d.find( "11" );
152 ypos = d.find( "99" );
153 if ( dpos > -1 && mpos > -1 && ypos > -1 ) {
154 // test for DMY, MDY, YMD, YDM
155 if ( dpos < mpos && mpos < ypos ) {
156 lOrder = QDateEdit::DMY;
157 } else if ( mpos < dpos && dpos < ypos ) {
158 lOrder = QDateEdit::MDY;
159 } else if ( ypos < mpos && mpos < dpos ) {
160 lOrder = QDateEdit::YMD;
161 } else if ( ypos < dpos && dpos < mpos ) {
162 lOrder = QDateEdit::YDM;
163 } else {
164 // cannot determine the dateformat - use the default
165 return;
166 }
167
168 // this code needs to change if new formats are added
169
170#ifndef Q_WS_WIN
171 QString sep = d.mid( QMIN( dpos, mpos ) + 2, QABS( dpos - mpos ) - 2 );
172 if ( d.contains( sep ) == 2 ) {
173 *lDateSep = sep;
174 }
175#endif
176 }
177
178#ifndef Q_WS_WIN
179 QString t = QTime( 11, 22, 33 ).toString( Qt::LocalDate );
180 dpos = t.find( "11" );
181 mpos = t.find( "22" );
182 ypos = t.find( "33" );
183 // We only allow hhmmss
184 if ( dpos > -1 && dpos < mpos && mpos < ypos ) {
185 QString sep = t.mid( dpos + 2, mpos - dpos - 2 );
186 if ( sep == t.mid( mpos + 2, ypos - mpos - 2 ) ) {
187 *lTimeSep = sep;
188 }
189 }
190#endif
191}
192
193static QDateEdit::Order localOrder() {
194 if ( !lDateSep ) {
195 readLocaleSettings();
196 }
197 return lOrder;
198}
199
200static QString localDateSep() {
201 if ( !lDateSep ) {
202 readLocaleSettings();
203 }
204 return *lDateSep;
205}
206
207static QString localTimeSep() {
208 if ( !lTimeSep ) {
209 readLocaleSettings();
210 }
211 return *lTimeSep;
212}
213
214class QDateTimeEditorPrivate
215{
216public:
217 QDateTimeEditorPrivate()
218 : frm( TRUE ),
219 parag( new QTextParagraph( 0, 0, 0, FALSE ) ),
220 focusSec(0)
221 {
222 parag->formatter()->setWrapEnabled( FALSE );
223 cursor = new QTextCursor( 0 );
224 cursor->setParagraph( parag );
225 offset = 0;
226 sep = localDateSep();
227 refcount++;
228 }
229 ~QDateTimeEditorPrivate()
230 {
231 delete parag;
232 delete cursor;
233 if ( !--refcount )
234 cleanup();
235 }
236
237 void appendSection( const QNumberSection& sec )
238 {
239 sections.append( sec );
240
241 }
242 void clearSections()
243 {
244 sections.clear();
245 }
246 void setSectionSelection( int sec, int selstart, int selend )
247 {
248 if ( sec < 0 || sec > (int)sections.count() )
249 return;
250 sections[sec].setSelectionStart( selstart );
251 sections[sec].setSelectionEnd( selend );
252 }
253 uint sectionCount() const { return (uint)sections.count(); }
254 void setSeparator( const QString& s ) { sep = s; }
255 QString separator() const { return sep; }
256
257 void setFrame( bool f ) { frm = f; }
258 bool frame() const { return frm; }
259
260 int focusSection() const { return focusSec; }
261 int section( const QPoint& p )
262 {
263 cursor->place( p + QPoint( offset, 0 ), parag );
264 int idx = cursor->index();
265 for ( uint i = 0; i < sections.count(); ++i ) {
266 if ( idx >= sections[i].selectionStart() &&
267 idx <= sections[i].selectionEnd() )
268 return i;
269 }
270 return -1;
271 }
272 QNumberSection section( int idx ) const
273 {
274 return sections[idx];
275 }
276 bool setFocusSection( int idx )
277 {
278 if ( idx > (int)sections.count()-1 || idx < 0 )
279 return FALSE;
280 if ( idx != focusSec ) {
281 focusSec = idx;
282 applyFocusSelection();
283 return TRUE;
284 }
285 return FALSE;
286 }
287
288 bool inSectionSelection( int idx )
289 {
290 for ( uint i = 0; i < sections.count(); ++i ) {
291 if ( idx >= sections[i].selectionStart() &&
292 idx <= sections[i].selectionEnd() )
293 return TRUE;
294 }
295 return FALSE;
296 }
297
298 void paint( const QString& txt, bool focus, QPainter& p,
299 const QColorGroup& cg, const QRect& rect, QStyle& style )
300 {
301 int fw = 0;
302 if ( frm )
303 fw = style.pixelMetric(QStyle::PM_DefaultFrameWidth);
304
305 parag->truncate( 0 );
306 parag->append( txt );
307 if ( !focus )
308 parag->removeSelection( QTextDocument::Standard );
309 else {
310 applyFocusSelection();
311 }
312
313 /* color all QDATETIMEEDIT_HIDDEN_CHAR chars to background color */
314 QTextFormat *fb = parag->formatCollection()->format( p.font(),
315 cg.base() );
316 QTextFormat *nf = parag->formatCollection()->format( p.font(),
317 cg.text() );
318 for ( uint i = 0; i < txt.length(); ++i ) {
319 parag->setFormat( i, 1, nf );
320 if ( inSectionSelection( i ) )
321 continue;
322 if ( txt.at(i) == QDATETIMEEDIT_HIDDEN_CHAR )
323 parag->setFormat( i, 1, fb );
324 else
325 parag->setFormat( i, 1, nf );
326 }
327 fb->removeRef();
328 nf->removeRef();
329
330 QRect r( rect.x(), rect.y(), rect.width() - 2 * ( 2 + fw ), rect.height() );
331 parag->pseudoDocument()->docRect = r;
332 parag->invalidate(0);
333 parag->format();
334
335 int xoff = 2 + fw - offset;
336 int yoff = ( rect.height() - parag->rect().height() + 1 ) / 2;
337 if ( yoff < 0 )
338 yoff = 0;
339
340 p.translate( xoff, yoff );
341 parag->paint( p, cg, 0, TRUE );
342 if ( frm )
343 p.translate( -xoff, -yoff );
344 }
345
346 void resize( const QSize& size ) { sz = size; }
347
348 int mapSection( int sec )
349 {
350 return sections[sec].index();
351 }
352
353protected:
354 void applyFocusSelection()
355 {
356 if ( focusSec > -1 ) {
357 int selstart = sections[ focusSec ].selectionStart();
358 int selend = sections[ focusSec ].selectionEnd();
359 parag->setSelection( QTextDocument::Standard, selstart, selend );
360 parag->format();
361 if ( parag->at( selstart )->x < offset ||
362 parag->at( selend )->x + parag->string()->width( selend ) > offset + sz.width() ) {
363 offset = parag->at( selstart )->x;
364 }
365 }
366 }
367private:
368 bool frm;
369 QTextParagraph *parag;
370 QTextCursor *cursor;
371 QSize sz;
372 int focusSec;
373 QValueList< QNumberSection > sections;
374 QString sep;
375 int offset;
376};
377
378class QDateTimeEditor : public QWidget
379{
380 Q_OBJECT
381public:
382 QDateTimeEditor( QDateTimeEditBase * parent=0,
383 const char * name=0 );
384 ~QDateTimeEditor();
385
386 void setControlWidget( QDateTimeEditBase * widget );
387 QDateTimeEditBase * controlWidget() const;
388
389 void setSeparator( const QString& s );
390 QString separator() const;
391
392 int focusSection() const;
393 bool setFocusSection( int s );
394 void appendSection( const QNumberSection& sec );
395 void clearSections();
396 void setSectionSelection( int sec, int selstart, int selend );
397 bool eventFilter( QObject *o, QEvent *e );
398 int sectionAt( const QPoint &p );
399 int mapSection( int sec );
400
401protected:
402 void init();
403 bool event( QEvent *e );
404 void resizeEvent( QResizeEvent * );
405 void paintEvent( QPaintEvent * );
406 void mousePressEvent( QMouseEvent *e );
407
408private:
409 QDateTimeEditBase* cw;
410 QDateTimeEditorPrivate* d;
411};
412
413class QDateTimeSpinWidget : public QSpinWidget
414{
415public:
416 QDateTimeSpinWidget( QWidget *parent, const char *name )
417 : QSpinWidget( parent, name )
418 {
419 }
420
421protected:
422#ifndef QT_NO_WHEELEVENT
423 void wheelEvent( QWheelEvent *e )
424 {
425 QDateTimeEditor *editor = (QDateTimeEditor*)editWidget()->qt_cast( "QDateTimeEditor" );
426 Q_ASSERT( editor );
427 if ( !editor )
428 return;
429
430 int section = editor->sectionAt( e->pos() );
431 editor->setFocusSection( section );
432
433 if ( section == -1 )
434 return;
435 QSpinWidget::wheelEvent( e );
436 }
437#endif
438};
439
440/*!
441 Constructs an empty datetime editor with parent \a parent and
442 called \a name.
443*/
444QDateTimeEditor::QDateTimeEditor( QDateTimeEditBase * parent,
445 const char * name )
446 : QWidget( parent, name, WNoAutoErase )
447{
448 d = new QDateTimeEditorPrivate();
449 cw = parent;
450 init();
451}
452
453/*!
454 Destroys the object and frees any allocated resources.
455*/
456
457QDateTimeEditor::~QDateTimeEditor()
458{
459 delete d;
460}
461
462/*! \internal
463
464*/
465
466void QDateTimeEditor::init()
467{
468 setBackgroundMode( PaletteBase );
469 setFocusSection( -1 );
470 installEventFilter( this );
471 setFocusPolicy( WheelFocus );
472}
473
474
475/*! \reimp
476
477*/
478
479bool QDateTimeEditor::event( QEvent *e )
480{
481 if ( e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut ) {
482 if ( e->type() == QEvent::FocusOut )
483 qApp->sendEvent( cw, e );
484 update( rect() );
485 } else if ( e->type() == QEvent::AccelOverride ) {
486 QKeyEvent* ke = (QKeyEvent*) e;
487 switch ( ke->key() ) {
488 case Key_Delete:
489 case Key_Backspace:
490 case Key_Up:
491 case Key_Down:
492 case Key_Left:
493 case Key_Right:
494 ke->accept();
495 default:
496 break;
497 }
498 }
499 return QWidget::event( e );
500}
501
502/*! \reimp
503
504*/
505
506void QDateTimeEditor::resizeEvent( QResizeEvent *e )
507{
508 d->resize( e->size() );
509 QWidget::resizeEvent( e );
510}
511
512
513/*! \reimp
514
515*/
516
517void QDateTimeEditor::paintEvent( QPaintEvent * )
518{
519 QString txt;
520 for ( uint i = 0; i < d->sectionCount(); ++i ) {
521 txt += cw->sectionFormattedText( i );
522 if ( i < d->sectionCount()-1 ) {
523 if ( d->section( i+1 ).separator() )
524 txt += d->separator();
525 else
526 txt += " ";
527 }
528 }
529
530 QSharedDoubleBuffer buffer( this );
531 const QBrush &bg =
532 colorGroup().brush( isEnabled() ? QColorGroup::Base : QColorGroup::Background );
533 buffer.painter()->fillRect( 0, 0, width(), height(), bg );
534 d->paint( txt, hasFocus(), *buffer.painter(), colorGroup(), rect(),
535 style() );
536 buffer.end();
537}
538
539
540/*!
541 Returns the section index at point \a p.
542*/
543int QDateTimeEditor::sectionAt( const QPoint &p )
544{
545 return d->section( p );
546}
547
548int QDateTimeEditor::mapSection( int sec )
549{
550 return d->mapSection( sec );
551}
552
553
554/*! \reimp
555
556*/
557
558void QDateTimeEditor::mousePressEvent( QMouseEvent *e )
559{
560 QPoint p( e->pos().x(), 0 );
561 int sec = sectionAt( p );
562 if ( sec != -1 ) {
563 cw->setFocusSection( sec );
564 repaint( rect(), FALSE );
565 }
566}
567
568/*! \reimp
569
570*/
571bool QDateTimeEditor::eventFilter( QObject *o, QEvent *e )
572{
573 if ( o == this ) {
574 if ( e->type() == QEvent::KeyPress ) {
575 QKeyEvent *ke = (QKeyEvent*)e;
576 switch ( ke->key() ) {
577 case Key_Right:
578 if ( d->focusSection() < (int)d->sectionCount()-1 ) {
579 if ( cw->setFocusSection( focusSection()+1 ) )
580 repaint( rect(), FALSE );
581 }
582 return TRUE;
583 case Key_Left:
584 if ( d->focusSection() > 0 ) {
585 if ( cw->setFocusSection( focusSection()-1 ) )
586 repaint( rect(), FALSE );
587 }
588 return TRUE;
589 case Key_Up:
590 cw->stepUp();
591 return TRUE;
592 case Key_Down:
593 cw->stepDown();
594 return TRUE;
595 case Key_Backspace:
596 if ( ::qt_cast<QDateEdit*>(cw) )
597 ((QDateEdit*)cw)->removeFirstNumber( d->focusSection() );
598 else if ( ::qt_cast<QTimeEdit*>(cw) )
599 ((QTimeEdit*)cw)->removeFirstNumber( d->focusSection() );
600 return TRUE;
601 case Key_Delete:
602 cw->removeLastNumber( d->focusSection() );
603 return TRUE;
604 case Key_Tab:
605 case Key_BackTab: {
606 if ( ke->state() == Qt::ControlButton )
607 return FALSE;
608
609 QWidget *w = this;
610 bool hadDateEdit = FALSE;
611 while ( w ) {
612 if ( ::qt_cast<QDateTimeSpinWidget*>(w) && qstrcmp( w->name(), "qt_spin_widget" ) != 0 ||
613 ::qt_cast<QDateTimeEdit*>(w) )
614 break;
615 hadDateEdit = hadDateEdit || ::qt_cast<QDateEdit*>(w);
616 w = w->parentWidget();
617 }
618
619 if ( w ) {
620 if ( !::qt_cast<QDateTimeEdit*>(w) ) {
621 w = w->parentWidget();
622 } else {
623 QDateTimeEdit *ed = (QDateTimeEdit*)w;
624 if ( hadDateEdit && ke->key() == Key_Tab ) {
625 ed->timeEdit()->setFocus();
626 return TRUE;
627 } else if ( !hadDateEdit && ke->key() == Key_BackTab ) {
628 ed->dateEdit()->setFocus();
629 return TRUE;
630 } else {
631 while ( w && !::qt_cast<QDateTimeEdit*>(w) )
632 w = w->parentWidget();
633 }
634 }
635
636 qApp->sendEvent( w, e );
637 return TRUE;
638 }
639 } break;
640 default:
641 QString txt = ke->text().lower();
642 if ( !txt.isEmpty() && !separator().isEmpty() && txt[0] == separator()[0] ) {
643 // do the same thing as KEY_RIGHT when the user presses the separator key
644 if ( d->focusSection() < 2 ) {
645 if ( cw->setFocusSection( focusSection()+1 ) )
646 repaint( rect(), FALSE );
647 }
648 return TRUE;
649 } else if ( !txt.isEmpty() && ::qt_cast<QTimeEdit*>(cw) && focusSection() == (int) d->sectionCount()-1 ) {
650 // the first character of the AM/PM indicator toggles if the section has focus
651 QTimeEdit *te = (QTimeEdit*)cw;
652 QTime time = te->time();
653 if ( lAMPM && lAM && lPM && (te->display()&QTimeEdit::AMPM) ) {
654 if ( txt[0] == (*lAM).lower()[0] && time.hour() >= 12 ) {
655 time.setHMS( time.hour()-12, time.minute(), time.second(), time.msec() );
656 te->setTime( time );
657 } else if ( txt[0] == (*lPM).lower()[0] && time.hour() < 12 ) {
658 time.setHMS( time.hour()+12, time.minute(), time.second(), time.msec() );
659 te->setTime( time );
660 }
661 }
662 }
663
664 int num = txt[0].digitValue();
665 if ( num != -1 ) {
666 cw->addNumber( d->focusSection(), num );
667 return TRUE;
668 }
669 }
670 }
671 }
672 return FALSE;
673}
674
675
676/*!
677 Appends the number section \a sec to the editor.
678*/
679
680void QDateTimeEditor::appendSection( const QNumberSection& sec )
681{
682 d->appendSection( sec );
683}
684
685/*!
686 Removes all sections from the editor.
687*/
688
689void QDateTimeEditor::clearSections()
690{
691 d->clearSections();
692}
693
694/*!
695 Sets the selection of \a sec to start at \a selstart and end at \a
696 selend.
697*/
698
699void QDateTimeEditor::setSectionSelection( int sec, int selstart, int selend )
700{
701 d->setSectionSelection( sec, selstart, selend );
702}
703
704/*!
705 Sets the separator for all numbered sections to \a s. Note that
706 currently, only the first character of \a s is used.
707*/
708
709void QDateTimeEditor::setSeparator( const QString& s )
710{
711 d->setSeparator( s );
712 update();
713}
714
715
716/*!
717 Returns the editor's separator.
718*/
719
720QString QDateTimeEditor::separator() const
721{
722 return d->separator();
723}
724
725/*!
726 Returns the number of the section that has focus.
727*/
728
729int QDateTimeEditor::focusSection() const
730{
731 return d->focusSection();
732}
733
734
735/*!
736 Sets the focus to section \a sec. If \a sec does not exist,
737 nothing happens.
738*/
739
740bool QDateTimeEditor::setFocusSection( int sec )
741{
742 return d->setFocusSection( sec );
743}
744
745/*! \class QDateTimeEditBase
746 \brief The QDateTimeEditBase class provides an abstraction for date and edit editors.
747
748 Small abstract class that provides some functions that are common
749 for both QDateEdit and QTimeEdit. It is used internally by
750 QDateTimeEditor.
751*/
752
753/*!
754 \fn QDateTimeEditBase::QDateTimeEditBase(QWidget *, const char*)
755 \internal
756*/
757
758/*!
759 \fn QDateTimeEditBase::setFocusSection(int)
760 \internal
761*/
762
763/*! \fn QString QDateTimeEditBase::sectionFormattedText( int sec )
764 \internal
765
766 Pure virtual function which returns the formatted text of section \a
767 sec.
768
769*/
770
771/*! \fn void QDateTimeEditBase::stepUp()
772 \internal
773
774 Pure virtual slot which is called whenever the user increases the
775 number in a section by pressing the widget's arrow buttons or the
776 keyboard's arrow keys.
777*/
778
779/*! \fn void QDateTimeEditBase::stepDown()
780 \internal
781
782 Pure virtual slot which is called whenever the user decreases the
783 number in a section by pressing the widget's arrow buttons or the
784 keyboard's arrow keys.
785
786*/
787
788/*! \fn void QDateTimeEditBase::addNumber( int sec, int num )
789 \internal
790
791 Pure virtual function which is called whenever the user types a number.
792 \a sec indicates the section where the number should be added. \a
793 num is the number that was pressed.
794*/
795
796/*! \fn void QDateTimeEditBase::removeLastNumber( int sec )
797 \internal
798
799 Pure virtual function which is called whenever the user tries to
800 remove the last number from \a sec by pressing the delete key.
801*/
802
803////////////////
804
805class QDateEditPrivate
806{
807public:
808 int y;
809 int m;
810 int d;
811 // remebers the last entry for the day.
812 // if the day is 31 and you cycle through the months,
813 // the day will be 31 again if you reach a month with 31 days
814 // otherwise it will be the highest day in the month
815 int dayCache;
816 int yearSection;
817 int monthSection;
818 int daySection;
819 QDateEdit::Order ord;
820 bool overwrite;
821 bool adv;
822 int timerId;
823 bool typing;
824 QDate min;
825 QDate max;
826 bool changed;
827 QDateTimeEditor *ed;
828 QSpinWidget *controls;
829};
830
831
832/*!
833 \class QDateEdit qdatetimeedit.h
834 \brief The QDateEdit class provides a date editor.
835
836 \ingroup advanced
837 \ingroup time
838 \mainclass
839
840 QDateEdit allows the user to edit dates by using the keyboard or
841 the arrow keys to increase/decrease date values. The arrow keys
842 can be used to move from section to section within the QDateEdit
843 box. Dates appear in accordance with the local date/time settings
844 or in year, month, day order if the system doesn't provide this
845 information. It is recommended that the QDateEdit be initialised
846 with a date, e.g.
847
848 \code
849 QDateEdit *dateEdit = new QDateEdit( QDate::currentDate(), this );
850 dateEdit->setRange( QDate::currentDate().addDays( -365 ),
851 QDate::currentDate().addDays( 365 ) );
852 dateEdit->setOrder( QDateEdit::MDY );
853 dateEdit->setAutoAdvance( TRUE );
854 \endcode
855
856 Here we've created a new QDateEdit object initialised with today's
857 date and restricted the valid date range to today plus or minus
858 365 days. We've set the order to month, day, year. If the auto
859 advance property is TRUE (as we've set it here) when the user
860 completes a section of the date, e.g. enters two digits for the
861 month, they are automatically taken to the next section.
862
863 The maximum and minimum values for a date value in the date editor
864 default to the maximum and minimum values for a QDate. You can
865 change this by calling setMinValue(), setMaxValue() or setRange().
866
867 Terminology: A QDateEdit widget comprises three 'sections', one
868 each for the year, month and day. You can change the separator
869 character using QDateTimeEditor::setSeparator(), by default the
870 separator will be taken from the systems settings. If that is
871 not possible, it defaults to "-".
872
873 \img datetimewidgets.png Date Time Widgets
874
875 \sa QDate QTimeEdit QDateTimeEdit
876*/
877
878/*!
879 \enum QDateEdit::Order
880
881 This enum defines the order in which the sections that comprise a
882 date appear.
883 \value MDY month-day-year
884 \value DMY day-month-year
885 \value YMD year-month-day (the default)
886 \value YDM year-day-month (included for completeness; but should
887 not be used)
888*/
889
890/*!
891 \enum QTimeEdit::Display
892
893 This enum defines the sections that comprise a time
894
895 \value Hours The hours section
896 \value Minutes The minutes section
897 \value Seconds The seconds section
898 \value AMPM The AM/PM section
899
900 The values can be or'ed together to show any combination.
901*/
902
903/*!
904 Constructs an empty date editor which is a child of \a parent and
905 called name \a name.
906*/
907
908QDateEdit::QDateEdit( QWidget * parent, const char * name )
909 : QDateTimeEditBase( parent, name )
910{
911 init();
912 updateButtons();
913}
914
915/*!
916 \overload
917
918 Constructs a date editor with the initial value \a date, parent \a
919 parent and called \a name.
920
921 The date editor is initialized with \a date.
922*/
923
924QDateEdit::QDateEdit( const QDate& date, QWidget * parent, const char * name )
925 : QDateTimeEditBase( parent, name )
926{
927 init();
928 setDate( date );
929}
930
931/*! \internal
932*/
933void QDateEdit::init()
934{
935 d = new QDateEditPrivate();
936 d->controls = new QDateTimeSpinWidget( this, qstrcmp( name(), "qt_datetime_dateedit" ) == 0 ? "qt_spin_widget" : "date edit controls" );
937 d->ed = new QDateTimeEditor( this, "date editor" );
938 d->controls->setEditWidget( d->ed );
939 setFocusProxy( d->ed );
940 connect( d->controls, SIGNAL( stepUpPressed() ), SLOT( stepUp() ) );
941 connect( d->controls, SIGNAL( stepDownPressed() ), SLOT( stepDown() ) );
942 connect( this, SIGNAL( valueChanged(const QDate&) ),
943 SLOT( updateButtons() ) );
944 d->ed->appendSection( QNumberSection( 0,4 ) );
945 d->ed->appendSection( QNumberSection( 5,7 ) );
946 d->ed->appendSection( QNumberSection( 8,10 ) );
947
948 d->yearSection = -1;
949 d->monthSection = -1;
950 d->daySection = -1;
951
952 d->y = 0;
953 d->m = 0;
954 d->d = 0;
955 d->dayCache = 0;
956 setOrder( localOrder() );
957 setFocusSection( 0 );
958 d->overwrite = TRUE;
959 d->adv = FALSE;
960 d->timerId = 0;
961 d->typing = FALSE;
962 d->min = QDate( 1752, 9, 14 );
963 d->max = QDate( 8000, 12, 31 );
964 d->changed = FALSE;
965
966 setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
967
968 refcount++;
969}
970
971/*!
972 Destroys the object and frees any allocated resources.
973*/
974
975QDateEdit::~QDateEdit()
976{
977 delete d;
978 if ( !--refcount )
979 cleanup();
980}
981
982/*!
983 \property QDateEdit::minValue
984
985 \brief the editor's minimum value
986
987 Setting the minimum date value is equivalent to calling
988 QDateEdit::setRange( \e d, maxValue() ), where \e d is the minimum
989 date. The default minimum date is 1752-09-14.
990
991 \sa maxValue setRange()
992*/
993
994QDate QDateEdit::minValue() const
995{
996 return d->min;
997}
998
999/*!
1000 \property QDateEdit::maxValue
1001
1002 \brief the editor's maximum value
1003
1004 Setting the maximum date value for the editor is equivalent to
1005 calling QDateEdit::setRange( minValue(), \e d ), where \e d is the
1006 maximum date. The default maximum date is 8000-12-31.
1007
1008 \sa minValue setRange()
1009*/
1010
1011QDate QDateEdit::maxValue() const
1012{
1013 return d->max;
1014}
1015
1016
1017/*!
1018 Sets the valid input range for the editor to be from \a min to \a
1019 max inclusive. If \a min is invalid no minimum date will be set.
1020 Similarly, if \a max is invalid no maximum date will be set.
1021*/
1022
1023void QDateEdit::setRange( const QDate& min, const QDate& max )
1024{
1025 if ( min.isValid() )
1026 d->min = min;
1027 if ( max.isValid() )
1028 d->max = max;
1029}
1030
1031/*!
1032 Sets the separator to \a s. Note that currently only the first
1033 character of \a s is used.
1034*/
1035
1036void QDateEdit::setSeparator( const QString& s )
1037{
1038 d->ed->setSeparator( s );
1039}
1040
1041/*!
1042 Returns the editor's separator.
1043*/
1044
1045QString QDateEdit::separator() const
1046{
1047 return d->ed->separator();
1048}
1049
1050
1051/*!
1052 Enables/disables the push buttons according to the min/max date
1053 for this widget.
1054*/
1055
1056void QDateEdit::updateButtons()
1057{
1058 if ( !isEnabled() )
1059 return;
1060
1061 bool upEnabled = date() < maxValue();
1062 bool downEnabled = date() > minValue();
1063
1064 d->controls->setUpEnabled( upEnabled );
1065 d->controls->setDownEnabled( downEnabled );
1066}
1067
1068/*! \reimp
1069 */
1070void QDateEdit::resizeEvent( QResizeEvent * )
1071{
1072 d->controls->resize( width(), height() );
1073}
1074
1075/*! \reimp
1076
1077*/
1078QSize QDateEdit::sizeHint() const
1079{
1080 constPolish();
1081 QFontMetrics fm( font() );
1082 int fw = style().pixelMetric( QStyle::PM_DefaultFrameWidth, this );
1083 int h = QMAX( fm.lineSpacing(), 14 ) + 2;
1084 int w = 2 + fm.width( '9' ) * 8 + fm.width( d->ed->separator() ) * 2 + d->controls->upRect().width() + fw * 4;
1085
1086 return QSize( w, QMAX(h + fw * 2,20) ).expandedTo( QApplication::globalStrut() );
1087}
1088
1089/*! \reimp
1090
1091*/
1092QSize QDateEdit::minimumSizeHint() const
1093{
1094 return sizeHint();
1095}
1096
1097
1098/*!
1099 Returns the formatted number for section \a sec. This will
1100 correspond to either the year, month or day section, depending on
1101 the current display order.
1102
1103 \sa setOrder()
1104*/
1105
1106QString QDateEdit::sectionFormattedText( int sec )
1107{
1108 QString txt;
1109 txt = sectionText( sec );
1110 if ( d->typing && sec == d->ed->focusSection() )
1111 d->ed->setSectionSelection( sec, sectionOffsetEnd( sec ) - txt.length(),
1112 sectionOffsetEnd( sec ) );
1113 else
1114 d->ed->setSectionSelection( sec, sectionOffsetEnd( sec ) - sectionLength( sec ),
1115 sectionOffsetEnd( sec ) );
1116 txt = txt.rightJustify( sectionLength( sec ), QDATETIMEEDIT_HIDDEN_CHAR );
1117 return txt;
1118}
1119
1120
1121/*!
1122 Returns the desired length (number of digits) of section \a sec.
1123 This will correspond to either the year, month or day section,
1124 depending on the current display order.
1125
1126 \sa setOrder()
1127*/
1128
1129int QDateEdit::sectionLength( int sec ) const
1130{
1131 int val = 0;
1132 if ( sec == d->yearSection ) {
1133 val = 4;
1134 } else if ( sec == d->monthSection ) {
1135 val = 2;
1136 } else if ( sec == d->daySection ) {
1137 val = 2;
1138 }
1139 return val;
1140}
1141
1142/*!
1143 Returns the text of section \a sec. This will correspond to either
1144 the year, month or day section, depending on the current display
1145 order.
1146
1147 \sa setOrder()
1148*/
1149
1150QString QDateEdit::sectionText( int sec ) const
1151{
1152 int val = 0;
1153 if ( sec == d->yearSection ) {
1154 val = d->y;
1155 } else if ( sec == d->monthSection ) {
1156 val = d->m;
1157 } else if ( sec == d->daySection ) {
1158 val = d->d;
1159 }
1160 return QString::number( val );
1161}
1162
1163/*! \internal
1164
1165 Returns the end of the section offset \a sec.
1166
1167*/
1168
1169int QDateEdit::sectionOffsetEnd( int sec ) const
1170{
1171 if ( sec == d->yearSection ) {
1172 switch( d->ord ) {
1173 case DMY:
1174 case MDY:
1175 return sectionOffsetEnd( sec-1) + separator().length() + sectionLength( sec );
1176 case YMD:
1177 case YDM:
1178 return sectionLength( sec );
1179 }
1180 } else if ( sec == d->monthSection ) {
1181 switch( d->ord ) {
1182 case DMY:
1183 case YDM:
1184 case YMD:
1185 return sectionOffsetEnd( sec-1) + separator().length() + sectionLength( sec );
1186 case MDY:
1187 return sectionLength( sec );
1188 }
1189 } else if ( sec == d->daySection ) {
1190 switch( d->ord ) {
1191 case DMY:
1192 return sectionLength( sec );
1193 case YMD:
1194 case MDY:
1195 case YDM:
1196 return sectionOffsetEnd( sec-1 ) + separator().length() + sectionLength( sec );
1197 }
1198 }
1199 return 0;
1200}
1201
1202
1203/*!
1204 \property QDateEdit::order
1205 \brief the order in which the year, month and day appear
1206
1207 The default order is locale dependent.
1208
1209 \sa Order
1210*/
1211
1212void QDateEdit::setOrder( QDateEdit::Order order )
1213{
1214 d->ord = order;
1215 switch( d->ord ) {
1216 case DMY:
1217 d->yearSection = 2;
1218 d->monthSection = 1;
1219 d->daySection = 0;
1220 break;
1221 case MDY:
1222 d->yearSection = 2;
1223 d->monthSection = 0;
1224 d->daySection = 1;
1225 break;
1226 case YMD:
1227 d->yearSection = 0;
1228 d->monthSection = 1;
1229 d->daySection = 2;
1230 break;
1231 case YDM:
1232 d->yearSection = 0;
1233 d->monthSection = 2;
1234 d->daySection = 1;
1235 break;
1236 }
1237 if ( isVisible() )
1238 d->ed->repaint( d->ed->rect(), FALSE );
1239}
1240
1241
1242QDateEdit::Order QDateEdit::order() const
1243{
1244 return d->ord;
1245}
1246
1247
1248/*! \reimp
1249
1250*/
1251void QDateEdit::stepUp()
1252{
1253 int sec = d->ed->focusSection();
1254 bool accepted = FALSE;
1255 if ( sec == d->yearSection ) {
1256 if ( !outOfRange( d->y+1, d->m, d->d ) ) {
1257 accepted = TRUE;
1258 setYear( d->y+1 );
1259 }
1260 } else if ( sec == d->monthSection ) {
1261 if ( !outOfRange( d->y, d->m+1, d->d ) ) {
1262 accepted = TRUE;
1263 setMonth( d->m+1 );
1264 }
1265 } else if ( sec == d->daySection ) {
1266 if ( !outOfRange( d->y, d->m, d->d+1 ) ) {
1267 accepted = TRUE;
1268 setDay( d->d+1 );
1269 }
1270 }
1271 if ( accepted ) {
1272 d->changed = TRUE;
1273 emit valueChanged( date() );
1274 }
1275 d->ed->repaint( d->ed->rect(), FALSE );
1276}
1277
1278
1279
1280/*! \reimp
1281
1282*/
1283
1284void QDateEdit::stepDown()
1285{
1286 int sec = d->ed->focusSection();
1287 bool accepted = FALSE;
1288 if ( sec == d->yearSection ) {
1289 if ( !outOfRange( d->y-1, d->m, d->d ) ) {
1290 accepted = TRUE;
1291 setYear( d->y-1 );
1292 }
1293 } else if ( sec == d->monthSection ) {
1294 if ( !outOfRange( d->y, d->m-1, d->d ) ) {
1295 accepted = TRUE;
1296 setMonth( d->m-1 );
1297 }
1298 } else if ( sec == d->daySection ) {
1299 if ( !outOfRange( d->y, d->m, d->d-1 ) ) {
1300 accepted = TRUE;
1301 setDay( d->d-1 );
1302 }
1303 }
1304 if ( accepted ) {
1305 d->changed = TRUE;
1306 emit valueChanged( date() );
1307 }
1308 d->ed->repaint( d->ed->rect(), FALSE );
1309}
1310
1311/*!
1312 Sets the year to \a year, which must be a valid year. The range
1313 currently supported is from 1752 to 8000.
1314
1315 \sa QDate
1316*/
1317
1318void QDateEdit::setYear( int year )
1319{
1320 if ( year < 1752 )
1321 year = 1752;
1322 if ( year > 8000 )
1323 year = 8000;
1324 if ( !outOfRange( year, d->m, d->d ) ) {
1325 d->y = year;
1326 setMonth( d->m );
1327 int tmp = d->dayCache;
1328 setDay( d->dayCache );
1329 d->dayCache = tmp;
1330 }
1331}
1332
1333
1334/*!
1335 Sets the month to \a month, which must be a valid month, i.e.
1336 between 1 and 12.
1337*/
1338
1339void QDateEdit::setMonth( int month )
1340{
1341 if ( month < 1 )
1342 month = 1;
1343 if ( month > 12 )
1344 month = 12;
1345 if ( !outOfRange( d->y, month, d->d ) ) {
1346 d->m = month;
1347 int tmp = d->dayCache;
1348 setDay( d->dayCache );
1349 d->dayCache = tmp;
1350 }
1351}
1352
1353
1354/*!
1355 Sets the day to \a day, which must be a valid day. The function
1356 will ensure that the \a day set is valid for the month and year.
1357*/
1358
1359void QDateEdit::setDay( int day )
1360{
1361 if ( day < 1 )
1362 day = 1;
1363 if ( day > 31 )
1364 day = 31;
1365 if ( d->m > 0 && d->y > 1752 ) {
1366 while ( !QDate::isValid( d->y, d->m, day ) )
1367 --day;
1368 if ( !outOfRange( d->y, d->m, day ) )
1369 d->d = day;
1370 } else if ( d->m > 0 ) {
1371 if ( day > 0 && day < 32 ) {
1372 if ( !outOfRange( d->y, d->m, day ) )
1373 d->d = day;
1374 }
1375 }
1376 d->dayCache = d->d;
1377}
1378
1379
1380/*!
1381 \property QDateEdit::date
1382 \brief the editor's date value.
1383
1384 If the date property is not valid, the editor displays all zeroes
1385 and QDateEdit::date() will return an invalid date. It is strongly
1386 recommended that the editor is given a default date value (e.g.
1387 currentDate()). That way, attempts to set the date property to an
1388 invalid date will fail.
1389
1390 When changing the date property, if the date is less than
1391 minValue(), or is greater than maxValue(), nothing happens.
1392*/
1393
1394void QDateEdit::setDate( const QDate& date )
1395{
1396 if ( !date.isValid() ) {
1397 d->y = 0;
1398 d->m = 0;
1399 d->d = 0;
1400 d->dayCache = 0;
1401 } else {
1402 if ( date > maxValue() || date < minValue() )
1403 return;
1404 d->y = date.year();
1405 d->m = date.month();
1406 d->d = date.day();
1407 d->dayCache = d->d;
1408 emit valueChanged( date );
1409 }
1410 d->changed = FALSE;
1411 d->ed->repaint( d->ed->rect(), FALSE );
1412}
1413
1414QDate QDateEdit::date() const
1415{
1416 if ( QDate::isValid( d->y, d->m, d->d ) )
1417 return QDate( d->y, d->m, d->d );
1418 return QDate();
1419}
1420
1421/*! \internal
1422
1423 Returns TRUE if \a y, \a m, \a d is out of range, otherwise returns
1424 FALSE.
1425
1426 \sa setRange()
1427
1428*/
1429
1430bool QDateEdit::outOfRange( int y, int m, int d ) const
1431{
1432 if ( QDate::isValid( y, m, d ) ) {
1433 QDate currentDate( y, m, d );
1434 if ( currentDate > maxValue() ||
1435 currentDate < minValue() ) {
1436 //## outOfRange should set overwrite?
1437 return TRUE;
1438 }
1439 return FALSE;
1440 }
1441 return FALSE; /* assume ok */
1442}
1443
1444/*! \reimp
1445
1446*/
1447
1448void QDateEdit::addNumber( int sec, int num )
1449{
1450 if ( sec == -1 )
1451 return;
1452 killTimer( d->timerId );
1453 bool overwrite = FALSE;
1454 bool accepted = FALSE;
1455 d->typing = TRUE;
1456 QString txt;
1457 if ( sec == d->yearSection ) {
1458 txt = QString::number( d->y );
1459 if ( d->overwrite || txt.length() == 4 ) {
1460 accepted = TRUE;
1461 d->y = num;
1462 } else {
1463 txt += QString::number( num );
1464 if ( txt.length() == 4 ) {
1465 int val = txt.toInt();
1466 if ( val < 1792 )
1467 d->y = 1792;
1468 else if ( val > 8000 )
1469 d->y = 8000;
1470 else if ( outOfRange( val, d->m, d->d ) )
1471 txt = QString::number( d->y );
1472 else {
1473 accepted = TRUE;
1474 d->y = val;
1475 }
1476 } else {
1477 accepted = TRUE;
1478 d->y = txt.toInt();
1479 }
1480 if ( d->adv && txt.length() == 4 ) {
1481 d->ed->setFocusSection( d->ed->focusSection()+1 );
1482 overwrite = TRUE;
1483 }
1484 }
1485 } else if ( sec == d->monthSection ) {
1486 txt = QString::number( d->m );
1487 if ( d->overwrite || txt.length() == 2 ) {
1488 accepted = TRUE;
1489 d->m = num;
1490 } else {
1491 txt += QString::number( num );
1492 int temp = txt.toInt();
1493 if ( temp > 12 )
1494 temp = num;
1495 if ( outOfRange( d->y, temp, d->d ) )
1496 txt = QString::number( d->m );
1497 else {
1498 accepted = TRUE;
1499 d->m = temp;
1500 }
1501 if ( d->adv && txt.length() == 2 ) {
1502 d->ed->setFocusSection( d->ed->focusSection()+1 );
1503 overwrite = TRUE;
1504 }
1505 }
1506 } else if ( sec == d->daySection ) {
1507 txt = QString::number( d->d );
1508 if ( d->overwrite || txt.length() == 2 ) {
1509 accepted = TRUE;
1510 d->d = num;
1511 d->dayCache = d->d;
1512 } else {
1513 txt += QString::number( num );
1514 int temp = txt.toInt();
1515 if ( temp > 31 )
1516 temp = num;
1517 if ( outOfRange( d->y, d->m, temp ) )
1518 txt = QString::number( d->d );
1519 else {
1520 accepted = TRUE;
1521 d->d = temp;
1522 d->dayCache = d->d;
1523 }
1524 if ( d->adv && txt.length() == 2 ) {
1525 d->ed->setFocusSection( d->ed->focusSection()+1 );
1526 overwrite = TRUE;
1527 }
1528 }
1529 }
1530 if ( accepted ) {
1531 d->changed = TRUE;
1532 emit valueChanged( date() );
1533 }
1534 d->overwrite = overwrite;
1535 d->timerId = startTimer( qApp->doubleClickInterval()*4 );
1536 d->ed->repaint( d->ed->rect(), FALSE );
1537}
1538
1539
1540/*! \reimp
1541
1542*/
1543
1544bool QDateEdit::setFocusSection( int s )
1545{
1546 if ( s != d->ed->focusSection() ) {
1547 killTimer( d->timerId );
1548 d->overwrite = TRUE;
1549 d->typing = FALSE;
1550 fix(); // will emit valueChanged if necessary
1551 }
1552 return d->ed->setFocusSection( s );
1553}
1554
1555
1556/*!
1557 Attempts to fix any invalid date entries.
1558
1559 The rules applied are as follows:
1560
1561 \list
1562 \i If the year has four digits it is left unchanged.
1563 \i If the year has two digits, the year will be changed to four
1564 digits in the range current year - 70 to current year + 29.
1565 \i If the year has three digits in the range 100..999, the
1566 current millennium, i.e. 2000, will be added giving a year
1567 in the range 2100..2999.
1568 \endlist
1569
1570*/
1571
1572void QDateEdit::fix()
1573{
1574 bool changed = FALSE;
1575 int currentYear = QDate::currentDate().year();
1576 int year = d->y;
1577 if ( year < 100 ) {
1578 int currentCentury = currentYear / 100;
1579 year += currentCentury * 100;
1580 if ( currentYear > year ) {
1581 if ( currentYear > year + 70 )
1582 year += 100;
1583 } else {
1584 if ( year >= currentYear + 30 )
1585 year -= 100;
1586 }
1587 changed = TRUE;
1588 } else if ( year < 1000 ) {
1589 int currentMillennium = currentYear / 10;
1590 year += currentMillennium * 10;
1591 changed = TRUE;
1592 }
1593 if ( changed && outOfRange( year, d->m, d->d ) ) {
1594 if ( minValue().isValid() && date() < minValue() ) {
1595 d->d = minValue().day();
1596 d->dayCache = d->d;
1597 d->m = minValue().month();
1598 d->y = minValue().year();
1599 }
1600 if ( date() > maxValue() ) {
1601 d->d = maxValue().day();
1602 d->dayCache = d->d;
1603 d->m = maxValue().month();
1604 d->y = maxValue().year();
1605 }
1606 } else if ( changed )
1607 setYear( year );
1608 if ( changed ) {
1609 emit valueChanged( date() );
1610 d->changed = FALSE;
1611 }
1612}
1613
1614
1615/*! \reimp
1616
1617*/
1618
1619bool QDateEdit::event( QEvent *e )
1620{
1621 if( e->type() == QEvent::FocusOut ) {
1622 d->typing = FALSE;
1623 fix();
1624 // the following can't be done in fix() because fix() called
1625 // from all over the place and it will break the old behaviour
1626 if ( !QDate::isValid( d->y, d->m, d->d ) ) {
1627 d->dayCache = d->d;
1628 int i = d->d;
1629 for ( ; i > 0; i-- ) {
1630 d->d = i;
1631 if ( QDate::isValid( d->y, d->m, d->d ) )
1632 break;
1633 }
1634 d->changed = TRUE;
1635 }
1636 if ( d->changed ) {
1637 emit valueChanged( date() );
1638 d->changed = FALSE;
1639 }
1640 } else if ( e->type() == QEvent::LocaleChange ) {
1641 readLocaleSettings();
1642 d->ed->setSeparator( localDateSep() );
1643 setOrder( localOrder() );
1644 }
1645 return QDateTimeEditBase::event( e );
1646}
1647
1648/*!
1649 \internal
1650
1651 Function which is called whenever the user tries to
1652 remove the first number from \a sec by pressing the backspace key.
1653*/
1654
1655void QDateEdit::removeFirstNumber( int sec )
1656{
1657 if ( sec == -1 )
1658 return;
1659 QString txt;
1660 if ( sec == d->yearSection ) {
1661 txt = QString::number( d->y );
1662 txt = txt.mid( 1, txt.length() ) + "0";
1663 d->y = txt.toInt();
1664 } else if ( sec == d->monthSection ) {
1665 txt = QString::number( d->m );
1666 txt = txt.mid( 1, txt.length() ) + "0";
1667 d->m = txt.toInt();
1668 } else if ( sec == d->daySection ) {
1669 txt = QString::number( d->d );
1670 txt = txt.mid( 1, txt.length() ) + "0";
1671 d->d = txt.toInt();
1672 d->dayCache = d->d;
1673 }
1674 d->ed->repaint( d->ed->rect(), FALSE );
1675}
1676
1677/*! \reimp
1678
1679*/
1680
1681void QDateEdit::removeLastNumber( int sec )
1682{
1683 if ( sec == -1 )
1684 return;
1685 QString txt;
1686 if ( sec == d->yearSection ) {
1687 txt = QString::number( d->y );
1688 txt = txt.mid( 0, txt.length()-1 );
1689 d->y = txt.toInt();
1690 } else if ( sec == d->monthSection ) {
1691 txt = QString::number( d->m );
1692 txt = txt.mid( 0, txt.length()-1 );
1693 d->m = txt.toInt();
1694 } else if ( sec == d->daySection ) {
1695 txt = QString::number( d->d );
1696 txt = txt.mid( 0, txt.length()-1 );
1697 d->d = txt.toInt();
1698 d->dayCache = d->d;
1699 }
1700 d->ed->repaint( d->ed->rect(), FALSE );
1701}
1702
1703/*!
1704 \property QDateEdit::autoAdvance
1705 \brief whether the editor automatically advances to the next
1706 section
1707
1708 If autoAdvance is TRUE, the editor will automatically advance
1709 focus to the next date section if a user has completed a section.
1710 The default is FALSE.
1711*/
1712
1713void QDateEdit::setAutoAdvance( bool advance )
1714{
1715 d->adv = advance;
1716}
1717
1718
1719bool QDateEdit::autoAdvance() const
1720{
1721 return d->adv;
1722}
1723
1724/*! \reimp
1725*/
1726
1727void QDateEdit::timerEvent( QTimerEvent * )
1728{
1729 d->overwrite = TRUE;
1730}
1731
1732/*!
1733 \fn void QDateEdit::valueChanged( const QDate& date )
1734
1735 This signal is emitted whenever the editor's value changes. The \a
1736 date parameter is the new value.
1737*/
1738
1739///////////
1740
1741class QTimeEditPrivate
1742{
1743public:
1744 int h;
1745 int m;
1746 int s;
1747 uint display;
1748 bool adv;
1749 bool overwrite;
1750 int timerId;
1751 bool typing;
1752 QTime min;
1753 QTime max;
1754 bool changed;
1755 QDateTimeEditor *ed;
1756 QSpinWidget *controls;
1757};
1758
1759/*!
1760 \class QTimeEdit qdatetimeedit.h
1761 \brief The QTimeEdit class provides a time editor.
1762
1763 \ingroup advanced
1764 \ingroup time
1765 \mainclass
1766
1767 QTimeEdit allows the user to edit times by using the keyboard or
1768 the arrow keys to increase/decrease time values. The arrow keys
1769 can be used to move from section to section within the QTimeEdit
1770 box. The user can automatically be moved to the next section once
1771 they complete a section using setAutoAdvance(). Times appear in
1772 hour, minute, second order. It is recommended that the QTimeEdit
1773 is initialised with a time, e.g.
1774 \code
1775 QTime timeNow = QTime::currentTime();
1776 QTimeEdit *timeEdit = new QTimeEdit( timeNow, this );
1777 timeEdit->setRange( timeNow, timeNow.addSecs( 60 * 60 ) );
1778 \endcode
1779 Here we've created a QTimeEdit widget set to the current time.
1780 We've also set the minimum value to the current time and the
1781 maximum time to one hour from now.
1782
1783 The maximum and minimum values for a time value in the time editor
1784 default to the maximum and minimum values for a QTime. You can
1785 change this by calling setMinValue(), setMaxValue() or setRange().
1786
1787 Terminology: A QTimeWidget consists of three sections, one each
1788 for the hour, minute and second. You can change the separator
1789 character using setSeparator(), by default the separator is read
1790 from the system's settings.
1791
1792 \img datetimewidgets.png Date Time Widgets
1793
1794 \sa QTime QDateEdit QDateTimeEdit
1795*/
1796
1797
1798/*!
1799 Constructs an empty time edit with parent \a parent and called \a
1800 name.
1801*/
1802
1803QTimeEdit::QTimeEdit( QWidget * parent, const char * name )
1804 : QDateTimeEditBase( parent, name )
1805{
1806 init();
1807}
1808
1809/*!
1810 \overload
1811
1812 Constructs a time edit with the initial time value, \a time,
1813 parent \a parent and called \a name.
1814*/
1815
1816QTimeEdit::QTimeEdit( const QTime& time, QWidget * parent, const char * name )
1817 : QDateTimeEditBase( parent, name )
1818{
1819 init();
1820 setTime( time );
1821}
1822
1823/*! \internal
1824 */
1825
1826void QTimeEdit::init()
1827{
1828 d = new QTimeEditPrivate();
1829 d->ed = new QDateTimeEditor( this, "time edit base" );
1830 d->controls = new QDateTimeSpinWidget( this, qstrcmp( name(), "qt_datetime_timeedit" ) == 0 ? "qt_spin_widget" : "time edit controls" );
1831 d->controls->setEditWidget( d->ed );
1832 setFocusProxy( d->ed );
1833 connect( d->controls, SIGNAL( stepUpPressed() ), SLOT( stepUp() ) );
1834 connect( d->controls, SIGNAL( stepDownPressed() ), SLOT( stepDown() ) );
1835
1836 d->ed->appendSection( QNumberSection( 0,0, TRUE, 0 ) );
1837 d->ed->appendSection( QNumberSection( 0,0, TRUE, 1 ) );
1838 d->ed->appendSection( QNumberSection( 0,0, TRUE, 2 ) );
1839 d->ed->setSeparator( localTimeSep() );
1840
1841 d->h = 0;
1842 d->m = 0;
1843 d->s = 0;
1844 d->display = Hours | Minutes | Seconds;
1845 if ( lAMPM ) {
1846 d->display |= AMPM;
1847 d->ed->appendSection( QNumberSection( 0,0, FALSE, 3 ) );
1848 }
1849 d->adv = FALSE;
1850 d->overwrite = TRUE;
1851 d->timerId = 0;
1852 d->typing = FALSE;
1853 d->min = QTime( 0, 0, 0 );
1854 d->max = QTime( 23, 59, 59 );
1855 d->changed = FALSE;
1856
1857 setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
1858
1859 refcount++;
1860}
1861
1862/*!
1863 Destroys the object and frees any allocated resources.
1864*/
1865
1866QTimeEdit::~QTimeEdit()
1867{
1868 delete d;
1869 if ( !--refcount )
1870 cleanup();
1871}
1872
1873/*!
1874 \property QTimeEdit::minValue
1875 \brief the minimum time value
1876
1877 Setting the minimum time value is equivalent to calling
1878 QTimeEdit::setRange( \e t, maxValue() ), where \e t is the minimum
1879 time. The default minimum time is 00:00:00.
1880
1881 \sa maxValue setRange()
1882*/
1883
1884QTime QTimeEdit::minValue() const
1885{
1886 return d->min;
1887}
1888
1889/*!
1890 \property QTimeEdit::maxValue
1891 \brief the maximum time value
1892
1893 Setting the maximum time value is equivalent to calling
1894 QTimeEdit::setRange( minValue(), \e t ), where \e t is the maximum
1895 time. The default maximum time is 23:59:59.
1896
1897 \sa minValue setRange()
1898*/
1899
1900QTime QTimeEdit::maxValue() const
1901{
1902 return d->max;
1903}
1904
1905
1906/*!
1907 Sets the valid input range for the editor to be from \a min to \a
1908 max inclusive. If \a min is invalid no minimum time is set.
1909 Similarly, if \a max is invalid no maximum time is set.
1910*/
1911
1912void QTimeEdit::setRange( const QTime& min, const QTime& max )
1913{
1914 if ( min.isValid() )
1915 d->min = min;
1916 if ( max.isValid() )
1917 d->max = max;
1918}
1919
1920/*!
1921 \property QTimeEdit::display
1922 \brief the sections that are displayed in the time edit
1923
1924 The value can be any combination of the values in the Display enum.
1925 By default, the widget displays hours, minutes and seconds.
1926*/
1927void QTimeEdit::setDisplay( uint display )
1928{
1929 if ( d->display == display )
1930 return;
1931
1932 d->ed->clearSections();
1933 d->display = display;
1934 if ( d->display & Hours )
1935 d->ed->appendSection( QNumberSection( 0,0, TRUE, 0 ) );
1936 if ( d->display & Minutes )
1937 d->ed->appendSection( QNumberSection( 0,0, TRUE, 1 ) );
1938 if ( d->display & Seconds )
1939 d->ed->appendSection( QNumberSection( 0,0, TRUE, 2 ) );
1940 if ( d->display & AMPM )
1941 d->ed->appendSection( QNumberSection( 0,0, FALSE, 3 ) );
1942
1943 d->ed->setFocusSection( 0 );
1944 d->ed->update();
1945}
1946
1947uint QTimeEdit::display() const
1948{
1949 return d->display;
1950}
1951
1952/*!
1953 \property QTimeEdit::time
1954 \brief the editor's time value.
1955
1956 When changing the time property, if the time is less than
1957 minValue(), or is greater than maxValue(), nothing happens.
1958*/
1959
1960void QTimeEdit::setTime( const QTime& time )
1961{
1962 if ( !time.isValid() ) {
1963 d->h = 0;
1964 d->m = 0;
1965 d->s = 0;
1966 } else {
1967 if ( time > maxValue() || time < minValue() )
1968 return;
1969 d->h = time.hour();
1970 d->m = time.minute();
1971 d->s = time.second();
1972 emit valueChanged( time );
1973 }
1974 d->changed = FALSE;
1975 d->ed->repaint( d->ed->rect(), FALSE );
1976}
1977
1978QTime QTimeEdit::time() const
1979{
1980 if ( QTime::isValid( d->h, d->m, d->s ) )
1981 return QTime( d->h, d->m, d->s );
1982 return QTime();
1983}
1984
1985/*!
1986 \property QTimeEdit::autoAdvance
1987 \brief whether the editor automatically advances to the next
1988 section
1989
1990 If autoAdvance is TRUE, the editor will automatically advance
1991 focus to the next time section if a user has completed a section.
1992 The default is FALSE.
1993*/
1994
1995void QTimeEdit::setAutoAdvance( bool advance )
1996{
1997 d->adv = advance;
1998}
1999
2000bool QTimeEdit::autoAdvance() const
2001{
2002 return d->adv;
2003}
2004
2005/*!
2006 Sets the separator to \a s. Note that currently only the first
2007 character of \a s is used.
2008*/
2009
2010void QTimeEdit::setSeparator( const QString& s )
2011{
2012 d->ed->setSeparator( s );
2013}
2014
2015/*!
2016 Returns the editor's separator.
2017*/
2018
2019QString QTimeEdit::separator() const
2020{
2021 return d->ed->separator();
2022}
2023
2024
2025/*!
2026 \fn void QTimeEdit::valueChanged( const QTime& time )
2027
2028 This signal is emitted whenever the editor's value changes. The \a
2029 time parameter is the new value.
2030*/
2031
2032/*! \reimp
2033
2034*/
2035
2036bool QTimeEdit::event( QEvent *e )
2037{
2038 if ( e->type() == QEvent::FocusOut ) {
2039 d->typing = FALSE;
2040 if ( d->changed ) {
2041 emit valueChanged( time() );
2042 d->changed = FALSE;
2043 }
2044 } else if ( e->type() == QEvent::LocaleChange ) {
2045 readLocaleSettings();
2046 d->ed->setSeparator( localTimeSep() );
2047 }
2048 return QDateTimeEditBase::event( e );
2049}
2050
2051/*! \reimp
2052
2053*/
2054
2055void QTimeEdit::timerEvent( QTimerEvent * )
2056{
2057 d->overwrite = TRUE;
2058}
2059
2060
2061/*! \reimp
2062
2063*/
2064
2065void QTimeEdit::stepUp()
2066{
2067 int sec = d->ed->mapSection( d->ed->focusSection() );
2068 bool accepted = TRUE;
2069 switch( sec ) {
2070 case 0:
2071 if ( !outOfRange( d->h+1, d->m, d->s ) )
2072 setHour( d->h+1 );
2073 else
2074 setHour( d->min.hour() );
2075 break;
2076 case 1:
2077 if ( !outOfRange( d->h, d->m+1, d->s ) )
2078 setMinute( d->m+1 );
2079 else
2080 setMinute( d->min.minute() );
2081 break;
2082 case 2:
2083 if ( !outOfRange( d->h, d->m, d->s+1 ) )
2084 setSecond( d->s+1 );
2085 else
2086 setSecond( d->min.second() );
2087 break;
2088 case 3:
2089 if ( d->h < 12 )
2090 setHour( d->h+12 );
2091 else
2092 setHour( d->h-12 );
2093 break;
2094 default:
2095 accepted = FALSE;
2096#ifdef QT_CHECK_RANGE
2097 qWarning( "QTimeEdit::stepUp: Focus section out of range!" );
2098#endif
2099 break;
2100 }
2101 if ( accepted ) {
2102 d->changed = TRUE;
2103 emit valueChanged( time() );
2104 }
2105 d->ed->repaint( d->ed->rect(), FALSE );
2106}
2107
2108
2109/*! \reimp
2110
2111*/
2112
2113void QTimeEdit::stepDown()
2114{
2115 int sec = d->ed->mapSection( d->ed->focusSection() );
2116
2117 bool accepted = TRUE;
2118 switch( sec ) {
2119 case 0:
2120 if ( !outOfRange( d->h-1, d->m, d->s ) )
2121 setHour( d->h-1 );
2122 else
2123 setHour( d->max.hour() );
2124 break;
2125 case 1:
2126 if ( !outOfRange( d->h, d->m-1, d->s ) )
2127 setMinute( d->m-1 );
2128 else
2129 setMinute( d->max.minute() );
2130 break;
2131 case 2:
2132 if ( !outOfRange( d->h, d->m, d->s-1 ) )
2133 setSecond( d->s-1 );
2134 else
2135 setSecond( d->max.second() );
2136 break;
2137 case 3:
2138 if ( d->h > 11 )
2139 setHour( d->h-12 );
2140 else
2141 setHour( d->h+12 );
2142 break;
2143 default:
2144 accepted = FALSE;
2145#ifdef QT_CHECK_RANGE
2146 qWarning( "QTimeEdit::stepDown: Focus section out of range!" );
2147#endif
2148 break;
2149 }
2150 if ( accepted ) {
2151 d->changed = TRUE;
2152 emit valueChanged( time() );
2153 }
2154 d->ed->repaint( d->ed->rect(), FALSE );
2155}
2156
2157
2158/*!
2159 Returns the formatted number for section \a sec. This will
2160 correspond to either the hour, minute or second section, depending
2161 on \a sec.
2162*/
2163
2164QString QTimeEdit::sectionFormattedText( int sec )
2165{
2166 QString txt;
2167 txt = sectionText( sec );
2168 txt = txt.rightJustify( 2, QDATETIMEEDIT_HIDDEN_CHAR );
2169 int offset = sec*2+sec*separator().length() + txt.length();
2170 if ( d->typing && sec == d->ed->focusSection() )
2171 d->ed->setSectionSelection( sec, offset - txt.length(), offset );
2172 else
2173 d->ed->setSectionSelection( sec, offset - txt.length(), offset );
2174
2175 return txt;
2176}
2177
2178
2179/*! \reimp
2180
2181*/
2182
2183bool QTimeEdit::setFocusSection( int sec )
2184{
2185 if ( sec != d->ed->focusSection() ) {
2186 killTimer( d->timerId );
2187 d->overwrite = TRUE;
2188 d->typing = FALSE;
2189 QString txt = sectionText( sec );
2190 txt = txt.rightJustify( 2, QDATETIMEEDIT_HIDDEN_CHAR );
2191 int offset = sec*2+sec*separator().length() + txt.length();
2192 d->ed->setSectionSelection( sec, offset - txt.length(), offset );
2193 if ( d->changed ) {
2194 emit valueChanged( time() );
2195 d->changed = FALSE;
2196 }
2197 }
2198 return d->ed->setFocusSection( sec );
2199}
2200
2201
2202/*!
2203 Sets the hour to \a h, which must be a valid hour, i.e. in the
2204 range 0..24.
2205*/
2206
2207void QTimeEdit::setHour( int h )
2208{
2209 if ( h < 0 )
2210 h = 0;
2211 if ( h > 23 )
2212 h = 23;
2213 d->h = h;
2214}
2215
2216
2217/*!
2218 Sets the minute to \a m, which must be a valid minute, i.e. in the
2219 range 0..59.
2220*/
2221
2222void QTimeEdit::setMinute( int m )
2223{
2224 if ( m < 0 )
2225 m = 0;
2226 if ( m > 59 )
2227 m = 59;
2228 d->m = m;
2229}
2230
2231
2232/*!
2233 Sets the second to \a s, which must be a valid second, i.e. in the
2234 range 0..59.
2235*/
2236
2237void QTimeEdit::setSecond( int s )
2238{
2239 if ( s < 0 )
2240 s = 0;
2241 if ( s > 59 )
2242 s = 59;
2243 d->s = s;
2244}
2245
2246
2247/*! \internal
2248
2249 Returns the text of section \a sec.
2250
2251*/
2252
2253QString QTimeEdit::sectionText( int sec )
2254{
2255 sec = d->ed->mapSection( sec );
2256
2257 QString txt;
2258 switch( sec ) {
2259 case 0:
2260 if ( !(d->display & AMPM) || ( d->h < 13 && d->h ) ) { // I wished the day stared at 0:00 for everybody
2261 txt = QString::number( d->h );
2262 } else {
2263 if ( d->h )
2264 txt = QString::number( d->h - 12 );
2265 else
2266 txt = "12";
2267 }
2268 break;
2269 case 1:
2270 txt = QString::number( d->m );
2271 break;
2272 case 2:
2273 txt = QString::number( d->s );
2274 break;
2275 case 3:
2276 if ( d->h < 12 ) {
2277 if ( lAM )
2278 txt = *lAM;
2279 else
2280 txt = QString::fromLatin1( "AM" );
2281 } else {
2282 if ( lPM )
2283 txt = *lPM;
2284 else
2285 txt = QString::fromLatin1( "PM" );
2286 }
2287 break;
2288 default:
2289 break;
2290 }
2291 return txt;
2292}
2293
2294
2295/*! \internal
2296 Returns TRUE if \a h, \a m, and \a s are out of range.
2297 */
2298
2299bool QTimeEdit::outOfRange( int h, int m, int s ) const
2300{
2301 if ( QTime::isValid( h, m, s ) ) {
2302 QTime currentTime( h, m, s );
2303 if ( currentTime > maxValue() ||
2304 currentTime < minValue() )
2305 return TRUE;
2306 else
2307 return FALSE;
2308 }
2309 return TRUE;
2310}
2311
2312/*! \reimp
2313
2314*/
2315
2316void QTimeEdit::addNumber( int sec, int num )
2317{
2318 if ( sec == -1 )
2319 return;
2320 sec = d->ed->mapSection( sec );
2321 killTimer( d->timerId );
2322 bool overwrite = FALSE;
2323 bool accepted = FALSE;
2324 d->typing = TRUE;
2325 QString txt;
2326
2327 switch( sec ) {
2328 case 0:
2329 txt = ( d->display & AMPM && d->h > 12 ) ?
2330 QString::number( d->h - 12 ) : QString::number( d->h );
2331
2332 if ( d->overwrite || txt.length() == 2 ) {
2333 if ( d->display & AMPM && num == 0 )
2334 break; // Don't process 0 in 12 hour clock mode
2335 if ( d->display & AMPM && d->h > 11 )
2336 num += 12;
2337 if ( !outOfRange( num, d->m, d->s ) ) {
2338 accepted = TRUE;
2339 d->h = num;
2340 }
2341 } else {
2342 txt += QString::number( num );
2343 int temp = txt.toInt();
2344
2345 if ( d->display & AMPM ) {
2346 if ( temp == 12 ) {
2347 if ( d->h < 12 ) {
2348 temp = 0;
2349 }
2350 accepted = TRUE;
2351 } else if ( outOfRange( temp + 12, d->m, d->s ) ) {
2352 txt = QString::number( d->h );
2353 } else {
2354 if ( d->h > 11 ) {
2355 temp += 12;
2356 }
2357 accepted = TRUE;
2358 }
2359 } else if ( !(d->display & AMPM) && outOfRange( temp, d->m, d->s ) ) {
2360 txt = QString::number( d->h );
2361 } else {
2362 accepted = TRUE;
2363 }
2364
2365 if ( accepted )
2366 d->h = temp;
2367
2368 if ( d->adv && txt.length() == 2 ) {
2369 setFocusSection( d->ed->focusSection()+1 );
2370 overwrite = TRUE;
2371 }
2372 }
2373 break;
2374
2375 case 1:
2376 txt = QString::number( d->m );
2377 if ( d->overwrite || txt.length() == 2 ) {
2378 if ( !outOfRange( d->h, num, d->s ) ) {
2379 accepted = TRUE;
2380 d->m = num;
2381 }
2382 } else {
2383 txt += QString::number( num );
2384 int temp = txt.toInt();
2385 if ( temp > 59 )
2386 temp = num;
2387 if ( outOfRange( d->h, temp, d->s ) )
2388 txt = QString::number( d->m );
2389 else {
2390 accepted = TRUE;
2391 d->m = temp;
2392 }
2393 if ( d->adv && txt.length() == 2 ) {
2394 setFocusSection( d->ed->focusSection()+1 );
2395 overwrite = TRUE;
2396 }
2397 }
2398 break;
2399
2400 case 2:
2401 txt = QString::number( d->s );
2402 if ( d->overwrite || txt.length() == 2 ) {
2403 if ( !outOfRange( d->h, d->m, num ) ) {
2404 accepted = TRUE;
2405 d->s = num;
2406 }
2407 } else {
2408 txt += QString::number( num );
2409 int temp = txt.toInt();
2410 if ( temp > 59 )
2411 temp = num;
2412 if ( outOfRange( d->h, d->m, temp ) )
2413 txt = QString::number( d->s );
2414 else {
2415 accepted = TRUE;
2416 d->s = temp;
2417 }
2418 if ( d->adv && txt.length() == 2 ) {
2419 setFocusSection( d->ed->focusSection()+1 );
2420 overwrite = TRUE;
2421 }
2422 }
2423 break;
2424
2425 case 3:
2426 break;
2427
2428 default:
2429 break;
2430 }
2431 d->changed = accepted;
2432 if ( accepted )
2433 emit valueChanged( time() );
2434 d->overwrite = overwrite;
2435 d->timerId = startTimer( qApp->doubleClickInterval()*4 );
2436 d->ed->repaint( d->ed->rect(), FALSE );
2437}
2438
2439
2440/*!
2441 \internal
2442
2443 Function which is called whenever the user tries to
2444 remove the first number from \a sec by pressing the backspace key.
2445*/
2446
2447void QTimeEdit::removeFirstNumber( int sec )
2448{
2449 if ( sec == -1 )
2450 return;
2451 sec = d->ed->mapSection( sec );
2452 QString txt;
2453 switch( sec ) {
2454 case 0:
2455 txt = QString::number( d->h );
2456 break;
2457 case 1:
2458 txt = QString::number( d->m );
2459 break;
2460 case 2:
2461 txt = QString::number( d->s );
2462 break;
2463 }
2464 txt = txt.mid( 1, txt.length() ) + "0";
2465 switch( sec ) {
2466 case 0:
2467 d->h = txt.toInt();
2468 break;
2469 case 1:
2470 d->m = txt.toInt();
2471 break;
2472 case 2:
2473 d->s = txt.toInt();
2474 break;
2475 }
2476 d->ed->repaint( d->ed->rect(), FALSE );
2477}
2478
2479/*! \reimp
2480
2481*/
2482void QTimeEdit::removeLastNumber( int sec )
2483{
2484 if ( sec == -1 )
2485 return;
2486 sec = d->ed->mapSection( sec );
2487 QString txt;
2488 switch( sec ) {
2489 case 0:
2490 txt = QString::number( d->h );
2491 break;
2492 case 1:
2493 txt = QString::number( d->m );
2494 break;
2495 case 2:
2496 txt = QString::number( d->s );
2497 break;
2498 }
2499 txt = txt.mid( 0, txt.length()-1 );
2500 switch( sec ) {
2501 case 0:
2502 d->h = txt.toInt();
2503 break;
2504 case 1:
2505 d->m = txt.toInt();
2506 break;
2507 case 2:
2508 d->s = txt.toInt();
2509 break;
2510 }
2511 d->ed->repaint( d->ed->rect(), FALSE );
2512}
2513
2514/*! \reimp
2515 */
2516void QTimeEdit::resizeEvent( QResizeEvent * )
2517{
2518 d->controls->resize( width(), height() );
2519}
2520
2521/*! \reimp
2522*/
2523QSize QTimeEdit::sizeHint() const
2524{
2525 constPolish();
2526 QFontMetrics fm( font() );
2527 int fw = style().pixelMetric( QStyle::PM_DefaultFrameWidth, this );
2528 int h = fm.lineSpacing() + 2;
2529 int w = 2 + fm.width( '9' ) * 6 + fm.width( d->ed->separator() ) * 2 +
2530 d->controls->upRect().width() + fw * 4;
2531 if ( d->display & AMPM ) {
2532 if ( lAM )
2533 w += fm.width( *lAM ) + 4;
2534 else
2535 w += fm.width( QString::fromLatin1( "AM" ) ) + 4;
2536 }
2537
2538 return QSize( w, QMAX(h + fw * 2,20) ).expandedTo( QApplication::globalStrut() );
2539}
2540
2541/*! \reimp
2542*/
2543QSize QTimeEdit::minimumSizeHint() const
2544{
2545 return sizeHint();
2546}
2547
2548/*!
2549 \internal
2550 Enables/disables the push buttons according to the min/max time
2551 for this widget.
2552*/
2553
2554// ### Remove in 4.0?
2555
2556void QTimeEdit::updateButtons()
2557{
2558 if ( !isEnabled() )
2559 return;
2560
2561 bool upEnabled = time() < maxValue();
2562 bool downEnabled = time() > minValue();
2563
2564 d->controls->setUpEnabled( upEnabled );
2565 d->controls->setDownEnabled( downEnabled );
2566}
2567
2568
2569class QDateTimeEditPrivate
2570{
2571public:
2572 bool adv;
2573};
2574
2575/*!
2576 \class QDateTimeEdit qdatetimeedit.h
2577 \brief The QDateTimeEdit class combines a QDateEdit and QTimeEdit
2578 widget into a single widget for editing datetimes.
2579
2580 \ingroup advanced
2581 \ingroup time
2582 \mainclass
2583
2584 QDateTimeEdit consists of a QDateEdit and QTimeEdit widget placed
2585 side by side and offers the functionality of both. The user can
2586 edit the date and time by using the keyboard or the arrow keys to
2587 increase/decrease date or time values. The Tab key can be used to
2588 move from section to section within the QDateTimeEdit widget, and
2589 the user can be moved automatically when they complete a section
2590 using setAutoAdvance(). The datetime can be set with
2591 setDateTime().
2592
2593 The date format is read from the system's locale settings. It is
2594 set to year, month, day order if that is not possible. See
2595 QDateEdit::setOrder() to change this. Times appear in the order
2596 hours, minutes, seconds using the 24 hour clock.
2597
2598 It is recommended that the QDateTimeEdit is initialised with a
2599 datetime, e.g.
2600 \code
2601 QDateTimeEdit *dateTimeEdit = new QDateTimeEdit( QDateTime::currentDateTime(), this );
2602 dateTimeEdit->dateEdit()->setRange( QDateTime::currentDate(),
2603 QDateTime::currentDate().addDays( 7 ) );
2604 \endcode
2605 Here we've created a new QDateTimeEdit set to the current date and
2606 time, and set the date to have a minimum date of now and a maximum
2607 date of a week from now.
2608
2609 Terminology: A QDateEdit widget consists of three 'sections', one
2610 each for the year, month and day. Similarly a QTimeEdit consists
2611 of three sections, one each for the hour, minute and second. The
2612 character that separates each date section is specified with
2613 setDateSeparator(); similarly setTimeSeparator() is used for the
2614 time sections.
2615
2616 \img datetimewidgets.png Date Time Widgets
2617
2618 \sa QDateEdit QTimeEdit
2619*/
2620
2621/*!
2622 Constructs an empty datetime edit with parent \a parent and called
2623 \a name.
2624*/
2625QDateTimeEdit::QDateTimeEdit( QWidget * parent, const char * name )
2626 : QWidget( parent, name )
2627{
2628 init();
2629}
2630
2631
2632/*!
2633 \overload
2634
2635 Constructs a datetime edit with the initial value \a datetime,
2636 parent \a parent and called \a name.
2637*/
2638QDateTimeEdit::QDateTimeEdit( const QDateTime& datetime,
2639 QWidget * parent, const char * name )
2640 : QWidget( parent, name )
2641{
2642 init();
2643 setDateTime( datetime );
2644}
2645
2646
2647
2648/*!
2649 Destroys the object and frees any allocated resources.
2650*/
2651
2652QDateTimeEdit::~QDateTimeEdit()
2653{
2654 delete d;
2655}
2656
2657
2658/*!
2659 \reimp
2660
2661 Intercepts and handles resize events which have special meaning
2662 for the QDateTimeEdit.
2663*/
2664
2665void QDateTimeEdit::resizeEvent( QResizeEvent * )
2666{
2667 int dw = de->sizeHint().width();
2668 int tw = te->sizeHint().width();
2669 int w = width();
2670 int h = height();
2671 int extra = w - ( dw + tw );
2672
2673 if ( tw + extra < 0 ) {
2674 dw = w;
2675 } else {
2676 dw += 9 * extra / 16;
2677 }
2678 tw = w - dw;
2679
2680 de->setGeometry( 0, 0, dw, h );
2681 te->setGeometry( dw, 0, tw, h );
2682}
2683
2684/*! \reimp
2685*/
2686
2687QSize QDateTimeEdit::minimumSizeHint() const
2688{
2689 QSize dsh = de->minimumSizeHint();
2690 QSize tsh = te->minimumSizeHint();
2691 return QSize( dsh.width() + tsh.width(),
2692 QMAX( dsh.height(), tsh.height() ) );
2693}
2694
2695/*! \internal
2696 */
2697
2698void QDateTimeEdit::init()
2699{
2700 d = new QDateTimeEditPrivate();
2701 de = new QDateEdit( this, "qt_datetime_dateedit" );
2702 te = new QTimeEdit( this, "qt_datetime_timeedit" );
2703 d->adv = FALSE;
2704 connect( de, SIGNAL( valueChanged(const QDate&) ),
2705 this, SLOT( newValue(const QDate&) ) );
2706 connect( te, SIGNAL( valueChanged(const QTime&) ),
2707 this, SLOT( newValue(const QTime&) ) );
2708 setFocusProxy( de );
2709 setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
2710}
2711
2712/*! \reimp
2713 */
2714
2715QSize QDateTimeEdit::sizeHint() const
2716{
2717 constPolish();
2718 QSize dsh = de->sizeHint();
2719 QSize tsh = te->sizeHint();
2720 return QSize( dsh.width() + tsh.width(),
2721 QMAX( dsh.height(), tsh.height() ) );
2722}
2723
2724/*!
2725 \property QDateTimeEdit::dateTime
2726 \brief the editor's datetime value
2727
2728 The datetime edit's datetime which may be an invalid datetime.
2729*/
2730
2731void QDateTimeEdit::setDateTime( const QDateTime & dt )
2732{
2733 if ( dt.isValid() ) {
2734 de->setDate( dt.date() );
2735 te->setTime( dt.time() );
2736 emit valueChanged( dt );
2737 }
2738}
2739
2740QDateTime QDateTimeEdit::dateTime() const
2741{
2742 return QDateTime( de->date(), te->time() );
2743}
2744
2745/*!
2746 \fn void QDateTimeEdit::valueChanged( const QDateTime& datetime )
2747
2748 This signal is emitted every time the date or time changes. The \a
2749 datetime argument is the new datetime.
2750*/
2751
2752
2753/*! \internal
2754
2755 Re-emits the value \a d.
2756 */
2757
2758void QDateTimeEdit::newValue( const QDate& )
2759{
2760 QDateTime dt = dateTime();
2761 emit valueChanged( dt );
2762}
2763
2764/*! \internal
2765 \overload
2766 Re-emits the value \a t.
2767 */
2768
2769void QDateTimeEdit::newValue( const QTime& )
2770{
2771 QDateTime dt = dateTime();
2772 emit valueChanged( dt );
2773}
2774
2775
2776/*!
2777 Sets the auto advance property of the editor to \a advance. If set
2778 to TRUE, the editor will automatically advance focus to the next
2779 date or time section if the user has completed a section.
2780*/
2781
2782void QDateTimeEdit::setAutoAdvance( bool advance )
2783{
2784 de->setAutoAdvance( advance );
2785 te->setAutoAdvance( advance );
2786}
2787
2788/*!
2789 Returns TRUE if auto-advance is enabled, otherwise returns FALSE.
2790
2791 \sa setAutoAdvance()
2792*/
2793
2794bool QDateTimeEdit::autoAdvance() const
2795{
2796 return de->autoAdvance();
2797}
2798
2799/*!
2800 \fn QDateEdit* QDateTimeEdit::dateEdit()
2801
2802 Returns the internal widget used for editing the date part of the
2803 datetime.
2804*/
2805
2806/*!
2807 \fn QTimeEdit* QDateTimeEdit::timeEdit()
2808
2809 Returns the internal widget used for editing the time part of the
2810 datetime.
2811*/
2812
2813#include "qdatetimeedit.moc"
2814
2815#endif
Note: See TracBrowser for help on using the repository browser.