| /**************************************************************************** |
| ** |
| ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). |
| ** All rights reserved. |
| ** Contact: Nokia Corporation (qt-info@nokia.com) |
| ** |
| ** This file is part of the Qt3Support module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** GNU Lesser General Public License Usage |
| ** This file may be used under the terms of the GNU Lesser General Public |
| ** License version 2.1 as published by the Free Software Foundation and |
| ** appearing in the file LICENSE.LGPL included in the packaging of this |
| ** file. Please review the following information to ensure the GNU Lesser |
| ** General Public License version 2.1 requirements will be met: |
| ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| ** |
| ** In addition, as a special exception, Nokia gives you certain additional |
| ** rights. These rights are described in the Nokia Qt LGPL Exception |
| ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU General |
| ** Public License version 3.0 as published by the Free Software Foundation |
| ** and appearing in the file LICENSE.GPL included in the packaging of this |
| ** file. Please review the following information to ensure the GNU General |
| ** Public License version 3.0 requirements will be met: |
| ** http://www.gnu.org/copyleft/gpl.html. |
| ** |
| ** Other Usage |
| ** Alternatively, this file may be used in accordance with the terms and |
| ** conditions contained in a signed written agreement between you and Nokia. |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "q3datetimeedit.h" |
| |
| #ifndef QT_NO_DATETIMEEDIT |
| |
| #include <private/q3richtext_p.h> |
| #include "qevent.h" |
| #include "q3rangecontrol.h" |
| #include "qapplication.h" |
| #include "qpixmap.h" |
| #include "qlist.h" |
| #include "qstring.h" |
| #include "qstyle.h" |
| |
| #if defined(Q_WS_WIN) |
| #include "qt_windows.h" |
| #endif |
| |
| QT_BEGIN_NAMESPACE |
| |
| #define QDATETIMEEDIT_HIDDEN_CHAR QLatin1Char('0') |
| |
| class Q_COMPAT_EXPORT QNumberSection |
| { |
| public: |
| QNumberSection(int selStart = 0, int selEnd = 0, bool separat = true, int actual = -1) |
| : selstart(selStart), selend(selEnd), act(actual), sep(separat) |
| {} |
| int selectionStart() const { return selstart; } |
| void setSelectionStart(int s) { selstart = s; } |
| int selectionEnd() const { return selend; } |
| void setSelectionEnd(int s) { selend = s; } |
| int width() const { return selend - selstart; } |
| int index() const { return act; } |
| bool separator() const { return sep; } |
| Q_DUMMY_COMPARISON_OPERATOR(QNumberSection) |
| private: |
| signed int selstart :12; |
| signed int selend :12; |
| signed int act :7; |
| bool sep :1; |
| }; |
| |
| static QString *lDateSep = 0; |
| static QString *lTimeSep = 0; |
| static bool lAMPM = false; |
| static QString *lAM = 0; |
| static QString *lPM = 0; |
| static Q3DateEdit::Order lOrder = Q3DateEdit::YMD; |
| static int refcount = 0; |
| |
| static void cleanup() |
| { |
| delete lDateSep; |
| lDateSep = 0; |
| delete lTimeSep; |
| lTimeSep = 0; |
| delete lAM; |
| lAM = 0; |
| delete lPM; |
| lPM = 0; |
| } |
| |
| /*! |
| \internal |
| try to get the order of DMY and the date/time separator from the locale settings |
| */ |
| static void readLocaleSettings() |
| { |
| int dpos, mpos, ypos; |
| cleanup(); |
| |
| lDateSep = new QString(); |
| lTimeSep = new QString(); |
| |
| #if defined(Q_WS_WIN) |
| wchar_t data[10]; |
| GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, data, 10); |
| *lDateSep = QString::fromWCharArray(data); |
| GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, data, 10); |
| *lTimeSep = QString::fromWCharArray(data); |
| GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITIME, data, 10); |
| lAMPM = QString::fromWCharArray(data).toInt() == 0; |
| GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_S1159, data, 10); |
| QString am = QString::fromWCharArray(data); |
| if (!am.isEmpty()) |
| lAM = new QString(am); |
| GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_S2359, data, 10); |
| QString pm = QString::fromWCharArray(data); |
| if (!pm.isEmpty() ) |
| lPM = new QString(pm); |
| #else |
| *lDateSep = QLatin1Char('-'); |
| *lTimeSep = QLatin1Char(':'); |
| #endif |
| QString d = QDate(1999, 11, 22).toString(Qt::LocalDate); |
| dpos = d.indexOf(QLatin1String("22")); |
| mpos = d.indexOf(QLatin1String("11")); |
| ypos = d.indexOf(QLatin1String("99")); |
| if (dpos > -1 && mpos > -1 && ypos > -1) { |
| // test for DMY, MDY, YMD, YDM |
| if (dpos < mpos && mpos < ypos) { |
| lOrder = Q3DateEdit::DMY; |
| } else if (mpos < dpos && dpos < ypos) { |
| lOrder = Q3DateEdit::MDY; |
| } else if (ypos < mpos && mpos < dpos) { |
| lOrder = Q3DateEdit::YMD; |
| } else if (ypos < dpos && dpos < mpos) { |
| lOrder = Q3DateEdit::YDM; |
| } else { |
| // cannot determine the dateformat - use the default |
| return; |
| } |
| |
| // this code needs to change if new formats are added |
| |
| #ifndef Q_WS_WIN |
| QString sep = d.mid(qMin(dpos, mpos) + 2, QABS(dpos - mpos) - 2); |
| if (d.count(sep) == 2) { |
| *lDateSep = sep; |
| } |
| #endif |
| } |
| |
| #ifndef Q_WS_WIN |
| QString t = QTime(11, 22, 33).toString(Qt::LocalDate); |
| dpos = t.indexOf(QLatin1String("11")); |
| mpos = t.indexOf(QLatin1String("22")); |
| ypos = t.indexOf(QLatin1String("33")); |
| // We only allow hhmmss |
| if (dpos > -1 && dpos < mpos && mpos < ypos) { |
| QString sep = t.mid(dpos + 2, mpos - dpos - 2); |
| if (sep == t.mid(mpos + 2, ypos - mpos - 2)) { |
| *lTimeSep = sep; |
| } |
| } |
| #endif |
| } |
| |
| static Q3DateEdit::Order localOrder() { |
| if (!lDateSep) { |
| readLocaleSettings(); |
| } |
| return lOrder; |
| } |
| |
| static QString localDateSep() { |
| if (!lDateSep) { |
| readLocaleSettings(); |
| } |
| return *lDateSep; |
| } |
| |
| static QString localTimeSep() { |
| if (!lTimeSep) { |
| readLocaleSettings(); |
| } |
| return *lTimeSep; |
| } |
| |
| class Q3DateTimeEditorPrivate |
| { |
| public: |
| Q3DateTimeEditorPrivate() |
| : frm(true), |
| parag(new Q3TextParagraph(0, 0, 0, false)), |
| focusSec(0) |
| { |
| parag->formatter()->setWrapEnabled(false); |
| cursor = new Q3TextCursor(0); |
| cursor->setParagraph(parag); |
| offset = 0; |
| sep = localDateSep(); |
| refcount++; |
| } |
| ~Q3DateTimeEditorPrivate() |
| { |
| delete parag; |
| delete cursor; |
| if (!--refcount) |
| cleanup(); |
| } |
| |
| void appendSection(const QNumberSection& sec) |
| { |
| sections.append(sec); |
| |
| } |
| void clearSections() |
| { |
| sections.clear(); |
| } |
| void setSectionSelection(int sec, int selstart, int selend) |
| { |
| if (sec < 0 || sec >= sections.count()) |
| return; |
| sections[sec].setSelectionStart(selstart); |
| sections[sec].setSelectionEnd(selend); |
| } |
| uint sectionCount() const { return (uint)sections.count(); } |
| void setSeparator(const QString& s) { sep = s; } |
| QString separator() const { return sep; } |
| |
| void setFrame(bool f) { frm = f; } |
| bool frame() const { return frm; } |
| |
| int focusSection() const { return focusSec; } |
| int section(const QPoint& p) |
| { |
| cursor->place(p + QPoint(offset, 0), parag); |
| int idx = cursor->index(); |
| for (int i = 0; i < sections.count(); ++i) { |
| if (idx >= sections[i].selectionStart() && |
| idx <= sections[i].selectionEnd()) |
| return i; |
| } |
| return -1; |
| } |
| QNumberSection section(int idx) const |
| { |
| return sections[idx]; |
| } |
| bool setFocusSection(int idx) |
| { |
| if (idx > (int)sections.count()-1 || idx < 0) |
| return false; |
| if (idx != focusSec) { |
| focusSec = idx; |
| applyFocusSelection(); |
| return true; |
| } |
| return false; |
| } |
| |
| bool inSectionSelection(int idx) |
| { |
| for (int i = 0; i < sections.count(); ++i) { |
| if (idx >= sections[i].selectionStart() && |
| idx <= sections[i].selectionEnd()) |
| return true; |
| } |
| return false; |
| } |
| |
| void paint(const QString& txt, bool focus, QPainter& p, |
| const QPalette&pal, const QRect& rect, QStyle *style) |
| { |
| int fw = 0; |
| if (frm) |
| fw = style->pixelMetric(QStyle::PM_DefaultFrameWidth); |
| |
| parag->truncate(0); |
| parag->append(txt); |
| if (!focus) |
| parag->removeSelection(Q3TextDocument::Standard); |
| else { |
| applyFocusSelection(); |
| } |
| |
| /* color all QDATETIMEEDIT_HIDDEN_CHAR chars to background color */ |
| Q3TextFormat *fb = parag->formatCollection()->format(p.font(), |
| pal.base().color()); |
| Q3TextFormat *nf = parag->formatCollection()->format(p.font(), |
| pal.text().color()); |
| for (int i = 0; i < txt.length(); ++i) { |
| parag->setFormat(i, 1, nf); |
| if (inSectionSelection(i)) |
| continue; |
| if (txt.at(i) == QDATETIMEEDIT_HIDDEN_CHAR) |
| parag->setFormat(i, 1, fb); |
| else |
| parag->setFormat(i, 1, nf); |
| } |
| fb->removeRef(); |
| nf->removeRef(); |
| |
| QRect r(rect.x(), rect.y(), rect.width() - 2 * (2 + fw), rect.height()); |
| parag->pseudoDocument()->docRect = r; |
| parag->invalidate(0); |
| parag->format(); |
| |
| int xoff = 2 + fw - offset; |
| int yoff = (rect.height() - parag->rect().height() + 1) / 2; |
| if (yoff < 0) |
| yoff = 0; |
| |
| p.translate(xoff, yoff); |
| parag->paint(p, pal, 0, true); |
| if (frm) |
| p.translate(-xoff, -yoff); |
| } |
| |
| void resize(const QSize& size) { sz = size; } |
| |
| int mapSection(int sec) |
| { |
| return (sec >= 0 && sec < sections.count() ? sections[sec].index() : -1); |
| } |
| |
| protected: |
| void applyFocusSelection() |
| { |
| if (focusSec > -1 && focusSec < sections.count()) { |
| int selstart = sections[focusSec].selectionStart(); |
| int selend = sections[focusSec].selectionEnd(); |
| parag->setSelection(Q3TextDocument::Standard, selstart, selend); |
| parag->format(); |
| if (parag->at(selstart)->x < offset || |
| parag->at(selend)->x + parag->string()->width(selend) > offset + sz.width()) { |
| offset = parag->at(selstart)->x; |
| } |
| } |
| } |
| private: |
| bool frm; |
| Q3TextParagraph *parag; |
| Q3TextCursor *cursor; |
| QSize sz; |
| int focusSec; |
| QList< QNumberSection > sections; |
| QString sep; |
| int offset; |
| }; |
| |
| class Q3DateTimeEditor : public QWidget |
| { |
| Q_OBJECT |
| public: |
| Q3DateTimeEditor(Q3DateTimeEditBase *widget, QWidget *parent, const char* name=0); |
| ~Q3DateTimeEditor(); |
| |
| void setControlWidget(Q3DateTimeEditBase * widget); |
| Q3DateTimeEditBase * controlWidget() const; |
| |
| void setSeparator(const QString& s); |
| QString separator() const; |
| |
| int focusSection() const; |
| bool setFocusSection(int s); |
| void appendSection(const QNumberSection& sec); |
| void clearSections(); |
| void setSectionSelection(int sec, int selstart, int selend); |
| bool eventFilter(QObject *o, QEvent *e); |
| int sectionAt(const QPoint &p); |
| int mapSection(int sec); |
| |
| protected: |
| void init(); |
| bool event(QEvent *e); |
| void resizeEvent(QResizeEvent *); |
| void paintEvent(QPaintEvent *); |
| void mousePressEvent(QMouseEvent *e); |
| |
| private: |
| Q3DateTimeEditBase* cw; |
| Q3DateTimeEditorPrivate* d; |
| }; |
| |
| class QDateTimeSpinWidget : public Q3SpinWidget |
| { |
| Q_OBJECT |
| public: |
| QDateTimeSpinWidget(QWidget *parent, const char *name) |
| : Q3SpinWidget(parent, name) |
| { |
| } |
| |
| void changeEvent(QEvent *e) |
| { |
| if (e->type() == QEvent::EnabledChange && isEnabled()) { |
| Q3DateEdit *de = qobject_cast<Q3DateEdit*>(parentWidget()); |
| if (de) { |
| setUpEnabled(de->date() < de->maxValue()); |
| setDownEnabled(de->date() > de->minValue()); |
| } else { |
| setUpEnabled(true); |
| setDownEnabled(true); |
| } |
| } |
| } |
| void enabledChange(bool notenabled) |
| { |
| Q3DateEdit *de = qobject_cast<Q3DateEdit*>(parentWidget()); |
| if (de && !notenabled) { |
| setUpEnabled(de->date() < de->maxValue()); |
| setDownEnabled(de->date() > de->minValue()); |
| } else { |
| setUpEnabled(!notenabled); |
| setDownEnabled(!notenabled); |
| } |
| } |
| |
| |
| protected: |
| #ifndef QT_NO_WHEELEVENT |
| void wheelEvent(QWheelEvent *e) |
| { |
| Q3DateTimeEditor *editor = qobject_cast<Q3DateTimeEditor*>(editWidget()); |
| Q_ASSERT(editor); |
| if (!editor) |
| return; |
| |
| int section = editor->sectionAt(e->pos()); |
| editor->setFocusSection(section); |
| |
| if (section == -1) |
| return; |
| Q3SpinWidget::wheelEvent(e); |
| } |
| #endif |
| }; |
| |
| /*! |
| Constructs an empty datetime editor with parent \a parent and |
| called \a name. |
| */ |
| Q3DateTimeEditor::Q3DateTimeEditor(Q3DateTimeEditBase *widget, QWidget *parent, const char * name) |
| : QWidget(parent, name) |
| { |
| d = new Q3DateTimeEditorPrivate(); |
| cw = widget; |
| init(); |
| } |
| |
| /*! |
| Destroys the object and frees any allocated resources. |
| */ |
| |
| Q3DateTimeEditor::~Q3DateTimeEditor() |
| { |
| delete d; |
| } |
| |
| /*! \internal |
| |
| */ |
| |
| void Q3DateTimeEditor::init() |
| { |
| setBackgroundRole(QPalette::Base); |
| setFocusSection(-1); |
| installEventFilter(this); |
| setFocusPolicy(Qt::WheelFocus); |
| } |
| |
| |
| /*! \reimp |
| |
| */ |
| |
| bool Q3DateTimeEditor::event(QEvent *e) |
| { |
| if (e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut) { |
| if (e->type() == QEvent::FocusOut) |
| qApp->sendEvent(cw, e); |
| update(rect()); |
| } else if (e->type() == QEvent::ShortcutOverride) { |
| QKeyEvent* ke = (QKeyEvent*) e; |
| switch (ke->key()) { |
| case Qt::Key_Delete: |
| case Qt::Key_Backspace: |
| case Qt::Key_Up: |
| case Qt::Key_Down: |
| case Qt::Key_Left: |
| case Qt::Key_Right: |
| ke->accept(); |
| default: |
| break; |
| } |
| } |
| return QWidget::event(e); |
| } |
| |
| /*! \reimp |
| |
| */ |
| |
| void Q3DateTimeEditor::resizeEvent(QResizeEvent *e) |
| { |
| d->resize(e->size()); |
| QWidget::resizeEvent(e); |
| } |
| |
| |
| /*! \reimp |
| |
| */ |
| |
| void Q3DateTimeEditor::paintEvent(QPaintEvent *) |
| { |
| QString txt; |
| for (uint i = 0; i < d->sectionCount(); ++i) { |
| txt += cw->sectionFormattedText(i); |
| if (i < d->sectionCount()-1) { |
| if (d->section(i+1).separator()) |
| txt += d->separator(); |
| else |
| txt += QLatin1Char(' '); |
| } |
| } |
| |
| QPainter p(this); |
| const QBrush &bg = palette().brush(isEnabled() ? QPalette::Base : QPalette::Window); |
| p.fillRect(0, 0, width(), height(), bg); |
| d->paint(txt, hasFocus(), p, palette(), rect(), style()); |
| } |
| |
| |
| /*! |
| Returns the section index at point \a p. |
| */ |
| int Q3DateTimeEditor::sectionAt(const QPoint &p) |
| { |
| return d->section(p); |
| } |
| |
| int Q3DateTimeEditor::mapSection(int sec) |
| { |
| return d->mapSection(sec); |
| } |
| |
| |
| /*! \reimp |
| |
| */ |
| |
| void Q3DateTimeEditor::mousePressEvent(QMouseEvent *e) |
| { |
| QPoint p(e->pos().x(), 0); |
| int sec = sectionAt(p); |
| if (sec != -1) { |
| cw->setFocusSection(sec); |
| repaint(rect()); |
| } |
| } |
| |
| /*! \reimp |
| |
| */ |
| bool Q3DateTimeEditor::eventFilter(QObject *o, QEvent *e) |
| { |
| if (o == this) { |
| if (e->type() == QEvent::KeyPress) { |
| QKeyEvent *ke = (QKeyEvent*)e; |
| switch (ke->key()) { |
| case Qt::Key_Right: |
| if (d->focusSection() < (int)d->sectionCount()-1) { |
| if (cw->setFocusSection(focusSection()+1)) |
| repaint(rect()); |
| } |
| return true; |
| case Qt::Key_Left: |
| if (d->focusSection() > 0) { |
| if (cw->setFocusSection(focusSection()-1)) |
| repaint(rect()); |
| } |
| return true; |
| case Qt::Key_Up: |
| cw->stepUp(); |
| return true; |
| case Qt::Key_Down: |
| cw->stepDown(); |
| return true; |
| case Qt::Key_Backspace: |
| if (qobject_cast<Q3DateEdit*>(cw)) |
| ((Q3DateEdit*)cw)->removeFirstNumber(d->focusSection()); |
| else if (qobject_cast<Q3TimeEdit*>(cw)) |
| ((Q3TimeEdit*)cw)->removeFirstNumber(d->focusSection()); |
| return true; |
| case Qt::Key_Delete: |
| cw->removeLastNumber(d->focusSection()); |
| return true; |
| case Qt::Key_Tab: |
| case Qt::Key_BackTab: { |
| if (ke->state() == Qt::ControlButton) |
| return false; |
| QWidget *w = this; |
| bool hadDateEdit = false; |
| while (w) { |
| if (qobject_cast<QDateTimeSpinWidget*>(w) || qobject_cast<Q3DateTimeEdit*>(w)) |
| break; |
| hadDateEdit = hadDateEdit || qobject_cast<Q3DateEdit*>(w); |
| w = w->parentWidget(); |
| } |
| if (w) { |
| if (!qobject_cast<Q3DateTimeEdit*>(w)) { |
| w = w->parentWidget(); |
| } else { |
| Q3DateTimeEdit *ed = (Q3DateTimeEdit*)w; |
| if (hadDateEdit && ke->key() == Qt::Key_Tab) { |
| ed->timeEdit()->setFocus(); |
| return true; |
| } else if (!hadDateEdit && ke->key() == Qt::Key_BackTab) { |
| ed->dateEdit()->setFocus(); |
| return true; |
| } else { |
| while (w && !qobject_cast<Q3DateTimeEdit*>(w)) |
| w = w->parentWidget(); |
| } |
| } |
| qApp->sendEvent(w, e); |
| return true; |
| } |
| } break; |
| default: |
| QString txt = ke->text().toLower(); |
| if (!txt.isEmpty() && !separator().isEmpty() && txt[0] == separator()[0]) { |
| // do the same thing as KEY_RIGHT when the user presses the separator key |
| if (d->focusSection() < 2) { |
| if (cw->setFocusSection(focusSection()+1)) |
| repaint(rect()); |
| } |
| return true; |
| } else if (!txt.isEmpty() && qobject_cast<Q3TimeEdit*>(cw) && focusSection() == (int) d->sectionCount()-1) { |
| // the first character of the AM/PM indicator toggles if the section has focus |
| Q3TimeEdit *te = (Q3TimeEdit*)cw; |
| QTime time = te->time(); |
| if (lAMPM && lAM && lPM && (te->display()&Q3TimeEdit::AMPM)) { |
| if (txt[0] == (*lAM).toLower()[0] && time.hour() >= 12) { |
| time.setHMS(time.hour()-12, time.minute(), time.second(), time.msec()); |
| te->setTime(time); |
| } else if (txt[0] == (*lPM).toLower()[0] && time.hour() < 12) { |
| time.setHMS(time.hour()+12, time.minute(), time.second(), time.msec()); |
| te->setTime(time); |
| } |
| } |
| } |
| |
| int num = txt[0].digitValue(); |
| if (num != -1) { |
| cw->addNumber(d->focusSection(), num); |
| return true; |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| |
| /*! |
| Appends the number section \a sec to the editor. |
| */ |
| |
| void Q3DateTimeEditor::appendSection(const QNumberSection& sec) |
| { |
| d->appendSection(sec); |
| } |
| |
| /*! |
| Removes all sections from the editor. |
| */ |
| |
| void Q3DateTimeEditor::clearSections() |
| { |
| d->clearSections(); |
| } |
| |
| /*! |
| Sets the selection of \a sec to start at \a selstart and end at \a |
| selend. |
| */ |
| |
| void Q3DateTimeEditor::setSectionSelection(int sec, int selstart, int selend) |
| { |
| d->setSectionSelection(sec, selstart, selend); |
| } |
| |
| /*! |
| Sets the separator for all numbered sections to \a s. Note that |
| currently, only the first character of \a s is used. |
| */ |
| |
| void Q3DateTimeEditor::setSeparator(const QString& s) |
| { |
| d->setSeparator(s); |
| update(); |
| } |
| |
| |
| /*! |
| Returns the editor's separator. |
| */ |
| |
| QString Q3DateTimeEditor::separator() const |
| { |
| return d->separator(); |
| } |
| |
| /*! |
| Returns the number of the section that has focus. |
| */ |
| |
| int Q3DateTimeEditor::focusSection() const |
| { |
| return d->focusSection(); |
| } |
| |
| |
| /*! |
| Sets the focus to section \a sec. If \a sec does not exist, |
| nothing happens. |
| */ |
| |
| bool Q3DateTimeEditor::setFocusSection(int sec) |
| { |
| return d->setFocusSection(sec); |
| } |
| |
| /*! |
| \class Q3DateTimeEditBase |
| \brief The Q3DateTimeEditBase class provides an abstraction for date and edit editors. |
| |
| \compat |
| |
| Small abstract class that provides some functions that are common |
| for both Q3DateEdit and Q3TimeEdit. It is used internally by |
| Q3DateTimeEditor. |
| */ |
| |
| /*! |
| \fn Q3DateTimeEditBase::Q3DateTimeEditBase(QWidget *, const char*) |
| \internal |
| */ |
| |
| /*! |
| \fn Q3DateTimeEditBase::setFocusSection(int) |
| \internal |
| */ |
| |
| /*! \fn QString Q3DateTimeEditBase::sectionFormattedText(int sec) |
| \internal |
| |
| Pure virtual function which returns the formatted text of section \a |
| sec. |
| |
| */ |
| |
| /*! \fn void Q3DateTimeEditBase::stepUp() |
| \internal |
| |
| Pure virtual slot which is called whenever the user increases the |
| number in a section by pressing the widget's arrow buttons or the |
| keyboard's arrow keys. |
| */ |
| |
| /*! \fn void Q3DateTimeEditBase::stepDown() |
| \internal |
| |
| Pure virtual slot which is called whenever the user decreases the |
| number in a section by pressing the widget's arrow buttons or the |
| keyboard's arrow keys. |
| |
| */ |
| |
| /*! \fn void Q3DateTimeEditBase::addNumber(int sec, int num) |
| \internal |
| |
| Pure virtual function which is called whenever the user types a number. |
| \a sec indicates the section where the number should be added. \a |
| num is the number that was pressed. |
| */ |
| |
| /*! \fn void Q3DateTimeEditBase::removeLastNumber(int sec) |
| \internal |
| |
| Pure virtual function which is called whenever the user tries to |
| remove the last number from \a sec by pressing the delete key. |
| */ |
| |
| //////////////// |
| |
| class Q3DateEditPrivate |
| { |
| public: |
| int y; |
| int m; |
| int d; |
| // remembers the last entry for the day. |
| // if the day is 31 and you cycle through the months, |
| // the day will be 31 again if you reach a month with 31 days |
| // otherwise it will be the highest day in the month |
| int dayCache; |
| int yearSection; |
| int monthSection; |
| int daySection; |
| Q3DateEdit::Order ord; |
| bool overwrite; |
| bool adv; |
| int timerId; |
| bool typing; |
| QDate min; |
| QDate max; |
| bool changed; |
| Q3DateTimeEditor *ed; |
| Q3SpinWidget *controls; |
| }; |
| |
| |
| /*! |
| \class Q3DateEdit |
| \brief The Q3DateEdit class provides a date editor. |
| |
| \compat |
| |
| Q3DateEdit allows the user to edit dates by using the keyboard or |
| the arrow keys to increase/decrease date values. The arrow keys |
| can be used to move from section to section within the Q3DateEdit |
| box. Dates appear in accordance with the local date/time settings |
| or in year, month, day order if the system doesn't provide this |
| information. It is recommended that the Q3DateEdit be initialised |
| with a date, e.g. |
| |
| \snippet doc/src/snippets/code/src_qt3support_widgets_q3datetimeedit.cpp 0 |
| |
| Here we've created a new Q3DateEdit object initialised with today's |
| date and restricted the valid date range to today plus or minus |
| 365 days. We've set the order to month, day, year. If the auto |
| advance property is true (as we've set it here) when the user |
| completes a section of the date, e.g. enters two digits for the |
| month, they are automatically taken to the next section. |
| |
| The maximum and minimum values for a date value in the date editor |
| default to the maximum and minimum values for a QDate. You can |
| change this by calling setMinValue(), setMaxValue() or setRange(). |
| |
| Terminology: A Q3DateEdit widget comprises three 'sections', one |
| each for the year, month and day. You can change the separator |
| character using Q3DateTimeEditor::setSeparator(), by default the |
| separator will be taken from the systems settings. If that is |
| not possible, it defaults to "-". |
| |
| \img datetimewidgets.png Date Time Widgets |
| |
| \sa QDate Q3TimeEdit Q3DateTimeEdit |
| */ |
| |
| /*! |
| \enum Q3DateEdit::Order |
| |
| This enum defines the order in which the sections that comprise a |
| date appear. |
| |
| \value MDY month-day-year |
| \value DMY day-month-year |
| \value YMD year-month-day (the default) |
| \omitvalue YDM |
| */ |
| |
| /*! |
| \enum Q3TimeEdit::Display |
| |
| This enum defines the sections that comprise a time |
| |
| \value Hours The hours section |
| \value Minutes The minutes section |
| \value Seconds The seconds section |
| \value AMPM The AM/PM section |
| |
| The values can be or'ed together to show any combination. |
| */ |
| |
| /*! |
| Constructs an empty date editor which is a child of \a parent and |
| called name \a name. |
| */ |
| |
| Q3DateEdit::Q3DateEdit(QWidget * parent, const char * name) |
| : Q3DateTimeEditBase(parent, name) |
| { |
| init(); |
| updateButtons(); |
| } |
| |
| /*! |
| \overload |
| |
| Constructs a date editor with the initial value \a date, parent \a |
| parent and called \a name. |
| |
| The date editor is initialized with \a date. |
| */ |
| |
| Q3DateEdit::Q3DateEdit(const QDate& date, QWidget * parent, const char * name) |
| : Q3DateTimeEditBase(parent, name) |
| { |
| init(); |
| setDate(date); |
| } |
| |
| /*! \internal |
| */ |
| void Q3DateEdit::init() |
| { |
| d = new Q3DateEditPrivate(); |
| d->controls = new QDateTimeSpinWidget(this, 0); |
| d->ed = new Q3DateTimeEditor(this, d->controls); |
| d->controls->setEditWidget(d->ed); |
| setFocusProxy(d->ed); |
| connect(d->controls, SIGNAL(stepUpPressed()), SLOT(stepUp())); |
| connect(d->controls, SIGNAL(stepDownPressed()), SLOT(stepDown())); |
| connect(this, SIGNAL(valueChanged(QDate)), SLOT(updateButtons())); |
| d->ed->appendSection(QNumberSection(0,4)); |
| d->ed->appendSection(QNumberSection(5,7)); |
| d->ed->appendSection(QNumberSection(8,10)); |
| |
| d->yearSection = -1; |
| d->monthSection = -1; |
| d->daySection = -1; |
| |
| d->y = 0; |
| d->m = 0; |
| d->d = 0; |
| d->dayCache = 0; |
| setOrder(localOrder()); |
| setFocusSection(0); |
| d->overwrite = true; |
| d->adv = false; |
| d->timerId = 0; |
| d->typing = false; |
| d->min = QDate(1752, 9, 14); |
| d->max = QDate(8000, 12, 31); |
| d->changed = false; |
| |
| setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); |
| |
| refcount++; |
| } |
| |
| /*! |
| Destroys the object and frees any allocated resources. |
| */ |
| |
| Q3DateEdit::~Q3DateEdit() |
| { |
| delete d; |
| if (!--refcount) |
| cleanup(); |
| } |
| |
| /*! |
| \property Q3DateEdit::minValue |
| |
| \brief the editor's minimum value |
| |
| Setting the minimum date value is equivalent to calling |
| Q3DateEdit::setRange(\e d, maxValue()), where \e d is the minimum |
| date. The default minimum date is 1752-09-14. |
| |
| \sa maxValue setRange() |
| */ |
| |
| QDate Q3DateEdit::minValue() const |
| { |
| return d->min; |
| } |
| |
| /*! |
| \property Q3DateEdit::maxValue |
| |
| \brief the editor's maximum value |
| |
| Setting the maximum date value for the editor is equivalent to |
| calling Q3DateEdit::setRange(minValue(), \e d), where \e d is the |
| maximum date. The default maximum date is 8000-12-31. |
| |
| \sa minValue setRange() |
| */ |
| |
| QDate Q3DateEdit::maxValue() const |
| { |
| return d->max; |
| } |
| |
| |
| /*! |
| Sets the valid input range for the editor to be from \a min to \a |
| max inclusive. If \a min is invalid no minimum date will be set. |
| Similarly, if \a max is invalid no maximum date will be set. |
| */ |
| |
| void Q3DateEdit::setRange(const QDate& min, const QDate& max) |
| { |
| if (min.isValid()) |
| d->min = min; |
| if (max.isValid()) |
| d->max = max; |
| } |
| |
| /*! |
| Sets the separator to \a s. Note that currently only the first |
| character of \a s is used. |
| */ |
| |
| void Q3DateEdit::setSeparator(const QString& s) |
| { |
| d->ed->setSeparator(s); |
| } |
| |
| /*! |
| Returns the editor's separator. |
| */ |
| |
| QString Q3DateEdit::separator() const |
| { |
| return d->ed->separator(); |
| } |
| |
| |
| /*! |
| Enables/disables the push buttons according to the min/max date |
| for this widget. |
| */ |
| |
| void Q3DateEdit::updateButtons() |
| { |
| if (!isEnabled()) |
| return; |
| |
| bool upEnabled = date() < maxValue(); |
| bool downEnabled = date() > minValue(); |
| |
| d->controls->setUpEnabled(upEnabled); |
| d->controls->setDownEnabled(downEnabled); |
| } |
| |
| /*! \reimp |
| */ |
| void Q3DateEdit::resizeEvent(QResizeEvent *) |
| { |
| d->controls->resize(width(), height()); |
| } |
| |
| /*! \reimp |
| |
| */ |
| QSize Q3DateEdit::sizeHint() const |
| { |
| ensurePolished(); |
| QFontMetrics fm(font()); |
| int fw = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, this); |
| int h = qMax(fm.lineSpacing(), 14) + 2; |
| int w = 2 + fm.width(QLatin1Char('9')) * 8 + fm.width(d->ed->separator()) * 2 + d->controls->upRect().width() + fw * 4; |
| |
| return QSize(w, qMax(h + fw * 2,20)).expandedTo(QApplication::globalStrut()); |
| } |
| |
| /*! \reimp |
| |
| */ |
| QSize Q3DateEdit::minimumSizeHint() const |
| { |
| return sizeHint(); |
| } |
| |
| |
| /*! |
| Returns the formatted number for section \a sec. This will |
| correspond to either the year, month or day section, depending on |
| the current display order. |
| |
| \sa setOrder() |
| */ |
| |
| QString Q3DateEdit::sectionFormattedText(int sec) |
| { |
| QString txt; |
| txt = sectionText(sec); |
| if (d->typing && sec == d->ed->focusSection()) |
| d->ed->setSectionSelection(sec, sectionOffsetEnd(sec) - txt.length(), |
| sectionOffsetEnd(sec)); |
| else |
| d->ed->setSectionSelection(sec, sectionOffsetEnd(sec) - sectionLength(sec), |
| sectionOffsetEnd(sec)); |
| txt = txt.rightJustified(sectionLength(sec), QDATETIMEEDIT_HIDDEN_CHAR); |
| return txt; |
| } |
| |
| |
| /*! |
| Returns the desired length (number of digits) of section \a sec. |
| This will correspond to either the year, month or day section, |
| depending on the current display order. |
| |
| \sa setOrder() |
| */ |
| |
| int Q3DateEdit::sectionLength(int sec) const |
| { |
| int val = 0; |
| if (sec == d->yearSection) { |
| val = 4; |
| } else if (sec == d->monthSection) { |
| val = 2; |
| } else if (sec == d->daySection) { |
| val = 2; |
| } |
| return val; |
| } |
| |
| /*! |
| Returns the text of section \a sec. This will correspond to either |
| the year, month or day section, depending on the current display |
| order. |
| |
| \sa setOrder() |
| */ |
| |
| QString Q3DateEdit::sectionText(int sec) const |
| { |
| int val = 0; |
| if (sec == d->yearSection) { |
| val = d->y; |
| } else if (sec == d->monthSection) { |
| val = d->m; |
| } else if (sec == d->daySection) { |
| val = d->d; |
| } |
| return QString::number(val); |
| } |
| |
| /*! \internal |
| |
| Returns the end of the section offset \a sec. |
| |
| */ |
| |
| int Q3DateEdit::sectionOffsetEnd(int sec) const |
| { |
| if (sec == d->yearSection) { |
| switch(d->ord) { |
| case DMY: |
| case MDY: |
| return sectionOffsetEnd(sec-1) + separator().length() + sectionLength(sec); |
| case YMD: |
| case YDM: |
| return sectionLength(sec); |
| } |
| } else if (sec == d->monthSection) { |
| switch(d->ord) { |
| case DMY: |
| case YDM: |
| case YMD: |
| return sectionOffsetEnd(sec-1) + separator().length() + sectionLength(sec); |
| case MDY: |
| return sectionLength(sec); |
| } |
| } else if (sec == d->daySection) { |
| switch(d->ord) { |
| case DMY: |
| return sectionLength(sec); |
| case YMD: |
| case MDY: |
| case YDM: |
| return sectionOffsetEnd(sec-1) + separator().length() + sectionLength(sec); |
| } |
| } |
| return 0; |
| } |
| |
| |
| /*! |
| \property Q3DateEdit::order |
| \brief the order in which the year, month and day appear |
| |
| The default order is locale dependent. |
| |
| \sa Order |
| */ |
| |
| void Q3DateEdit::setOrder(Q3DateEdit::Order order) |
| { |
| d->ord = order; |
| switch(d->ord) { |
| case DMY: |
| d->yearSection = 2; |
| d->monthSection = 1; |
| d->daySection = 0; |
| break; |
| case MDY: |
| d->yearSection = 2; |
| d->monthSection = 0; |
| d->daySection = 1; |
| break; |
| case YMD: |
| d->yearSection = 0; |
| d->monthSection = 1; |
| d->daySection = 2; |
| break; |
| case YDM: |
| d->yearSection = 0; |
| d->monthSection = 2; |
| d->daySection = 1; |
| break; |
| } |
| if (isVisible()) |
| d->ed->repaint(d->ed->rect()); |
| } |
| |
| |
| Q3DateEdit::Order Q3DateEdit::order() const |
| { |
| return d->ord; |
| } |
| |
| |
| /*! \internal |
| |
| */ |
| void Q3DateEdit::stepUp() |
| { |
| int sec = d->ed->focusSection(); |
| bool accepted = false; |
| if (sec == d->yearSection) { |
| if (!outOfRange(d->y+1, d->m, d->d)) { |
| accepted = true; |
| setYear(d->y+1); |
| } |
| } else if (sec == d->monthSection) { |
| if (!outOfRange(d->y, d->m+1, d->d)) { |
| accepted = true; |
| setMonth(d->m+1); |
| } |
| } else if (sec == d->daySection) { |
| if (!outOfRange(d->y, d->m, d->d+1)) { |
| accepted = true; |
| setDay(d->d+1); |
| } |
| } |
| if (accepted) { |
| d->changed = false; |
| emit valueChanged(date()); |
| } |
| d->ed->repaint(d->ed->rect()); |
| } |
| |
| |
| |
| /*! \internal |
| |
| */ |
| |
| void Q3DateEdit::stepDown() |
| { |
| int sec = d->ed->focusSection(); |
| bool accepted = false; |
| if (sec == d->yearSection) { |
| if (!outOfRange(d->y-1, d->m, d->d)) { |
| accepted = true; |
| setYear(d->y-1); |
| } |
| } else if (sec == d->monthSection) { |
| if (!outOfRange(d->y, d->m-1, d->d)) { |
| accepted = true; |
| setMonth(d->m-1); |
| } |
| } else if (sec == d->daySection) { |
| if (!outOfRange(d->y, d->m, d->d-1)) { |
| accepted = true; |
| setDay(d->d-1); |
| } |
| } |
| if (accepted) { |
| d->changed = false; |
| emit valueChanged(date()); |
| } |
| d->ed->repaint(d->ed->rect()); |
| } |
| |
| /*! |
| Sets the year to \a year, which must be a valid year. The range |
| currently supported is from 1752 to 8000. |
| |
| \sa QDate |
| */ |
| |
| void Q3DateEdit::setYear(int year) |
| { |
| if (year < 1752) |
| year = 1752; |
| if (year > 8000) |
| year = 8000; |
| if (!outOfRange(year, d->m, d->d)) { |
| d->y = year; |
| setMonth(d->m); |
| int tmp = d->dayCache; |
| setDay(d->dayCache); |
| d->dayCache = tmp; |
| } |
| } |
| |
| |
| /*! |
| Sets the month to \a month, which must be a valid month, i.e. |
| between 1 and 12. |
| */ |
| |
| void Q3DateEdit::setMonth(int month) |
| { |
| if (month < 1) |
| month = 1; |
| if (month > 12) |
| month = 12; |
| if (!outOfRange(d->y, month, d->d)) { |
| d->m = month; |
| int tmp = d->dayCache; |
| setDay(d->dayCache); |
| d->dayCache = tmp; |
| } |
| } |
| |
| |
| /*! |
| Sets the day to \a day, which must be a valid day. The function |
| will ensure that the \a day set is valid for the month and year. |
| */ |
| |
| void Q3DateEdit::setDay(int day) |
| { |
| if (day < 1) |
| day = 1; |
| if (day > 31) |
| day = 31; |
| if (d->m > 0 && d->y > 1752) { |
| while (!QDate::isValid(d->y, d->m, day)) |
| --day; |
| if (!outOfRange(d->y, d->m, day)) |
| d->d = day; |
| } else if (d->m > 0) { |
| if (day > 0 && day < 32) { |
| if (!outOfRange(d->y, d->m, day)) |
| d->d = day; |
| } |
| } |
| d->dayCache = d->d; |
| } |
| |
| |
| /*! |
| \property Q3DateEdit::date |
| \brief the editor's date value. |
| |
| If the date property is not valid, the editor displays all zeroes |
| and Q3DateEdit::date() will return an invalid date. It is strongly |
| recommended that the editor is given a default date value (e.g. |
| currentDate()). That way, attempts to set the date property to an |
| invalid date will fail. |
| |
| When changing the date property, if the date is less than |
| minValue(), or is greater than maxValue(), nothing happens. |
| */ |
| |
| void Q3DateEdit::setDate(const QDate& date) |
| { |
| if (!date.isValid()) { |
| d->y = 0; |
| d->m = 0; |
| d->d = 0; |
| d->dayCache = 0; |
| } else { |
| if (date > maxValue() || date < minValue()) |
| return; |
| d->y = date.year(); |
| d->m = date.month(); |
| d->d = date.day(); |
| d->dayCache = d->d; |
| emit valueChanged(date); |
| } |
| d->changed = false; |
| d->ed->repaint(d->ed->rect()); |
| } |
| |
| QDate Q3DateEdit::date() const |
| { |
| if (QDate::isValid(d->y, d->m, d->d)) |
| return QDate(d->y, d->m, d->d); |
| return QDate(); |
| } |
| |
| /*! \internal |
| |
| Returns true if \a y, \a m, \a d is out of range, otherwise returns |
| false. |
| |
| \sa setRange() |
| |
| */ |
| |
| bool Q3DateEdit::outOfRange(int y, int m, int d) const |
| { |
| if (QDate::isValid(y, m, d)) { |
| QDate currentDate(y, m, d); |
| if (currentDate > maxValue() || |
| currentDate < minValue()) { |
| //## outOfRange should set overwrite? |
| return true; |
| } |
| return false; |
| } |
| return false; /* assume ok */ |
| } |
| |
| /*! \internal |
| |
| */ |
| |
| void Q3DateEdit::addNumber(int sec, int num) |
| { |
| if (sec == -1) |
| return; |
| if (d->timerId) |
| killTimer(d->timerId); |
| d->timerId = 0; |
| bool overwrite = false; |
| bool accepted = false; |
| d->typing = true; |
| QString txt; |
| if (sec == d->yearSection) { |
| txt = QString::number(d->y); |
| if (d->overwrite || txt.length() == 4) { |
| accepted = true; |
| d->y = num; |
| } else { |
| txt += QString::number(num); |
| if (txt.length() == 4 ) { |
| const int val = qBound(1792, txt.toInt(), 8000); |
| if (outOfRange(val, d->m, d->d)) { |
| txt = QString::number(d->y); |
| } else { |
| accepted = true; |
| d->y = val; |
| } |
| } else { |
| accepted = true; |
| d->y = txt.toInt(); |
| } |
| if (d->adv && txt.length() == 4) { |
| d->ed->setFocusSection(d->ed->focusSection()+1); |
| overwrite = true; |
| } |
| } |
| } else if (sec == d->monthSection) { |
| txt = QString::number(d->m); |
| if (d->overwrite || txt.length() == 2) { |
| accepted = true; |
| d->m = num; |
| } else { |
| txt += QString::number(num); |
| int temp = txt.toInt(); |
| if (temp > 12) |
| temp = num; |
| if (outOfRange(d->y, temp, d->d)) |
| txt = QString::number(d->m); |
| else { |
| accepted = true; |
| d->m = temp; |
| } |
| if (d->adv && txt.length() == 2) { |
| d->ed->setFocusSection(d->ed->focusSection()+1); |
| overwrite = true; |
| } |
| } |
| } else if (sec == d->daySection) { |
| txt = QString::number(d->d); |
| if (d->overwrite || txt.length() == 2) { |
| accepted = true; |
| d->d = num; |
| d->dayCache = d->d; |
| } else { |
| txt += QString::number(num); |
| int temp = txt.toInt(); |
| if (temp > 31) |
| temp = num; |
| if (outOfRange(d->y, d->m, temp)) |
| txt = QString::number(d->d); |
| else { |
| accepted = true; |
| d->d = temp; |
| d->dayCache = d->d; |
| } |
| if (d->adv && txt.length() == 2) { |
| d->ed->setFocusSection(d->ed->focusSection()+1); |
| overwrite = true; |
| } |
| } |
| } |
| if (accepted) { |
| d->changed = false; |
| emit valueChanged(date()); |
| } |
| d->overwrite = overwrite; |
| d->timerId = startTimer(qApp->doubleClickInterval()*4); |
| d->ed->repaint(d->ed->rect()); |
| } |
| |
| |
| /*! \internal |
| |
| */ |
| |
| bool Q3DateEdit::setFocusSection(int s) |
| { |
| if (s != d->ed->focusSection()) { |
| if (d->timerId) |
| killTimer(d->timerId); |
| d->timerId = 0; |
| d->overwrite = true; |
| d->typing = false; |
| fix(); // will emit valueChanged if necessary |
| } |
| return d->ed->setFocusSection(s); |
| } |
| |
| |
| /*! |
| Attempts to fix any invalid date entries. |
| |
| The rules applied are as follows: |
| |
| \list |
| \i If the year has four digits it is left unchanged. |
| \i If the year has two digits, the year will be changed to four |
| digits in the range current year - 70 to current year + 29. |
| \i If the year has three digits in the range 100..999, the |
| current millennium, i.e. 2000, will be added giving a year |
| in the range 2100..2999. |
| \i If the day or month is 0 then it will be set to 1 or the |
| minimum valid day/month in the range. |
| \endlist |
| */ |
| |
| void Q3DateEdit::fix() |
| { |
| bool changed = false; |
| int currentYear = QDate::currentDate().year(); |
| int year = d->y; |
| if (year < 100) { |
| int currentCentury = currentYear / 100; |
| year += currentCentury * 100; |
| if (currentYear > year) { |
| if (currentYear > year + 70) |
| year += 100; |
| } else { |
| if (year >= currentYear + 30) |
| year -= 100; |
| } |
| changed = true; |
| } else if (year < 1000) { |
| int currentMillennium = currentYear / 10; |
| year += currentMillennium * 10; |
| changed = true; |
| } else if (d->d == 0) { |
| d->d = 1; |
| changed = true; |
| } else if (d->m == 0) { |
| d->m = 1; |
| changed = true; |
| } |
| if (outOfRange(year, d->m, d->d)) { |
| if (minValue().isValid() && date() < minValue()) { |
| d->d = minValue().day(); |
| d->dayCache = d->d; |
| d->m = minValue().month(); |
| d->y = minValue().year(); |
| } |
| if (date() > maxValue()) { |
| d->d = maxValue().day(); |
| d->dayCache = d->d; |
| d->m = maxValue().month(); |
| d->y = maxValue().year(); |
| } |
| changed = true; |
| } else if (changed) |
| setYear(year); |
| if (changed) { |
| emit valueChanged(date()); |
| d->changed = false; |
| } |
| } |
| |
| |
| /*! \reimp |
| |
| */ |
| |
| bool Q3DateEdit::event(QEvent *e) |
| { |
| if(e->type() == QEvent::FocusOut) { |
| d->typing = false; |
| fix(); |
| // the following can't be done in fix() because fix() called |
| // from all over the place and it will break the old behaviour |
| if (!QDate::isValid(d->y, d->m, d->d)) { |
| d->dayCache = d->d; |
| int i = d->d; |
| for (; i > 0; i--) { |
| d->d = i; |
| if (QDate::isValid(d->y, d->m, d->d)) |
| break; |
| } |
| d->changed = true; |
| } |
| if (d->changed) { |
| emit valueChanged(date()); |
| d->changed = false; |
| } |
| } else if (e->type() == QEvent::LocaleChange) { |
| readLocaleSettings(); |
| d->ed->setSeparator(localDateSep()); |
| setOrder(localOrder()); |
| } |
| return Q3DateTimeEditBase::event(e); |
| } |
| |
| /*! |
| \internal |
| |
| Function which is called whenever the user tries to |
| remove the first number from \a sec by pressing the backspace key. |
| */ |
| |
| void Q3DateEdit::removeFirstNumber(int sec) |
| { |
| if (sec == -1) |
| return; |
| QString txt; |
| if (sec == d->yearSection) { |
| txt = QString::number(d->y); |
| txt = txt.mid(1, txt.length()) + QLatin1Char('0'); |
| d->y = txt.toInt(); |
| } else if (sec == d->monthSection) { |
| txt = QString::number(d->m); |
| txt = txt.mid(1, txt.length()) + QLatin1Char('0'); |
| d->m = txt.toInt(); |
| } else if (sec == d->daySection) { |
| txt = QString::number(d->d); |
| txt = txt.mid(1, txt.length()) + QLatin1Char('0'); |
| d->d = txt.toInt(); |
| d->dayCache = d->d; |
| } |
| d->ed->repaint(d->ed->rect()); |
| } |
| |
| /*! \internal |
| |
| */ |
| |
| void Q3DateEdit::removeLastNumber(int sec) |
| { |
| if (sec == -1) |
| return; |
| QString txt; |
| if (sec == d->yearSection) { |
| txt = QString::number(d->y); |
| txt = txt.mid(0, txt.length()-1); |
| d->y = txt.toInt(); |
| } else if (sec == d->monthSection) { |
| txt = QString::number(d->m); |
| txt = txt.mid(0, txt.length()-1); |
| d->m = txt.toInt(); |
| } else if (sec == d->daySection) { |
| txt = QString::number(d->d); |
| txt = txt.mid(0, txt.length()-1); |
| d->d = txt.toInt(); |
| d->dayCache = d->d; |
| } |
| d->ed->repaint(d->ed->rect()); |
| } |
| |
| /*! |
| \property Q3DateEdit::autoAdvance |
| \brief whether the editor automatically advances to the next |
| section |
| |
| If autoAdvance is true, the editor will automatically advance |
| focus to the next date section if a user has completed a section. |
| The default is false. |
| */ |
| |
| void Q3DateEdit::setAutoAdvance(bool advance) |
| { |
| d->adv = advance; |
| } |
| |
| |
| bool Q3DateEdit::autoAdvance() const |
| { |
| return d->adv; |
| } |
| |
| /*! \reimp |
| */ |
| |
| void Q3DateEdit::timerEvent(QTimerEvent *) |
| { |
| d->overwrite = true; |
| } |
| |
| /*! |
| \fn void Q3DateEdit::valueChanged(const QDate& date) |
| |
| This signal is emitted whenever the editor's value changes. The \a |
| date parameter is the new value. |
| */ |
| |
| /////////// |
| |
| class Q3TimeEditPrivate |
| { |
| public: |
| int h; |
| int m; |
| int s; |
| uint display; |
| bool adv; |
| bool overwrite; |
| int timerId; |
| bool typing; |
| QTime min; |
| QTime max; |
| bool changed; |
| Q3DateTimeEditor *ed; |
| Q3SpinWidget *controls; |
| }; |
| |
| /*! |
| \class Q3TimeEdit |
| \brief The Q3TimeEdit class provides a time editor. |
| |
| \compat |
| |
| Q3TimeEdit allows the user to edit times by using the keyboard or |
| the arrow keys to increase/decrease time values. The arrow keys |
| can be used to move from section to section within the Q3TimeEdit |
| box. The user can automatically be moved to the next section once |
| they complete a section using setAutoAdvance(). Times appear in |
| hour, minute, second order. It is recommended that the Q3TimeEdit |
| is initialised with a time, e.g. |
| \snippet doc/src/snippets/code/src_qt3support_widgets_q3datetimeedit.cpp 1 |
| Here we've created a Q3TimeEdit widget set to the current time. |
| We've also set the minimum value to the current time and the |
| maximum time to one hour from now. |
| |
| The maximum and minimum values for a time value in the time editor |
| default to the maximum and minimum values for a QTime. You can |
| change this by calling setMinValue(), setMaxValue() or setRange(). |
| |
| Terminology: A QTimeWidget consists of three sections, one each |
| for the hour, minute and second. You can change the separator |
| character using setSeparator(), by default the separator is read |
| from the system's settings. |
| |
| \img datetimewidgets.png Date Time Widgets |
| |
| \sa QTime Q3DateEdit Q3DateTimeEdit |
| */ |
| |
| |
| /*! |
| Constructs an empty time edit with parent \a parent and called \a |
| name. |
| */ |
| |
| Q3TimeEdit::Q3TimeEdit(QWidget * parent, const char * name) |
| : Q3DateTimeEditBase(parent, name) |
| { |
| init(); |
| } |
| |
| /*! |
| \overload |
| |
| Constructs a time edit with the initial time value, \a time, |
| parent \a parent and called \a name. |
| */ |
| |
| Q3TimeEdit::Q3TimeEdit(const QTime& time, QWidget * parent, const char * name) |
| : Q3DateTimeEditBase(parent, name) |
| { |
| init(); |
| setTime(time); |
| } |
| |
| /*! \internal |
| */ |
| |
| void Q3TimeEdit::init() |
| { |
| d = new Q3TimeEditPrivate(); |
| d->controls = new QDateTimeSpinWidget(this, 0); |
| d->ed = new Q3DateTimeEditor(this, d->controls, "time edit base"); |
| d->controls->setEditWidget(d->ed); |
| setFocusProxy(d->ed); |
| connect(d->controls, SIGNAL(stepUpPressed()), SLOT(stepUp())); |
| connect(d->controls, SIGNAL(stepDownPressed()), SLOT(stepDown())); |
| |
| d->ed->appendSection(QNumberSection(0,0, true, 0)); |
| d->ed->appendSection(QNumberSection(0,0, true, 1)); |
| d->ed->appendSection(QNumberSection(0,0, true, 2)); |
| d->ed->setSeparator(localTimeSep()); |
| |
| d->h = 0; |
| d->m = 0; |
| d->s = 0; |
| d->display = Hours | Minutes | Seconds; |
| if (lAMPM) { |
| d->display |= AMPM; |
| d->ed->appendSection(QNumberSection(0,0, false, 3)); |
| } |
| d->adv = false; |
| d->overwrite = true; |
| d->timerId = 0; |
| d->typing = false; |
| d->min = QTime(0, 0, 0); |
| d->max = QTime(23, 59, 59); |
| d->changed = false; |
| |
| setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); |
| |
| refcount++; |
| } |
| |
| /*! |
| Destroys the object and frees any allocated resources. |
| */ |
| |
| Q3TimeEdit::~Q3TimeEdit() |
| { |
| delete d; |
| if (!--refcount) |
| cleanup(); |
| } |
| |
| /*! |
| \property Q3TimeEdit::minValue |
| \brief the minimum time value |
| |
| Setting the minimum time value is equivalent to calling |
| Q3TimeEdit::setRange(\e t, maxValue()), where \e t is the minimum |
| time. The default minimum time is 00:00:00. |
| |
| \sa maxValue setRange() |
| */ |
| |
| QTime Q3TimeEdit::minValue() const |
| { |
| return d->min; |
| } |
| |
| /*! |
| \property Q3TimeEdit::maxValue |
| \brief the maximum time value |
| |
| Setting the maximum time value is equivalent to calling |
| Q3TimeEdit::setRange(minValue(), \e t), where \e t is the maximum |
| time. The default maximum time is 23:59:59. |
| |
| \sa minValue setRange() |
| */ |
| |
| QTime Q3TimeEdit::maxValue() const |
| { |
| return d->max; |
| } |
| |
| |
| /*! |
| Sets the valid input range for the editor to be from \a min to \a |
| max inclusive. If \a min is invalid no minimum time is set. |
| Similarly, if \a max is invalid no maximum time is set. |
| */ |
| |
| void Q3TimeEdit::setRange(const QTime& min, const QTime& max) |
| { |
| if (min.isValid()) |
| d->min = min; |
| if (max.isValid()) |
| d->max = max; |
| } |
| |
| /*! |
| \property Q3TimeEdit::display |
| \brief the sections that are displayed in the time edit |
| |
| The value can be any combination of the values in the Display enum. |
| By default, the widget displays hours, minutes and seconds. |
| */ |
| void Q3TimeEdit::setDisplay(uint display) |
| { |
| if (d->display == display) |
| return; |
| |
| d->ed->clearSections(); |
| d->display = display; |
| if (d->display & Hours) |
| d->ed->appendSection(QNumberSection(0,0, true, 0)); |
| if (d->display & Minutes) |
| d->ed->appendSection(QNumberSection(0,0, true, 1)); |
| if (d->display & Seconds) |
| d->ed->appendSection(QNumberSection(0,0, true, 2)); |
| if (d->display & AMPM) |
| d->ed->appendSection(QNumberSection(0,0, false, 3)); |
| |
| d->ed->setFocusSection(0); |
| d->ed->update(); |
| } |
| |
| uint Q3TimeEdit::display() const |
| { |
| return d->display; |
| } |
| |
| /*! |
| \property Q3TimeEdit::time |
| \brief the editor's time value. |
| |
| When changing the time property, if the time is less than |
| minValue(), or is greater than maxValue(), nothing happens. |
| */ |
| |
| void Q3TimeEdit::setTime(const QTime& time) |
| { |
| if (!time.isValid()) { |
| d->h = 0; |
| d->m = 0; |
| d->s = 0; |
| } else { |
| if (time > maxValue() || time < minValue()) |
| return; |
| d->h = time.hour(); |
| d->m = time.minute(); |
| d->s = time.second(); |
| emit valueChanged(time); |
| } |
| d->changed = false; |
| d->ed->repaint(d->ed->rect()); |
| } |
| |
| QTime Q3TimeEdit::time() const |
| { |
| if (QTime::isValid(d->h, d->m, d->s)) |
| return QTime(d->h, d->m, d->s); |
| return QTime(); |
| } |
| |
| /*! |
| \property Q3TimeEdit::autoAdvance |
| \brief whether the editor automatically advances to the next |
| section |
| |
| If autoAdvance is true, the editor will automatically advance |
| focus to the next time section if a user has completed a section. |
| The default is false. |
| */ |
| |
| void Q3TimeEdit::setAutoAdvance(bool advance) |
| { |
| d->adv = advance; |
| } |
| |
| bool Q3TimeEdit::autoAdvance() const |
| { |
| return d->adv; |
| } |
| |
| /*! |
| Sets the separator to \a s. Note that currently only the first |
| character of \a s is used. |
| */ |
| |
| void Q3TimeEdit::setSeparator(const QString& s) |
| { |
| d->ed->setSeparator(s); |
| } |
| |
| /*! |
| Returns the editor's separator. |
| */ |
| |
| QString Q3TimeEdit::separator() const |
| { |
| return d->ed->separator(); |
| } |
| |
| |
| /*! |
| \fn void Q3TimeEdit::valueChanged(const QTime& time) |
| |
| This signal is emitted whenever the editor's value changes. The \a |
| time parameter is the new value. |
| */ |
| |
| /*! \reimp |
| |
| */ |
| |
| bool Q3TimeEdit::event(QEvent *e) |
| { |
| if (e->type() == QEvent::FocusOut) { |
| d->typing = false; |
| if (d->changed) { |
| emit valueChanged(time()); |
| d->changed = false; |
| } |
| } else if (e->type() == QEvent::LocaleChange) { |
| readLocaleSettings(); |
| d->ed->setSeparator(localTimeSep()); |
| } |
| return Q3DateTimeEditBase::event(e); |
| } |
| |
| /*! \reimp |
| |
| */ |
| |
| void Q3TimeEdit::timerEvent(QTimerEvent *) |
| { |
| d->overwrite = true; |
| } |
| |
| |
| /*! \internal |
| |
| */ |
| |
| void Q3TimeEdit::stepUp() |
| { |
| int sec = d->ed->mapSection(d->ed->focusSection()); |
| bool accepted = true; |
| switch(sec) { |
| case 0: |
| if (!outOfRange(d->h+1, d->m, d->s)) |
| setHour(d->h+1); |
| else |
| setHour(d->min.hour()); |
| break; |
| case 1: |
| if (!outOfRange(d->h, d->m+1, d->s)) |
| setMinute(d->m+1); |
| else |
| setMinute(d->min.minute()); |
| break; |
| case 2: |
| if (!outOfRange(d->h, d->m, d->s+1)) |
| setSecond(d->s+1); |
| else |
| setSecond(d->min.second()); |
| break; |
| case 3: |
| if (d->h < 12) |
| setHour(d->h+12); |
| else |
| setHour(d->h-12); |
| break; |
| default: |
| accepted = false; |
| qWarning("Q3TimeEdit::stepUp: Focus section out of range!"); |
| break; |
| } |
| if (accepted) { |
| d->changed = false; |
| emit valueChanged(time()); |
| } |
| d->ed->repaint(d->ed->rect()); |
| } |
| |
| |
| /*! \internal |
| |
| */ |
| |
| void Q3TimeEdit::stepDown() |
| { |
| int sec = d->ed->mapSection(d->ed->focusSection()); |
| |
| bool accepted = true; |
| switch(sec) { |
| case 0: |
| if (!outOfRange(d->h-1, d->m, d->s)) |
| setHour(d->h-1); |
| else |
| setHour(d->max.hour()); |
| break; |
| case 1: |
| if (!outOfRange(d->h, d->m-1, d->s)) |
| setMinute(d->m-1); |
| else |
| setMinute(d->max.minute()); |
| break; |
| case 2: |
| if (!outOfRange(d->h, d->m, d->s-1)) |
| setSecond(d->s-1); |
| else |
| setSecond(d->max.second()); |
| break; |
| case 3: |
| if (d->h > 11) |
| setHour(d->h-12); |
| else |
| setHour(d->h+12); |
| break; |
| default: |
| accepted = false; |
| qWarning("Q3TimeEdit::stepDown: Focus section out of range!"); |
| break; |
| } |
| if (accepted) { |
| d->changed = false; |
| emit valueChanged(time()); |
| } |
| d->ed->repaint(d->ed->rect()); |
| } |
| |
| |
| /*! |
| Returns the formatted number for section \a sec. This will |
| correspond to either the hour, minute or second section, depending |
| on \a sec. |
| */ |
| |
| QString Q3TimeEdit::sectionFormattedText(int sec) |
| { |
| QString txt; |
| txt = sectionText(sec); |
| txt = txt.rightJustified(2, QDATETIMEEDIT_HIDDEN_CHAR); |
| int offset = sec*2+sec*separator().length() + txt.length(); |
| if (d->typing && sec == d->ed->focusSection()) |
| d->ed->setSectionSelection(sec, offset - txt.length(), offset); |
| else |
| d->ed->setSectionSelection(sec, offset - txt.length(), offset); |
| |
| return txt; |
| } |
| |
| |
| /*! \internal |
| |
| */ |
| |
| bool Q3TimeEdit::setFocusSection(int sec) |
| { |
| if (sec != d->ed->focusSection()) { |
| if (d->timerId) |
| killTimer(d->timerId); |
| d->timerId = 0; |
| d->overwrite = true; |
| d->typing = false; |
| QString txt = sectionText(sec); |
| txt = txt.rightJustified(2, QDATETIMEEDIT_HIDDEN_CHAR); |
| int offset = sec*2+sec*separator().length() + txt.length(); |
| d->ed->setSectionSelection(sec, offset - txt.length(), offset); |
| if (d->changed) { |
| emit valueChanged(time()); |
| d->changed = false; |
| } |
| } |
| return d->ed->setFocusSection(sec); |
| } |
| |
| |
| /*! |
| Sets the hour to \a h, which must be a valid hour, i.e. in the |
| range 0..24. |
| */ |
| |
| void Q3TimeEdit::setHour(int h) |
| { |
| if (h < 0) |
| h = 0; |
| if (h > 23) |
| h = 23; |
| d->h = h; |
| } |
| |
| |
| /*! |
| Sets the minute to \a m, which must be a valid minute, i.e. in the |
| range 0..59. |
| */ |
| |
| void Q3TimeEdit::setMinute(int m) |
| { |
| if (m < 0) |
| m = 0; |
| if (m > 59) |
| m = 59; |
| d->m = m; |
| } |
| |
| |
| /*! |
| Sets the second to \a s, which must be a valid second, i.e. in the |
| range 0..59. |
| */ |
| |
| void Q3TimeEdit::setSecond(int s) |
| { |
| if (s < 0) |
| s = 0; |
| if (s > 59) |
| s = 59; |
| d->s = s; |
| } |
| |
| |
| /*! \internal |
| |
| Returns the text of section \a sec. |
| |
| */ |
| |
| QString Q3TimeEdit::sectionText(int sec) |
| { |
| sec = d->ed->mapSection(sec); |
| |
| QString txt; |
| switch(sec) { |
| case 0: |
| if (!(d->display & AMPM) || (d->h < 13 && d->h)) { // I wished the day stared at 0:00 for everybody |
| txt = QString::number(d->h); |
| } else { |
| if (d->h) |
| txt = QString::number(d->h - 12); |
| else |
| txt = QLatin1String("12"); |
| } |
| break; |
| case 1: |
| txt = QString::number(d->m); |
| break; |
| case 2: |
| txt = QString::number(d->s); |
| break; |
| case 3: |
| if (d->h < 12) { |
| if (lAM) |
| txt = *lAM; |
| else |
| txt = QString::fromLatin1("AM"); |
| } else { |
| if (lPM) |
| txt = *lPM; |
| else |
| txt = QString::fromLatin1("PM"); |
| } |
| break; |
| default: |
| break; |
| } |
| return txt; |
| } |
| |
| |
| /*! \internal |
| Returns true if \a h, \a m, and \a s are out of range. |
| */ |
| |
| bool Q3TimeEdit::outOfRange(int h, int m, int s) const |
| { |
| if (QTime::isValid(h, m, s)) { |
| QTime currentTime(h, m, s); |
| if (currentTime > maxValue() || |
| currentTime < minValue()) |
| return true; |
| else |
| return false; |
| } |
| return true; |
| } |
| |
| /*! \internal |
| |
| */ |
| |
| void Q3TimeEdit::addNumber(int sec, int num) |
| { |
| if (sec == -1) |
| return; |
| sec = d->ed->mapSection(sec); |
| if (d->timerId) |
| killTimer(d->timerId); |
| d->timerId = 0; |
| bool overwrite = false; |
| bool accepted = false; |
| d->typing = true; |
| QString txt; |
| |
| switch(sec) { |
| case 0: |
| txt = (d->display & AMPM && d->h > 12) ? |
| QString::number(d->h - 12) : QString::number(d->h); |
| |
| if (d->overwrite || txt.length() == 2) { |
| if (d->display & AMPM && num == 0) |
| break; // Don't process 0 in 12 hour clock mode |
| if (d->display & AMPM && d->h > 11) |
| num += 12; |
| if (!outOfRange(num, d->m, d->s)) { |
| accepted = true; |
| d->h = num; |
| } |
| } else { |
| txt += QString::number(num); |
| int temp = txt.toInt(); |
| |
| if (d->display & AMPM) { |
| if (temp == 12) { |
| if (d->h < 12) { |
| temp = 0; |
| } |
| accepted = true; |
| } else if (outOfRange(temp + 12, d->m, d->s)) { |
| txt = QString::number(d->h); |
| } else { |
| if (d->h > 11) { |
| temp += 12; |
| } |
| accepted = true; |
| } |
| } else if (!(d->display & AMPM) && outOfRange(temp, d->m, d->s)) { |
| txt = QString::number(d->h); |
| } else { |
| accepted = true; |
| } |
| |
| if (accepted) |
| d->h = temp; |
| |
| if (d->adv && txt.length() == 2) { |
| setFocusSection(d->ed->focusSection()+1); |
| overwrite = true; |
| } |
| } |
| break; |
| |
| case 1: |
| txt = QString::number(d->m); |
| if (d->overwrite || txt.length() == 2) { |
| if (!outOfRange(d->h, num, d->s)) { |
| accepted = true; |
| d->m = num; |
| } |
| } else { |
| txt += QString::number(num); |
| int temp = txt.toInt(); |
| if (temp > 59) |
| temp = num; |
| if (outOfRange(d->h, temp, d->s)) |
| txt = QString::number(d->m); |
| else { |
| accepted = true; |
| d->m = temp; |
| } |
| if (d->adv && txt.length() == 2) { |
| setFocusSection(d->ed->focusSection()+1); |
| overwrite = true; |
| } |
| } |
| break; |
| |
| case 2: |
| txt = QString::number(d->s); |
| if (d->overwrite || txt.length() == 2) { |
| if (!outOfRange(d->h, d->m, num)) { |
| accepted = true; |
| d->s = num; |
| } |
| } else { |
| txt += QString::number(num); |
| int temp = txt.toInt(); |
| if (temp > 59) |
| temp = num; |
| if (outOfRange(d->h, d->m, temp)) |
| txt = QString::number(d->s); |
| else { |
| accepted = true; |
| d->s = temp; |
| } |
| if (d->adv && txt.length() == 2) { |
| setFocusSection(d->ed->focusSection()+1); |
| overwrite = true; |
| } |
| } |
| break; |
| |
| case 3: |
| break; |
| |
| default: |
| break; |
| } |
| d->changed = !accepted; |
| if (accepted) |
| emit valueChanged(time()); |
| d->overwrite = overwrite; |
| d->timerId = startTimer(qApp->doubleClickInterval()*4); |
| d->ed->repaint(d->ed->rect()); |
| } |
| |
| |
| /*! |
| \internal |
| |
| Function which is called whenever the user tries to |
| remove the first number from \a sec by pressing the backspace key. |
| */ |
| |
| void Q3TimeEdit::removeFirstNumber(int sec) |
| { |
| if (sec == -1) |
| return; |
| sec = d->ed->mapSection(sec); |
| QString txt; |
| switch(sec) { |
| case 0: |
| txt = QString::number(d->h); |
| break; |
| case 1: |
| txt = QString::number(d->m); |
| break; |
| case 2: |
| txt = QString::number(d->s); |
| break; |
| } |
| txt = txt.mid(1, txt.length()) + QLatin1Char('0'); |
| switch(sec) { |
| case 0: |
| d->h = txt.toInt(); |
| break; |
| case 1: |
| d->m = txt.toInt(); |
| break; |
| case 2: |
| d->s = txt.toInt(); |
| break; |
| } |
| d->ed->repaint(d->ed->rect()); |
| } |
| |
| /*! \internal |
| |
| */ |
| void Q3TimeEdit::removeLastNumber(int sec) |
| { |
| if (sec == -1) |
| return; |
| sec = d->ed->mapSection(sec); |
| QString txt; |
| switch(sec) { |
| case 0: |
| txt = QString::number(d->h); |
| break; |
| case 1: |
| txt = QString::number(d->m); |
| break; |
| case 2: |
| txt = QString::number(d->s); |
| break; |
| } |
| txt = txt.mid(0, txt.length()-1); |
| switch(sec) { |
| case 0: |
| d->h = txt.toInt(); |
| break; |
| case 1: |
| d->m = txt.toInt(); |
| break; |
| case 2: |
| d->s = txt.toInt(); |
| break; |
| } |
| d->ed->repaint(d->ed->rect()); |
| } |
| |
| /*! \reimp |
| */ |
| void Q3TimeEdit::resizeEvent(QResizeEvent *) |
| { |
| d->controls->resize(width(), height()); |
| } |
| |
| /*! \reimp |
| */ |
| QSize Q3TimeEdit::sizeHint() const |
| { |
| ensurePolished(); |
| QFontMetrics fm(font()); |
| int fw = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, this); |
| int h = fm.lineSpacing() + 2; |
| int w = 2 + fm.width(QLatin1Char('9')) * 6 + fm.width(d->ed->separator()) * 2 + |
| d->controls->upRect().width() + fw * 4; |
| if (d->display & AMPM) { |
| if (lAM) |
| w += fm.width(*lAM) + 4; |
| else |
| w += fm.width(QString::fromLatin1("AM")) + 4; |
| } |
| |
| return QSize(w, qMax(h + fw * 2,20)).expandedTo(QApplication::globalStrut()); |
| } |
| |
| /*! \reimp |
| */ |
| QSize Q3TimeEdit::minimumSizeHint() const |
| { |
| return sizeHint(); |
| } |
| |
| /*! |
| \internal |
| Enables/disables the push buttons according to the min/max time |
| for this widget. |
| */ |
| |
| void Q3TimeEdit::updateButtons() |
| { |
| if (!isEnabled()) |
| return; |
| |
| bool upEnabled = time() < maxValue(); |
| bool downEnabled = time() > minValue(); |
| |
| d->controls->setUpEnabled(upEnabled); |
| d->controls->setDownEnabled(downEnabled); |
| } |
| |
| |
| class Q3DateTimeEditPrivate |
| { |
| public: |
| bool adv; |
| }; |
| |
| /*! |
| \class Q3DateTimeEdit |
| \brief The Q3DateTimeEdit class combines a Q3DateEdit and Q3TimeEdit |
| widget into a single widget for editing datetimes. |
| |
| \compat |
| |
| Q3DateTimeEdit consists of a Q3DateEdit and Q3TimeEdit widget placed |
| side by side and offers the functionality of both. The user can |
| edit the date and time by using the keyboard or the arrow keys to |
| increase/decrease date or time values. The Tab key can be used to |
| move from section to section within the Q3DateTimeEdit widget, and |
| the user can be moved automatically when they complete a section |
| using setAutoAdvance(). The datetime can be set with |
| setDateTime(). |
| |
| The date format is read from the system's locale settings. It is |
| set to year, month, day order if that is not possible. See |
| Q3DateEdit::setOrder() to change this. Times appear in the order |
| hours, minutes, seconds using the 24 hour clock. |
| |
| It is recommended that the Q3DateTimeEdit is initialised with a |
| datetime, e.g. |
| \snippet doc/src/snippets/code/src_qt3support_widgets_q3datetimeedit.cpp 2 |
| Here we've created a new Q3DateTimeEdit set to the current date and |
| time, and set the date to have a minimum date of now and a maximum |
| date of a week from now. |
| |
| Terminology: A Q3DateEdit widget consists of three 'sections', one |
| each for the year, month and day. Similarly a Q3TimeEdit consists |
| of three sections, one each for the hour, minute and second. The |
| character that separates each date section is specified with |
| setDateSeparator(); similarly setTimeSeparator() is used for the |
| time sections. |
| |
| \img datetimewidgets.png Date Time Widgets |
| |
| \sa Q3DateEdit Q3TimeEdit |
| */ |
| |
| /*! |
| Constructs an empty datetime edit with parent \a parent and called |
| \a name. |
| */ |
| Q3DateTimeEdit::Q3DateTimeEdit(QWidget * parent, const char * name) |
| : QWidget(parent, name) |
| { |
| init(); |
| } |
| |
| |
| /*! |
| \overload |
| |
| Constructs a datetime edit with the initial value \a datetime, |
| parent \a parent and called \a name. |
| */ |
| Q3DateTimeEdit::Q3DateTimeEdit(const QDateTime& datetime, |
| QWidget * parent, const char * name) |
| : QWidget(parent, name) |
| { |
| init(); |
| setDateTime(datetime); |
| } |
| |
| |
| |
| /*! |
| Destroys the object and frees any allocated resources. |
| */ |
| |
| Q3DateTimeEdit::~Q3DateTimeEdit() |
| { |
| delete d; |
| } |
| |
| |
| /*! \fn void Q3DateTimeEdit::resizeEvent(QResizeEvent *event) |
| \reimp |
| |
| Intercepts and handles the resize \a event, which hase a |
| special meaning for the Q3DateTimeEdit. |
| */ |
| void Q3DateTimeEdit::resizeEvent(QResizeEvent *) |
| { |
| int dw = de->sizeHint().width(); |
| int tw = te->sizeHint().width(); |
| int w = width(); |
| int h = height(); |
| int extra = w - (dw + tw); |
| |
| if (tw + extra < 0) { |
| dw = w; |
| } else { |
| dw += 9 * extra / 16; |
| } |
| tw = w - dw; |
| |
| de->setGeometry(0, 0, dw, h); |
| te->setGeometry(dw, 0, tw, h); |
| } |
| |
| /*! \reimp |
| */ |
| |
| QSize Q3DateTimeEdit::minimumSizeHint() const |
| { |
| QSize dsh = de->minimumSizeHint(); |
| QSize tsh = te->minimumSizeHint(); |
| return QSize(dsh.width() + tsh.width(), |
| qMax(dsh.height(), tsh.height())); |
| } |
| |
| /*! \internal |
| */ |
| |
| void Q3DateTimeEdit::init() |
| { |
| d = new Q3DateTimeEditPrivate(); |
| de = new Q3DateEdit(this, "qt_datetime_dateedit"); |
| te = new Q3TimeEdit(this, "qt_datetime_timeedit"); |
| d->adv = false; |
| connect(de, SIGNAL(valueChanged(QDate)), this, SLOT(newValue(QDate))); |
| connect(te, SIGNAL(valueChanged(QTime)), this, SLOT(newValue(QTime))); |
| setFocusProxy(de); |
| setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); |
| } |
| |
| /*! \reimp |
| */ |
| |
| QSize Q3DateTimeEdit::sizeHint() const |
| { |
| ensurePolished(); |
| QSize dsh = de->sizeHint(); |
| QSize tsh = te->sizeHint(); |
| return QSize(dsh.width() + tsh.width(), |
| qMax(dsh.height(), tsh.height())); |
| } |
| |
| /*! |
| \property Q3DateTimeEdit::dateTime |
| \brief the editor's datetime value |
| |
| The datetime edit's datetime which may be an invalid datetime. |
| */ |
| |
| void Q3DateTimeEdit::setDateTime(const QDateTime & dt) |
| { |
| if (dt.isValid()) { |
| de->setDate(dt.date()); |
| te->setTime(dt.time()); |
| emit valueChanged(dt); |
| } |
| } |
| |
| QDateTime Q3DateTimeEdit::dateTime() const |
| { |
| return QDateTime(de->date(), te->time()); |
| } |
| |
| /*! |
| \fn void Q3DateTimeEdit::valueChanged(const QDateTime& datetime) |
| |
| This signal is emitted every time the date or time changes. The \a |
| datetime argument is the new datetime. |
| */ |
| |
| |
| /*! \internal |
| |
| Re-emits the value \a d. |
| */ |
| |
| void Q3DateTimeEdit::newValue(const QDate&) |
| { |
| QDateTime dt = dateTime(); |
| emit valueChanged(dt); |
| } |
| |
| /*! \internal |
| \overload |
| Re-emits the value \a t. |
| */ |
| |
| void Q3DateTimeEdit::newValue(const QTime&) |
| { |
| QDateTime dt = dateTime(); |
| emit valueChanged(dt); |
| } |
| |
| |
| /*! |
| Sets the auto advance property of the editor to \a advance. If set |
| to true, the editor will automatically advance focus to the next |
| date or time section if the user has completed a section. |
| */ |
| |
| void Q3DateTimeEdit::setAutoAdvance(bool advance) |
| { |
| de->setAutoAdvance(advance); |
| te->setAutoAdvance(advance); |
| } |
| |
| /*! |
| Returns true if auto-advance is enabled, otherwise returns false. |
| |
| \sa setAutoAdvance() |
| */ |
| |
| bool Q3DateTimeEdit::autoAdvance() const |
| { |
| return de->autoAdvance(); |
| } |
| |
| /*! |
| \fn Q3DateEdit* Q3DateTimeEdit::dateEdit() |
| |
| Returns the internal widget used for editing the date part of the |
| datetime. |
| */ |
| |
| /*! |
| \fn Q3TimeEdit* Q3DateTimeEdit::timeEdit() |
| |
| Returns the internal widget used for editing the time part of the |
| datetime. |
| */ |
| |
| QT_END_NAMESPACE |
| |
| #include "q3datetimeedit.moc" |
| |
| #endif |