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

Last change on this file since 345 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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