source: trunk/src/widgets/qdatetimeedit.cpp@ 174

Last change on this file since 174 was 174, checked in by dmik, 18 years ago

Styles: Implemented the first version of the Warp4 style (contributed by Cornelis Bockemuehl).

  • Property svn:keywords set to Id
File size: 65.5 KB
Line 
1/****************************************************************************
2** $Id: qdatetimeedit.cpp 174 2007-11-06 22:27:57Z 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 );
1084 if ( style().styleHint( QStyle::SH_GUIStyle ) != QStyle::PMStyle )
1085 h += 2;
1086 int w = 2 + fm.width( '9' ) * 8 + fm.width( d->ed->separator() ) * 2 + d->controls->upRect().width() + fw * 4;
1087
1088 return QSize( w, QMAX(h + fw * 2, 20) ).expandedTo( QApplication::globalStrut() );
1089}
1090
1091/*! \reimp
1092
1093*/
1094QSize QDateEdit::minimumSizeHint() const
1095{
1096 return sizeHint();
1097}
1098
1099
1100/*!
1101 Returns the formatted number for section \a sec. This will
1102 correspond to either the year, month or day section, depending on
1103 the current display order.
1104
1105 \sa setOrder()
1106*/
1107
1108QString QDateEdit::sectionFormattedText( int sec )
1109{
1110 QString txt;
1111 txt = sectionText( sec );
1112 if ( d->typing && sec == d->ed->focusSection() )
1113 d->ed->setSectionSelection( sec, sectionOffsetEnd( sec ) - txt.length(),
1114 sectionOffsetEnd( sec ) );
1115 else
1116 d->ed->setSectionSelection( sec, sectionOffsetEnd( sec ) - sectionLength( sec ),
1117 sectionOffsetEnd( sec ) );
1118 txt = txt.rightJustify( sectionLength( sec ), QDATETIMEEDIT_HIDDEN_CHAR );
1119 return txt;
1120}
1121
1122
1123/*!
1124 Returns the desired length (number of digits) of section \a sec.
1125 This will correspond to either the year, month or day section,
1126 depending on the current display order.
1127
1128 \sa setOrder()
1129*/
1130
1131int QDateEdit::sectionLength( int sec ) const
1132{
1133 int val = 0;
1134 if ( sec == d->yearSection ) {
1135 val = 4;
1136 } else if ( sec == d->monthSection ) {
1137 val = 2;
1138 } else if ( sec == d->daySection ) {
1139 val = 2;
1140 }
1141 return val;
1142}
1143
1144/*!
1145 Returns the text of section \a sec. This will correspond to either
1146 the year, month or day section, depending on the current display
1147 order.
1148
1149 \sa setOrder()
1150*/
1151
1152QString QDateEdit::sectionText( int sec ) const
1153{
1154 int val = 0;
1155 if ( sec == d->yearSection ) {
1156 val = d->y;
1157 } else if ( sec == d->monthSection ) {
1158 val = d->m;
1159 } else if ( sec == d->daySection ) {
1160 val = d->d;
1161 }
1162 return QString::number( val );
1163}
1164
1165/*! \internal
1166
1167 Returns the end of the section offset \a sec.
1168
1169*/
1170
1171int QDateEdit::sectionOffsetEnd( int sec ) const
1172{
1173 if ( sec == d->yearSection ) {
1174 switch( d->ord ) {
1175 case DMY:
1176 case MDY:
1177 return sectionOffsetEnd( sec-1) + separator().length() + sectionLength( sec );
1178 case YMD:
1179 case YDM:
1180 return sectionLength( sec );
1181 }
1182 } else if ( sec == d->monthSection ) {
1183 switch( d->ord ) {
1184 case DMY:
1185 case YDM:
1186 case YMD:
1187 return sectionOffsetEnd( sec-1) + separator().length() + sectionLength( sec );
1188 case MDY:
1189 return sectionLength( sec );
1190 }
1191 } else if ( sec == d->daySection ) {
1192 switch( d->ord ) {
1193 case DMY:
1194 return sectionLength( sec );
1195 case YMD:
1196 case MDY:
1197 case YDM:
1198 return sectionOffsetEnd( sec-1 ) + separator().length() + sectionLength( sec );
1199 }
1200 }
1201 return 0;
1202}
1203
1204
1205/*!
1206 \property QDateEdit::order
1207 \brief the order in which the year, month and day appear
1208
1209 The default order is locale dependent.
1210
1211 \sa Order
1212*/
1213
1214void QDateEdit::setOrder( QDateEdit::Order order )
1215{
1216 d->ord = order;
1217 switch( d->ord ) {
1218 case DMY:
1219 d->yearSection = 2;
1220 d->monthSection = 1;
1221 d->daySection = 0;
1222 break;
1223 case MDY:
1224 d->yearSection = 2;
1225 d->monthSection = 0;
1226 d->daySection = 1;
1227 break;
1228 case YMD:
1229 d->yearSection = 0;
1230 d->monthSection = 1;
1231 d->daySection = 2;
1232 break;
1233 case YDM:
1234 d->yearSection = 0;
1235 d->monthSection = 2;
1236 d->daySection = 1;
1237 break;
1238 }
1239 if ( isVisible() )
1240 d->ed->repaint( d->ed->rect(), FALSE );
1241}
1242
1243
1244QDateEdit::Order QDateEdit::order() const
1245{
1246 return d->ord;
1247}
1248
1249
1250/*! \reimp
1251
1252*/
1253void QDateEdit::stepUp()
1254{
1255 int sec = d->ed->focusSection();
1256 bool accepted = FALSE;
1257 if ( sec == d->yearSection ) {
1258 if ( !outOfRange( d->y+1, d->m, d->d ) ) {
1259 accepted = TRUE;
1260 setYear( d->y+1 );
1261 }
1262 } else if ( sec == d->monthSection ) {
1263 if ( !outOfRange( d->y, d->m+1, d->d ) ) {
1264 accepted = TRUE;
1265 setMonth( d->m+1 );
1266 }
1267 } else if ( sec == d->daySection ) {
1268 if ( !outOfRange( d->y, d->m, d->d+1 ) ) {
1269 accepted = TRUE;
1270 setDay( d->d+1 );
1271 }
1272 }
1273 if ( accepted ) {
1274 d->changed = TRUE;
1275 emit valueChanged( date() );
1276 }
1277 d->ed->repaint( d->ed->rect(), FALSE );
1278}
1279
1280
1281
1282/*! \reimp
1283
1284*/
1285
1286void QDateEdit::stepDown()
1287{
1288 int sec = d->ed->focusSection();
1289 bool accepted = FALSE;
1290 if ( sec == d->yearSection ) {
1291 if ( !outOfRange( d->y-1, d->m, d->d ) ) {
1292 accepted = TRUE;
1293 setYear( d->y-1 );
1294 }
1295 } else if ( sec == d->monthSection ) {
1296 if ( !outOfRange( d->y, d->m-1, d->d ) ) {
1297 accepted = TRUE;
1298 setMonth( d->m-1 );
1299 }
1300 } else if ( sec == d->daySection ) {
1301 if ( !outOfRange( d->y, d->m, d->d-1 ) ) {
1302 accepted = TRUE;
1303 setDay( d->d-1 );
1304 }
1305 }
1306 if ( accepted ) {
1307 d->changed = TRUE;
1308 emit valueChanged( date() );
1309 }
1310 d->ed->repaint( d->ed->rect(), FALSE );
1311}
1312
1313/*!
1314 Sets the year to \a year, which must be a valid year. The range
1315 currently supported is from 1752 to 8000.
1316
1317 \sa QDate
1318*/
1319
1320void QDateEdit::setYear( int year )
1321{
1322 if ( year < 1752 )
1323 year = 1752;
1324 if ( year > 8000 )
1325 year = 8000;
1326 if ( !outOfRange( year, d->m, d->d ) ) {
1327 d->y = year;
1328 setMonth( d->m );
1329 int tmp = d->dayCache;
1330 setDay( d->dayCache );
1331 d->dayCache = tmp;
1332 }
1333}
1334
1335
1336/*!
1337 Sets the month to \a month, which must be a valid month, i.e.
1338 between 1 and 12.
1339*/
1340
1341void QDateEdit::setMonth( int month )
1342{
1343 if ( month < 1 )
1344 month = 1;
1345 if ( month > 12 )
1346 month = 12;
1347 if ( !outOfRange( d->y, month, d->d ) ) {
1348 d->m = month;
1349 int tmp = d->dayCache;
1350 setDay( d->dayCache );
1351 d->dayCache = tmp;
1352 }
1353}
1354
1355
1356/*!
1357 Sets the day to \a day, which must be a valid day. The function
1358 will ensure that the \a day set is valid for the month and year.
1359*/
1360
1361void QDateEdit::setDay( int day )
1362{
1363 if ( day < 1 )
1364 day = 1;
1365 if ( day > 31 )
1366 day = 31;
1367 if ( d->m > 0 && d->y > 1752 ) {
1368 while ( !QDate::isValid( d->y, d->m, day ) )
1369 --day;
1370 if ( !outOfRange( d->y, d->m, day ) )
1371 d->d = day;
1372 } else if ( d->m > 0 ) {
1373 if ( day > 0 && day < 32 ) {
1374 if ( !outOfRange( d->y, d->m, day ) )
1375 d->d = day;
1376 }
1377 }
1378 d->dayCache = d->d;
1379}
1380
1381
1382/*!
1383 \property QDateEdit::date
1384 \brief the editor's date value.
1385
1386 If the date property is not valid, the editor displays all zeroes
1387 and QDateEdit::date() will return an invalid date. It is strongly
1388 recommended that the editor is given a default date value (e.g.
1389 currentDate()). That way, attempts to set the date property to an
1390 invalid date will fail.
1391
1392 When changing the date property, if the date is less than
1393 minValue(), or is greater than maxValue(), nothing happens.
1394*/
1395
1396void QDateEdit::setDate( const QDate& date )
1397{
1398 if ( !date.isValid() ) {
1399 d->y = 0;
1400 d->m = 0;
1401 d->d = 0;
1402 d->dayCache = 0;
1403 } else {
1404 if ( date > maxValue() || date < minValue() )
1405 return;
1406 d->y = date.year();
1407 d->m = date.month();
1408 d->d = date.day();
1409 d->dayCache = d->d;
1410 emit valueChanged( date );
1411 }
1412 d->changed = FALSE;
1413 d->ed->repaint( d->ed->rect(), FALSE );
1414}
1415
1416QDate QDateEdit::date() const
1417{
1418 if ( QDate::isValid( d->y, d->m, d->d ) )
1419 return QDate( d->y, d->m, d->d );
1420 return QDate();
1421}
1422
1423/*! \internal
1424
1425 Returns TRUE if \a y, \a m, \a d is out of range, otherwise returns
1426 FALSE.
1427
1428 \sa setRange()
1429
1430*/
1431
1432bool QDateEdit::outOfRange( int y, int m, int d ) const
1433{
1434 if ( QDate::isValid( y, m, d ) ) {
1435 QDate currentDate( y, m, d );
1436 if ( currentDate > maxValue() ||
1437 currentDate < minValue() ) {
1438 //## outOfRange should set overwrite?
1439 return TRUE;
1440 }
1441 return FALSE;
1442 }
1443 return FALSE; /* assume ok */
1444}
1445
1446/*! \reimp
1447
1448*/
1449
1450void QDateEdit::addNumber( int sec, int num )
1451{
1452 if ( sec == -1 )
1453 return;
1454 killTimer( d->timerId );
1455 bool overwrite = FALSE;
1456 bool accepted = FALSE;
1457 d->typing = TRUE;
1458 QString txt;
1459 if ( sec == d->yearSection ) {
1460 txt = QString::number( d->y );
1461 if ( d->overwrite || txt.length() == 4 ) {
1462 accepted = TRUE;
1463 d->y = num;
1464 } else {
1465 txt += QString::number( num );
1466 if ( txt.length() == 4 ) {
1467 int val = txt.toInt();
1468 if ( val < 1792 )
1469 d->y = 1792;
1470 else if ( val > 8000 )
1471 d->y = 8000;
1472 else if ( outOfRange( val, d->m, d->d ) )
1473 txt = QString::number( d->y );
1474 else {
1475 accepted = TRUE;
1476 d->y = val;
1477 }
1478 } else {
1479 accepted = TRUE;
1480 d->y = txt.toInt();
1481 }
1482 if ( d->adv && txt.length() == 4 ) {
1483 d->ed->setFocusSection( d->ed->focusSection()+1 );
1484 overwrite = TRUE;
1485 }
1486 }
1487 } else if ( sec == d->monthSection ) {
1488 txt = QString::number( d->m );
1489 if ( d->overwrite || txt.length() == 2 ) {
1490 accepted = TRUE;
1491 d->m = num;
1492 } else {
1493 txt += QString::number( num );
1494 int temp = txt.toInt();
1495 if ( temp > 12 )
1496 temp = num;
1497 if ( outOfRange( d->y, temp, d->d ) )
1498 txt = QString::number( d->m );
1499 else {
1500 accepted = TRUE;
1501 d->m = temp;
1502 }
1503 if ( d->adv && txt.length() == 2 ) {
1504 d->ed->setFocusSection( d->ed->focusSection()+1 );
1505 overwrite = TRUE;
1506 }
1507 }
1508 } else if ( sec == d->daySection ) {
1509 txt = QString::number( d->d );
1510 if ( d->overwrite || txt.length() == 2 ) {
1511 accepted = TRUE;
1512 d->d = num;
1513 d->dayCache = d->d;
1514 } else {
1515 txt += QString::number( num );
1516 int temp = txt.toInt();
1517 if ( temp > 31 )
1518 temp = num;
1519 if ( outOfRange( d->y, d->m, temp ) )
1520 txt = QString::number( d->d );
1521 else {
1522 accepted = TRUE;
1523 d->d = temp;
1524 d->dayCache = d->d;
1525 }
1526 if ( d->adv && txt.length() == 2 ) {
1527 d->ed->setFocusSection( d->ed->focusSection()+1 );
1528 overwrite = TRUE;
1529 }
1530 }
1531 }
1532 if ( accepted ) {
1533 d->changed = TRUE;
1534 emit valueChanged( date() );
1535 }
1536 d->overwrite = overwrite;
1537 d->timerId = startTimer( qApp->doubleClickInterval()*4 );
1538 d->ed->repaint( d->ed->rect(), FALSE );
1539}
1540
1541
1542/*! \reimp
1543
1544*/
1545
1546bool QDateEdit::setFocusSection( int s )
1547{
1548 if ( s != d->ed->focusSection() ) {
1549 killTimer( d->timerId );
1550 d->overwrite = TRUE;
1551 d->typing = FALSE;
1552 fix(); // will emit valueChanged if necessary
1553 }
1554 return d->ed->setFocusSection( s );
1555}
1556
1557
1558/*!
1559 Attempts to fix any invalid date entries.
1560
1561 The rules applied are as follows:
1562
1563 \list
1564 \i If the year has four digits it is left unchanged.
1565 \i If the year has two digits, the year will be changed to four
1566 digits in the range current year - 70 to current year + 29.
1567 \i If the year has three digits in the range 100..999, the
1568 current millennium, i.e. 2000, will be added giving a year
1569 in the range 2100..2999.
1570 \endlist
1571
1572*/
1573
1574void QDateEdit::fix()
1575{
1576 bool changed = FALSE;
1577 int currentYear = QDate::currentDate().year();
1578 int year = d->y;
1579 if ( year < 100 ) {
1580 int currentCentury = currentYear / 100;
1581 year += currentCentury * 100;
1582 if ( currentYear > year ) {
1583 if ( currentYear > year + 70 )
1584 year += 100;
1585 } else {
1586 if ( year >= currentYear + 30 )
1587 year -= 100;
1588 }
1589 changed = TRUE;
1590 } else if ( year < 1000 ) {
1591 int currentMillennium = currentYear / 10;
1592 year += currentMillennium * 10;
1593 changed = TRUE;
1594 }
1595 if ( changed && outOfRange( year, d->m, d->d ) ) {
1596 if ( minValue().isValid() && date() < minValue() ) {
1597 d->d = minValue().day();
1598 d->dayCache = d->d;
1599 d->m = minValue().month();
1600 d->y = minValue().year();
1601 }
1602 if ( date() > maxValue() ) {
1603 d->d = maxValue().day();
1604 d->dayCache = d->d;
1605 d->m = maxValue().month();
1606 d->y = maxValue().year();
1607 }
1608 } else if ( changed )
1609 setYear( year );
1610 if ( changed ) {
1611 emit valueChanged( date() );
1612 d->changed = FALSE;
1613 }
1614}
1615
1616
1617/*! \reimp
1618
1619*/
1620
1621bool QDateEdit::event( QEvent *e )
1622{
1623 if( e->type() == QEvent::FocusOut ) {
1624 d->typing = FALSE;
1625 fix();
1626 // the following can't be done in fix() because fix() called
1627 // from all over the place and it will break the old behaviour
1628 if ( !QDate::isValid( d->y, d->m, d->d ) ) {
1629 d->dayCache = d->d;
1630 int i = d->d;
1631 for ( ; i > 0; i-- ) {
1632 d->d = i;
1633 if ( QDate::isValid( d->y, d->m, d->d ) )
1634 break;
1635 }
1636 d->changed = TRUE;
1637 }
1638 if ( d->changed ) {
1639 emit valueChanged( date() );
1640 d->changed = FALSE;
1641 }
1642 } else if ( e->type() == QEvent::LocaleChange ) {
1643 readLocaleSettings();
1644 d->ed->setSeparator( localDateSep() );
1645 setOrder( localOrder() );
1646 }
1647 return QDateTimeEditBase::event( e );
1648}
1649
1650/*!
1651 \internal
1652
1653 Function which is called whenever the user tries to
1654 remove the first number from \a sec by pressing the backspace key.
1655*/
1656
1657void QDateEdit::removeFirstNumber( int sec )
1658{
1659 if ( sec == -1 )
1660 return;
1661 QString txt;
1662 if ( sec == d->yearSection ) {
1663 txt = QString::number( d->y );
1664 txt = txt.mid( 1, txt.length() ) + "0";
1665 d->y = txt.toInt();
1666 } else if ( sec == d->monthSection ) {
1667 txt = QString::number( d->m );
1668 txt = txt.mid( 1, txt.length() ) + "0";
1669 d->m = txt.toInt();
1670 } else if ( sec == d->daySection ) {
1671 txt = QString::number( d->d );
1672 txt = txt.mid( 1, txt.length() ) + "0";
1673 d->d = txt.toInt();
1674 d->dayCache = d->d;
1675 }
1676 d->ed->repaint( d->ed->rect(), FALSE );
1677}
1678
1679/*! \reimp
1680
1681*/
1682
1683void QDateEdit::removeLastNumber( int sec )
1684{
1685 if ( sec == -1 )
1686 return;
1687 QString txt;
1688 if ( sec == d->yearSection ) {
1689 txt = QString::number( d->y );
1690 txt = txt.mid( 0, txt.length()-1 );
1691 d->y = txt.toInt();
1692 } else if ( sec == d->monthSection ) {
1693 txt = QString::number( d->m );
1694 txt = txt.mid( 0, txt.length()-1 );
1695 d->m = txt.toInt();
1696 } else if ( sec == d->daySection ) {
1697 txt = QString::number( d->d );
1698 txt = txt.mid( 0, txt.length()-1 );
1699 d->d = txt.toInt();
1700 d->dayCache = d->d;
1701 }
1702 d->ed->repaint( d->ed->rect(), FALSE );
1703}
1704
1705/*!
1706 \property QDateEdit::autoAdvance
1707 \brief whether the editor automatically advances to the next
1708 section
1709
1710 If autoAdvance is TRUE, the editor will automatically advance
1711 focus to the next date section if a user has completed a section.
1712 The default is FALSE.
1713*/
1714
1715void QDateEdit::setAutoAdvance( bool advance )
1716{
1717 d->adv = advance;
1718}
1719
1720
1721bool QDateEdit::autoAdvance() const
1722{
1723 return d->adv;
1724}
1725
1726/*! \reimp
1727*/
1728
1729void QDateEdit::timerEvent( QTimerEvent * )
1730{
1731 d->overwrite = TRUE;
1732}
1733
1734/*!
1735 \fn void QDateEdit::valueChanged( const QDate& date )
1736
1737 This signal is emitted whenever the editor's value changes. The \a
1738 date parameter is the new value.
1739*/
1740
1741///////////
1742
1743class QTimeEditPrivate
1744{
1745public:
1746 int h;
1747 int m;
1748 int s;
1749 uint display;
1750 bool adv;
1751 bool overwrite;
1752 int timerId;
1753 bool typing;
1754 QTime min;
1755 QTime max;
1756 bool changed;
1757 QDateTimeEditor *ed;
1758 QSpinWidget *controls;
1759};
1760
1761/*!
1762 \class QTimeEdit qdatetimeedit.h
1763 \brief The QTimeEdit class provides a time editor.
1764
1765 \ingroup advanced
1766 \ingroup time
1767 \mainclass
1768
1769 QTimeEdit allows the user to edit times by using the keyboard or
1770 the arrow keys to increase/decrease time values. The arrow keys
1771 can be used to move from section to section within the QTimeEdit
1772 box. The user can automatically be moved to the next section once
1773 they complete a section using setAutoAdvance(). Times appear in
1774 hour, minute, second order. It is recommended that the QTimeEdit
1775 is initialised with a time, e.g.
1776 \code
1777 QTime timeNow = QTime::currentTime();
1778 QTimeEdit *timeEdit = new QTimeEdit( timeNow, this );
1779 timeEdit->setRange( timeNow, timeNow.addSecs( 60 * 60 ) );
1780 \endcode
1781 Here we've created a QTimeEdit widget set to the current time.
1782 We've also set the minimum value to the current time and the
1783 maximum time to one hour from now.
1784
1785 The maximum and minimum values for a time value in the time editor
1786 default to the maximum and minimum values for a QTime. You can
1787 change this by calling setMinValue(), setMaxValue() or setRange().
1788
1789 Terminology: A QTimeWidget consists of three sections, one each
1790 for the hour, minute and second. You can change the separator
1791 character using setSeparator(), by default the separator is read
1792 from the system's settings.
1793
1794 \img datetimewidgets.png Date Time Widgets
1795
1796 \sa QTime QDateEdit QDateTimeEdit
1797*/
1798
1799
1800/*!
1801 Constructs an empty time edit with parent \a parent and called \a
1802 name.
1803*/
1804
1805QTimeEdit::QTimeEdit( QWidget * parent, const char * name )
1806 : QDateTimeEditBase( parent, name )
1807{
1808 init();
1809}
1810
1811/*!
1812 \overload
1813
1814 Constructs a time edit with the initial time value, \a time,
1815 parent \a parent and called \a name.
1816*/
1817
1818QTimeEdit::QTimeEdit( const QTime& time, QWidget * parent, const char * name )
1819 : QDateTimeEditBase( parent, name )
1820{
1821 init();
1822 setTime( time );
1823}
1824
1825/*! \internal
1826 */
1827
1828void QTimeEdit::init()
1829{
1830 d = new QTimeEditPrivate();
1831 d->ed = new QDateTimeEditor( this, "time edit base" );
1832 d->controls = new QDateTimeSpinWidget( this, qstrcmp( name(), "qt_datetime_timeedit" ) == 0 ? "qt_spin_widget" : "time edit controls" );
1833 d->controls->setEditWidget( d->ed );
1834 setFocusProxy( d->ed );
1835 connect( d->controls, SIGNAL( stepUpPressed() ), SLOT( stepUp() ) );
1836 connect( d->controls, SIGNAL( stepDownPressed() ), SLOT( stepDown() ) );
1837
1838 d->ed->appendSection( QNumberSection( 0,0, TRUE, 0 ) );
1839 d->ed->appendSection( QNumberSection( 0,0, TRUE, 1 ) );
1840 d->ed->appendSection( QNumberSection( 0,0, TRUE, 2 ) );
1841 d->ed->setSeparator( localTimeSep() );
1842
1843 d->h = 0;
1844 d->m = 0;
1845 d->s = 0;
1846 d->display = Hours | Minutes | Seconds;
1847 if ( lAMPM ) {
1848 d->display |= AMPM;
1849 d->ed->appendSection( QNumberSection( 0,0, FALSE, 3 ) );
1850 }
1851 d->adv = FALSE;
1852 d->overwrite = TRUE;
1853 d->timerId = 0;
1854 d->typing = FALSE;
1855 d->min = QTime( 0, 0, 0 );
1856 d->max = QTime( 23, 59, 59 );
1857 d->changed = FALSE;
1858
1859 setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
1860
1861 refcount++;
1862}
1863
1864/*!
1865 Destroys the object and frees any allocated resources.
1866*/
1867
1868QTimeEdit::~QTimeEdit()
1869{
1870 delete d;
1871 if ( !--refcount )
1872 cleanup();
1873}
1874
1875/*!
1876 \property QTimeEdit::minValue
1877 \brief the minimum time value
1878
1879 Setting the minimum time value is equivalent to calling
1880 QTimeEdit::setRange( \e t, maxValue() ), where \e t is the minimum
1881 time. The default minimum time is 00:00:00.
1882
1883 \sa maxValue setRange()
1884*/
1885
1886QTime QTimeEdit::minValue() const
1887{
1888 return d->min;
1889}
1890
1891/*!
1892 \property QTimeEdit::maxValue
1893 \brief the maximum time value
1894
1895 Setting the maximum time value is equivalent to calling
1896 QTimeEdit::setRange( minValue(), \e t ), where \e t is the maximum
1897 time. The default maximum time is 23:59:59.
1898
1899 \sa minValue setRange()
1900*/
1901
1902QTime QTimeEdit::maxValue() const
1903{
1904 return d->max;
1905}
1906
1907
1908/*!
1909 Sets the valid input range for the editor to be from \a min to \a
1910 max inclusive. If \a min is invalid no minimum time is set.
1911 Similarly, if \a max is invalid no maximum time is set.
1912*/
1913
1914void QTimeEdit::setRange( const QTime& min, const QTime& max )
1915{
1916 if ( min.isValid() )
1917 d->min = min;
1918 if ( max.isValid() )
1919 d->max = max;
1920}
1921
1922/*!
1923 \property QTimeEdit::display
1924 \brief the sections that are displayed in the time edit
1925
1926 The value can be any combination of the values in the Display enum.
1927 By default, the widget displays hours, minutes and seconds.
1928*/
1929void QTimeEdit::setDisplay( uint display )
1930{
1931 if ( d->display == display )
1932 return;
1933
1934 d->ed->clearSections();
1935 d->display = display;
1936 if ( d->display & Hours )
1937 d->ed->appendSection( QNumberSection( 0,0, TRUE, 0 ) );
1938 if ( d->display & Minutes )
1939 d->ed->appendSection( QNumberSection( 0,0, TRUE, 1 ) );
1940 if ( d->display & Seconds )
1941 d->ed->appendSection( QNumberSection( 0,0, TRUE, 2 ) );
1942 if ( d->display & AMPM )
1943 d->ed->appendSection( QNumberSection( 0,0, FALSE, 3 ) );
1944
1945 d->ed->setFocusSection( 0 );
1946 d->ed->update();
1947}
1948
1949uint QTimeEdit::display() const
1950{
1951 return d->display;
1952}
1953
1954/*!
1955 \property QTimeEdit::time
1956 \brief the editor's time value.
1957
1958 When changing the time property, if the time is less than
1959 minValue(), or is greater than maxValue(), nothing happens.
1960*/
1961
1962void QTimeEdit::setTime( const QTime& time )
1963{
1964 if ( !time.isValid() ) {
1965 d->h = 0;
1966 d->m = 0;
1967 d->s = 0;
1968 } else {
1969 if ( time > maxValue() || time < minValue() )
1970 return;
1971 d->h = time.hour();
1972 d->m = time.minute();
1973 d->s = time.second();
1974 emit valueChanged( time );
1975 }
1976 d->changed = FALSE;
1977 d->ed->repaint( d->ed->rect(), FALSE );
1978}
1979
1980QTime QTimeEdit::time() const
1981{
1982 if ( QTime::isValid( d->h, d->m, d->s ) )
1983 return QTime( d->h, d->m, d->s );
1984 return QTime();
1985}
1986
1987/*!
1988 \property QTimeEdit::autoAdvance
1989 \brief whether the editor automatically advances to the next
1990 section
1991
1992 If autoAdvance is TRUE, the editor will automatically advance
1993 focus to the next time section if a user has completed a section.
1994 The default is FALSE.
1995*/
1996
1997void QTimeEdit::setAutoAdvance( bool advance )
1998{
1999 d->adv = advance;
2000}
2001
2002bool QTimeEdit::autoAdvance() const
2003{
2004 return d->adv;
2005}
2006
2007/*!
2008 Sets the separator to \a s. Note that currently only the first
2009 character of \a s is used.
2010*/
2011
2012void QTimeEdit::setSeparator( const QString& s )
2013{
2014 d->ed->setSeparator( s );
2015}
2016
2017/*!
2018 Returns the editor's separator.
2019*/
2020
2021QString QTimeEdit::separator() const
2022{
2023 return d->ed->separator();
2024}
2025
2026
2027/*!
2028 \fn void QTimeEdit::valueChanged( const QTime& time )
2029
2030 This signal is emitted whenever the editor's value changes. The \a
2031 time parameter is the new value.
2032*/
2033
2034/*! \reimp
2035
2036*/
2037
2038bool QTimeEdit::event( QEvent *e )
2039{
2040 if ( e->type() == QEvent::FocusOut ) {
2041 d->typing = FALSE;
2042 if ( d->changed ) {
2043 emit valueChanged( time() );
2044 d->changed = FALSE;
2045 }
2046 } else if ( e->type() == QEvent::LocaleChange ) {
2047 readLocaleSettings();
2048 d->ed->setSeparator( localTimeSep() );
2049 }
2050 return QDateTimeEditBase::event( e );
2051}
2052
2053/*! \reimp
2054
2055*/
2056
2057void QTimeEdit::timerEvent( QTimerEvent * )
2058{
2059 d->overwrite = TRUE;
2060}
2061
2062
2063/*! \reimp
2064
2065*/
2066
2067void QTimeEdit::stepUp()
2068{
2069 int sec = d->ed->mapSection( d->ed->focusSection() );
2070 bool accepted = TRUE;
2071 switch( sec ) {
2072 case 0:
2073 if ( !outOfRange( d->h+1, d->m, d->s ) )
2074 setHour( d->h+1 );
2075 else
2076 setHour( d->min.hour() );
2077 break;
2078 case 1:
2079 if ( !outOfRange( d->h, d->m+1, d->s ) )
2080 setMinute( d->m+1 );
2081 else
2082 setMinute( d->min.minute() );
2083 break;
2084 case 2:
2085 if ( !outOfRange( d->h, d->m, d->s+1 ) )
2086 setSecond( d->s+1 );
2087 else
2088 setSecond( d->min.second() );
2089 break;
2090 case 3:
2091 if ( d->h < 12 )
2092 setHour( d->h+12 );
2093 else
2094 setHour( d->h-12 );
2095 break;
2096 default:
2097 accepted = FALSE;
2098#ifdef QT_CHECK_RANGE
2099 qWarning( "QTimeEdit::stepUp: Focus section out of range!" );
2100#endif
2101 break;
2102 }
2103 if ( accepted ) {
2104 d->changed = TRUE;
2105 emit valueChanged( time() );
2106 }
2107 d->ed->repaint( d->ed->rect(), FALSE );
2108}
2109
2110
2111/*! \reimp
2112
2113*/
2114
2115void QTimeEdit::stepDown()
2116{
2117 int sec = d->ed->mapSection( d->ed->focusSection() );
2118
2119 bool accepted = TRUE;
2120 switch( sec ) {
2121 case 0:
2122 if ( !outOfRange( d->h-1, d->m, d->s ) )
2123 setHour( d->h-1 );
2124 else
2125 setHour( d->max.hour() );
2126 break;
2127 case 1:
2128 if ( !outOfRange( d->h, d->m-1, d->s ) )
2129 setMinute( d->m-1 );
2130 else
2131 setMinute( d->max.minute() );
2132 break;
2133 case 2:
2134 if ( !outOfRange( d->h, d->m, d->s-1 ) )
2135 setSecond( d->s-1 );
2136 else
2137 setSecond( d->max.second() );
2138 break;
2139 case 3:
2140 if ( d->h > 11 )
2141 setHour( d->h-12 );
2142 else
2143 setHour( d->h+12 );
2144 break;
2145 default:
2146 accepted = FALSE;
2147#ifdef QT_CHECK_RANGE
2148 qWarning( "QTimeEdit::stepDown: Focus section out of range!" );
2149#endif
2150 break;
2151 }
2152 if ( accepted ) {
2153 d->changed = TRUE;
2154 emit valueChanged( time() );
2155 }
2156 d->ed->repaint( d->ed->rect(), FALSE );
2157}
2158
2159
2160/*!
2161 Returns the formatted number for section \a sec. This will
2162 correspond to either the hour, minute or second section, depending
2163 on \a sec.
2164*/
2165
2166QString QTimeEdit::sectionFormattedText( int sec )
2167{
2168 QString txt;
2169 txt = sectionText( sec );
2170 txt = txt.rightJustify( 2, QDATETIMEEDIT_HIDDEN_CHAR );
2171 int offset = sec*2+sec*separator().length() + txt.length();
2172 if ( d->typing && sec == d->ed->focusSection() )
2173 d->ed->setSectionSelection( sec, offset - txt.length(), offset );
2174 else
2175 d->ed->setSectionSelection( sec, offset - txt.length(), offset );
2176
2177 return txt;
2178}
2179
2180
2181/*! \reimp
2182
2183*/
2184
2185bool QTimeEdit::setFocusSection( int sec )
2186{
2187 if ( sec != d->ed->focusSection() ) {
2188 killTimer( d->timerId );
2189 d->overwrite = TRUE;
2190 d->typing = FALSE;
2191 QString txt = sectionText( sec );
2192 txt = txt.rightJustify( 2, QDATETIMEEDIT_HIDDEN_CHAR );
2193 int offset = sec*2+sec*separator().length() + txt.length();
2194 d->ed->setSectionSelection( sec, offset - txt.length(), offset );
2195 if ( d->changed ) {
2196 emit valueChanged( time() );
2197 d->changed = FALSE;
2198 }
2199 }
2200 return d->ed->setFocusSection( sec );
2201}
2202
2203
2204/*!
2205 Sets the hour to \a h, which must be a valid hour, i.e. in the
2206 range 0..24.
2207*/
2208
2209void QTimeEdit::setHour( int h )
2210{
2211 if ( h < 0 )
2212 h = 0;
2213 if ( h > 23 )
2214 h = 23;
2215 d->h = h;
2216}
2217
2218
2219/*!
2220 Sets the minute to \a m, which must be a valid minute, i.e. in the
2221 range 0..59.
2222*/
2223
2224void QTimeEdit::setMinute( int m )
2225{
2226 if ( m < 0 )
2227 m = 0;
2228 if ( m > 59 )
2229 m = 59;
2230 d->m = m;
2231}
2232
2233
2234/*!
2235 Sets the second to \a s, which must be a valid second, i.e. in the
2236 range 0..59.
2237*/
2238
2239void QTimeEdit::setSecond( int s )
2240{
2241 if ( s < 0 )
2242 s = 0;
2243 if ( s > 59 )
2244 s = 59;
2245 d->s = s;
2246}
2247
2248
2249/*! \internal
2250
2251 Returns the text of section \a sec.
2252
2253*/
2254
2255QString QTimeEdit::sectionText( int sec )
2256{
2257 sec = d->ed->mapSection( sec );
2258
2259 QString txt;
2260 switch( sec ) {
2261 case 0:
2262 if ( !(d->display & AMPM) || ( d->h < 13 && d->h ) ) { // I wished the day stared at 0:00 for everybody
2263 txt = QString::number( d->h );
2264 } else {
2265 if ( d->h )
2266 txt = QString::number( d->h - 12 );
2267 else
2268 txt = "12";
2269 }
2270 break;
2271 case 1:
2272 txt = QString::number( d->m );
2273 break;
2274 case 2:
2275 txt = QString::number( d->s );
2276 break;
2277 case 3:
2278 if ( d->h < 12 ) {
2279 if ( lAM )
2280 txt = *lAM;
2281 else
2282 txt = QString::fromLatin1( "AM" );
2283 } else {
2284 if ( lPM )
2285 txt = *lPM;
2286 else
2287 txt = QString::fromLatin1( "PM" );
2288 }
2289 break;
2290 default:
2291 break;
2292 }
2293 return txt;
2294}
2295
2296
2297/*! \internal
2298 Returns TRUE if \a h, \a m, and \a s are out of range.
2299 */
2300
2301bool QTimeEdit::outOfRange( int h, int m, int s ) const
2302{
2303 if ( QTime::isValid( h, m, s ) ) {
2304 QTime currentTime( h, m, s );
2305 if ( currentTime > maxValue() ||
2306 currentTime < minValue() )
2307 return TRUE;
2308 else
2309 return FALSE;
2310 }
2311 return TRUE;
2312}
2313
2314/*! \reimp
2315
2316*/
2317
2318void QTimeEdit::addNumber( int sec, int num )
2319{
2320 if ( sec == -1 )
2321 return;
2322 sec = d->ed->mapSection( sec );
2323 killTimer( d->timerId );
2324 bool overwrite = FALSE;
2325 bool accepted = FALSE;
2326 d->typing = TRUE;
2327 QString txt;
2328
2329 switch( sec ) {
2330 case 0:
2331 txt = ( d->display & AMPM && d->h > 12 ) ?
2332 QString::number( d->h - 12 ) : QString::number( d->h );
2333
2334 if ( d->overwrite || txt.length() == 2 ) {
2335 if ( d->display & AMPM && num == 0 )
2336 break; // Don't process 0 in 12 hour clock mode
2337 if ( d->display & AMPM && d->h > 11 )
2338 num += 12;
2339 if ( !outOfRange( num, d->m, d->s ) ) {
2340 accepted = TRUE;
2341 d->h = num;
2342 }
2343 } else {
2344 txt += QString::number( num );
2345 int temp = txt.toInt();
2346
2347 if ( d->display & AMPM ) {
2348 if ( temp == 12 ) {
2349 if ( d->h < 12 ) {
2350 temp = 0;
2351 }
2352 accepted = TRUE;
2353 } else if ( outOfRange( temp + 12, d->m, d->s ) ) {
2354 txt = QString::number( d->h );
2355 } else {
2356 if ( d->h > 11 ) {
2357 temp += 12;
2358 }
2359 accepted = TRUE;
2360 }
2361 } else if ( !(d->display & AMPM) && outOfRange( temp, d->m, d->s ) ) {
2362 txt = QString::number( d->h );
2363 } else {
2364 accepted = TRUE;
2365 }
2366
2367 if ( accepted )
2368 d->h = temp;
2369
2370 if ( d->adv && txt.length() == 2 ) {
2371 setFocusSection( d->ed->focusSection()+1 );
2372 overwrite = TRUE;
2373 }
2374 }
2375 break;
2376
2377 case 1:
2378 txt = QString::number( d->m );
2379 if ( d->overwrite || txt.length() == 2 ) {
2380 if ( !outOfRange( d->h, num, d->s ) ) {
2381 accepted = TRUE;
2382 d->m = num;
2383 }
2384 } else {
2385 txt += QString::number( num );
2386 int temp = txt.toInt();
2387 if ( temp > 59 )
2388 temp = num;
2389 if ( outOfRange( d->h, temp, d->s ) )
2390 txt = QString::number( d->m );
2391 else {
2392 accepted = TRUE;
2393 d->m = temp;
2394 }
2395 if ( d->adv && txt.length() == 2 ) {
2396 setFocusSection( d->ed->focusSection()+1 );
2397 overwrite = TRUE;
2398 }
2399 }
2400 break;
2401
2402 case 2:
2403 txt = QString::number( d->s );
2404 if ( d->overwrite || txt.length() == 2 ) {
2405 if ( !outOfRange( d->h, d->m, num ) ) {
2406 accepted = TRUE;
2407 d->s = num;
2408 }
2409 } else {
2410 txt += QString::number( num );
2411 int temp = txt.toInt();
2412 if ( temp > 59 )
2413 temp = num;
2414 if ( outOfRange( d->h, d->m, temp ) )
2415 txt = QString::number( d->s );
2416 else {
2417 accepted = TRUE;
2418 d->s = temp;
2419 }
2420 if ( d->adv && txt.length() == 2 ) {
2421 setFocusSection( d->ed->focusSection()+1 );
2422 overwrite = TRUE;
2423 }
2424 }
2425 break;
2426
2427 case 3:
2428 break;
2429
2430 default:
2431 break;
2432 }
2433 d->changed = accepted;
2434 if ( accepted )
2435 emit valueChanged( time() );
2436 d->overwrite = overwrite;
2437 d->timerId = startTimer( qApp->doubleClickInterval()*4 );
2438 d->ed->repaint( d->ed->rect(), FALSE );
2439}
2440
2441
2442/*!
2443 \internal
2444
2445 Function which is called whenever the user tries to
2446 remove the first number from \a sec by pressing the backspace key.
2447*/
2448
2449void QTimeEdit::removeFirstNumber( int sec )
2450{
2451 if ( sec == -1 )
2452 return;
2453 sec = d->ed->mapSection( sec );
2454 QString txt;
2455 switch( sec ) {
2456 case 0:
2457 txt = QString::number( d->h );
2458 break;
2459 case 1:
2460 txt = QString::number( d->m );
2461 break;
2462 case 2:
2463 txt = QString::number( d->s );
2464 break;
2465 }
2466 txt = txt.mid( 1, txt.length() ) + "0";
2467 switch( sec ) {
2468 case 0:
2469 d->h = txt.toInt();
2470 break;
2471 case 1:
2472 d->m = txt.toInt();
2473 break;
2474 case 2:
2475 d->s = txt.toInt();
2476 break;
2477 }
2478 d->ed->repaint( d->ed->rect(), FALSE );
2479}
2480
2481/*! \reimp
2482
2483*/
2484void QTimeEdit::removeLastNumber( int sec )
2485{
2486 if ( sec == -1 )
2487 return;
2488 sec = d->ed->mapSection( sec );
2489 QString txt;
2490 switch( sec ) {
2491 case 0:
2492 txt = QString::number( d->h );
2493 break;
2494 case 1:
2495 txt = QString::number( d->m );
2496 break;
2497 case 2:
2498 txt = QString::number( d->s );
2499 break;
2500 }
2501 txt = txt.mid( 0, txt.length()-1 );
2502 switch( sec ) {
2503 case 0:
2504 d->h = txt.toInt();
2505 break;
2506 case 1:
2507 d->m = txt.toInt();
2508 break;
2509 case 2:
2510 d->s = txt.toInt();
2511 break;
2512 }
2513 d->ed->repaint( d->ed->rect(), FALSE );
2514}
2515
2516/*! \reimp
2517 */
2518void QTimeEdit::resizeEvent( QResizeEvent * )
2519{
2520 d->controls->resize( width(), height() );
2521}
2522
2523/*! \reimp
2524*/
2525QSize QTimeEdit::sizeHint() const
2526{
2527 constPolish();
2528 QFontMetrics fm( font() );
2529 int fw = style().pixelMetric( QStyle::PM_DefaultFrameWidth, this );
2530 int h = fm.lineSpacing();
2531 if ( style().styleHint( QStyle::SH_GUIStyle ) != QStyle::PMStyle )
2532 h += 2;
2533 int w = 2 + fm.width( '9' ) * 6 + fm.width( d->ed->separator() ) * 2 +
2534 d->controls->upRect().width() + fw * 4;
2535 if ( d->display & AMPM ) {
2536 if ( lAM )
2537 w += fm.width( *lAM ) + 4;
2538 else
2539 w += fm.width( QString::fromLatin1( "AM" ) ) + 4;
2540 }
2541
2542 return QSize( w, QMAX(h + fw * 2, 20) ).expandedTo( QApplication::globalStrut() );
2543}
2544
2545/*! \reimp
2546*/
2547QSize QTimeEdit::minimumSizeHint() const
2548{
2549 return sizeHint();
2550}
2551
2552/*!
2553 \internal
2554 Enables/disables the push buttons according to the min/max time
2555 for this widget.
2556*/
2557
2558// ### Remove in 4.0?
2559
2560void QTimeEdit::updateButtons()
2561{
2562 if ( !isEnabled() )
2563 return;
2564
2565 bool upEnabled = time() < maxValue();
2566 bool downEnabled = time() > minValue();
2567
2568 d->controls->setUpEnabled( upEnabled );
2569 d->controls->setDownEnabled( downEnabled );
2570}
2571
2572
2573class QDateTimeEditPrivate
2574{
2575public:
2576 bool adv;
2577};
2578
2579/*!
2580 \class QDateTimeEdit qdatetimeedit.h
2581 \brief The QDateTimeEdit class combines a QDateEdit and QTimeEdit
2582 widget into a single widget for editing datetimes.
2583
2584 \ingroup advanced
2585 \ingroup time
2586 \mainclass
2587
2588 QDateTimeEdit consists of a QDateEdit and QTimeEdit widget placed
2589 side by side and offers the functionality of both. The user can
2590 edit the date and time by using the keyboard or the arrow keys to
2591 increase/decrease date or time values. The Tab key can be used to
2592 move from section to section within the QDateTimeEdit widget, and
2593 the user can be moved automatically when they complete a section
2594 using setAutoAdvance(). The datetime can be set with
2595 setDateTime().
2596
2597 The date format is read from the system's locale settings. It is
2598 set to year, month, day order if that is not possible. See
2599 QDateEdit::setOrder() to change this. Times appear in the order
2600 hours, minutes, seconds using the 24 hour clock.
2601
2602 It is recommended that the QDateTimeEdit is initialised with a
2603 datetime, e.g.
2604 \code
2605 QDateTimeEdit *dateTimeEdit = new QDateTimeEdit( QDateTime::currentDateTime(), this );
2606 dateTimeEdit->dateEdit()->setRange( QDateTime::currentDate(),
2607 QDateTime::currentDate().addDays( 7 ) );
2608 \endcode
2609 Here we've created a new QDateTimeEdit set to the current date and
2610 time, and set the date to have a minimum date of now and a maximum
2611 date of a week from now.
2612
2613 Terminology: A QDateEdit widget consists of three 'sections', one
2614 each for the year, month and day. Similarly a QTimeEdit consists
2615 of three sections, one each for the hour, minute and second. The
2616 character that separates each date section is specified with
2617 setDateSeparator(); similarly setTimeSeparator() is used for the
2618 time sections.
2619
2620 \img datetimewidgets.png Date Time Widgets
2621
2622 \sa QDateEdit QTimeEdit
2623*/
2624
2625/*!
2626 Constructs an empty datetime edit with parent \a parent and called
2627 \a name.
2628*/
2629QDateTimeEdit::QDateTimeEdit( QWidget * parent, const char * name )
2630 : QWidget( parent, name )
2631{
2632 init();
2633}
2634
2635
2636/*!
2637 \overload
2638
2639 Constructs a datetime edit with the initial value \a datetime,
2640 parent \a parent and called \a name.
2641*/
2642QDateTimeEdit::QDateTimeEdit( const QDateTime& datetime,
2643 QWidget * parent, const char * name )
2644 : QWidget( parent, name )
2645{
2646 init();
2647 setDateTime( datetime );
2648}
2649
2650
2651
2652/*!
2653 Destroys the object and frees any allocated resources.
2654*/
2655
2656QDateTimeEdit::~QDateTimeEdit()
2657{
2658 delete d;
2659}
2660
2661
2662/*!
2663 \reimp
2664
2665 Intercepts and handles resize events which have special meaning
2666 for the QDateTimeEdit.
2667*/
2668
2669void QDateTimeEdit::resizeEvent( QResizeEvent * )
2670{
2671 int dw = de->sizeHint().width();
2672 int tw = te->sizeHint().width();
2673 int w = width();
2674 int h = height();
2675 int extra = w - ( dw + tw );
2676
2677 if ( tw + extra < 0 ) {
2678 dw = w;
2679 } else {
2680 dw += 9 * extra / 16;
2681 }
2682 tw = w - dw;
2683
2684 de->setGeometry( 0, 0, dw, h );
2685 te->setGeometry( dw, 0, tw, h );
2686}
2687
2688/*! \reimp
2689*/
2690
2691QSize QDateTimeEdit::minimumSizeHint() const
2692{
2693 QSize dsh = de->minimumSizeHint();
2694 QSize tsh = te->minimumSizeHint();
2695 return QSize( dsh.width() + tsh.width(),
2696 QMAX( dsh.height(), tsh.height() ) );
2697}
2698
2699/*! \internal
2700 */
2701
2702void QDateTimeEdit::init()
2703{
2704 d = new QDateTimeEditPrivate();
2705 de = new QDateEdit( this, "qt_datetime_dateedit" );
2706 te = new QTimeEdit( this, "qt_datetime_timeedit" );
2707 d->adv = FALSE;
2708 connect( de, SIGNAL( valueChanged(const QDate&) ),
2709 this, SLOT( newValue(const QDate&) ) );
2710 connect( te, SIGNAL( valueChanged(const QTime&) ),
2711 this, SLOT( newValue(const QTime&) ) );
2712 setFocusProxy( de );
2713 setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
2714}
2715
2716/*! \reimp
2717 */
2718
2719QSize QDateTimeEdit::sizeHint() const
2720{
2721 constPolish();
2722 QSize dsh = de->sizeHint();
2723 QSize tsh = te->sizeHint();
2724 return QSize( dsh.width() + tsh.width(),
2725 QMAX( dsh.height(), tsh.height() ) );
2726}
2727
2728/*!
2729 \property QDateTimeEdit::dateTime
2730 \brief the editor's datetime value
2731
2732 The datetime edit's datetime which may be an invalid datetime.
2733*/
2734
2735void QDateTimeEdit::setDateTime( const QDateTime & dt )
2736{
2737 if ( dt.isValid() ) {
2738 de->setDate( dt.date() );
2739 te->setTime( dt.time() );
2740 emit valueChanged( dt );
2741 }
2742}
2743
2744QDateTime QDateTimeEdit::dateTime() const
2745{
2746 return QDateTime( de->date(), te->time() );
2747}
2748
2749/*!
2750 \fn void QDateTimeEdit::valueChanged( const QDateTime& datetime )
2751
2752 This signal is emitted every time the date or time changes. The \a
2753 datetime argument is the new datetime.
2754*/
2755
2756
2757/*! \internal
2758
2759 Re-emits the value \a d.
2760 */
2761
2762void QDateTimeEdit::newValue( const QDate& )
2763{
2764 QDateTime dt = dateTime();
2765 emit valueChanged( dt );
2766}
2767
2768/*! \internal
2769 \overload
2770 Re-emits the value \a t.
2771 */
2772
2773void QDateTimeEdit::newValue( const QTime& )
2774{
2775 QDateTime dt = dateTime();
2776 emit valueChanged( dt );
2777}
2778
2779
2780/*!
2781 Sets the auto advance property of the editor to \a advance. If set
2782 to TRUE, the editor will automatically advance focus to the next
2783 date or time section if the user has completed a section.
2784*/
2785
2786void QDateTimeEdit::setAutoAdvance( bool advance )
2787{
2788 de->setAutoAdvance( advance );
2789 te->setAutoAdvance( advance );
2790}
2791
2792/*!
2793 Returns TRUE if auto-advance is enabled, otherwise returns FALSE.
2794
2795 \sa setAutoAdvance()
2796*/
2797
2798bool QDateTimeEdit::autoAdvance() const
2799{
2800 return de->autoAdvance();
2801}
2802
2803/*!
2804 \fn QDateEdit* QDateTimeEdit::dateEdit()
2805
2806 Returns the internal widget used for editing the date part of the
2807 datetime.
2808*/
2809
2810/*!
2811 \fn QTimeEdit* QDateTimeEdit::timeEdit()
2812
2813 Returns the internal widget used for editing the time part of the
2814 datetime.
2815*/
2816
2817#include "qdatetimeedit.moc"
2818
2819#endif
Note: See TracBrowser for help on using the repository browser.