source: trunk/src/qt3support/widgets/q3datetimeedit.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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