From 6a75e4b322c9055bc1bfefa56e190e2a9a087873 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Thu, 4 Aug 2005 06:12:58 +0000 Subject: [PATCH] libkdeedu/extdate for kde-4 now compiles. I had to disable the ExtDateTimeEdit class, because making it work is going to require a major reimplementation. Since we need this library in order to work on the rest of KStars, I don't want to let this minor widget stand in the way. libkde/kdeeduplot already compiles, but there is still a compile problem with libkdeedu/kdeeduui (specifically, the glossary widget that we use). I will see if I can get that library compiling as well, then we can finally start porting kstars itself. CCMAIL: kstars-devel@kde.org svn path=/trunk/KDE/kdeedu/libkdeedu/; revision=442868 --- extdate/extdatetimeedit.cpp | 4799 ++++++++++++++++++----------------- extdate/extdatetimeedit.h | 416 +-- extdate/extdatewidget.cpp | 8 +- extdate/test_extdate.cc | 42 +- 4 files changed, 2646 insertions(+), 2619 deletions(-) diff --git a/extdate/extdatetimeedit.cpp b/extdate/extdatetimeedit.cpp index 7c5a67c..26c1404 100644 --- a/extdate/extdatetimeedit.cpp +++ b/extdate/extdatetimeedit.cpp @@ -1,2742 +1,2945 @@ +/***** --==>> JH: Commenting entire file, for now. + ***** This class is derived from QDateTimeEdit, which makes use of + ***** QVariant(QDateTime). It is not possible to translate this to + ***** ExtDateTime easily. I will have to write a custom widget eventually. + ***** However, we need this directory to compile so that the kde4 port + ***** can proceed. So I am commenting out the class. + */ + +#if 0 + --- ENTIRE CLASS COMMENTED OUT --- + /**************************************************************************** ** +** Copyright (C) 1992-2005 Trolltech AS. All rights reserved. ** -** Implementation of date and time edit classes -** -** Created : 001103 +** This file is part of the QtGui module of the Qt Toolkit. ** -** Original qatetimeedit.cpp Copyright (C) 2000-2002 Trolltech AS. All rights reserved. -**>> ExtDate modifications (C) 2004 Jason Harris +** This file may be used under the terms of the GNU General Public +** License version 2.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 GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html ** -** This file may be distributed and/or modified under the terms of the -** GNU General Public License version 2 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** -** See http://www.trolltech.com/gpl/ for GPL licensing information. -** -**********************************************************************/ +****************************************************************************/ -//DEBUG -#include +#include +#include +#include +#include +#include +#include #include "extdatetimeedit.h" #ifndef QT_NO_DATETIMEEDIT -//#include "../kernel/qinternal_p.h" -//#include "../kernel/qrichtext_p.h" -#include -#include -#include -#include -#include -#include -#include -#include //need for QTimeEdit -//Added by qt3to4: -#include -#include -#include -#include -#include -#include -#include - -#define EXTDATETIMEEDIT_HIDDEN_CHAR '0' - -static QString *lDateSep = 0; -static QString *lTimeSep = 0; -static bool lAMPM = FALSE; -static QString *lAM = 0; -static QString *lPM = 0; -static ExtDateEdit::Order lOrder = ExtDateEdit::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) - QT_WA( { - TCHAR data[10]; - GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_SDATE, data, 10 ); - *lDateSep = QString::fromUcs2( (ushort*)data ); - GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_STIME, data, 10 ); - *lTimeSep = QString::fromUcs2( (ushort*)data ); - GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_ITIME, data, 10 ); - lAMPM = QString::fromUcs2( (ushort*)data ).toInt()==0; - GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_S1159, data, 10 ); - QString am = QString::fromUcs2( (ushort*)data ); - if ( !am.isEmpty() ) - lAM = new QString( am ); - GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_S2359, data, 10 ); - QString pm = QString::fromUcs2( (ushort*)data ); - if ( !pm.isEmpty() ) - lPM = new QString( pm ); - } , { - char data[10]; - GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_SDATE, (char*)&data, 10 ); - *lDateSep = QString::fromLocal8Bit( data ); - GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_STIME, (char*)&data, 10 ); - *lTimeSep = QString::fromLocal8Bit( data ); - GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_ITIME, (char*)&data, 10 ); - lAMPM = QString::fromLocal8Bit( data ).toInt()==0; - GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_S1159, (char*)&data, 10 ); - QString am = QString::fromLocal8Bit( data ); - if ( !am.isEmpty() ) - lAM = new QString( am ); - GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_S2359, (char*)&data, 10 ); - QString pm = QString::fromLocal8Bit( data ); - if ( !pm.isEmpty() ) - lPM = new QString( pm ); - } ); -#else - *lDateSep = "-"; - *lTimeSep = ":"; -#endif - QString d = ExtDate( 1999, 11, 22 ).toString( Qt::LocalDate ); - dpos = d.find( "22" ); - mpos = d.find( "11" ); - ypos = d.find( "99" ); - if ( dpos > -1 && mpos > -1 && ypos > -1 ) { - // test for DMY, MDY, YMD, YDM - if ( dpos < mpos && mpos < ypos ) { - lOrder = ExtDateEdit::DMY; - } else if ( mpos < dpos && dpos < ypos ) { - lOrder = ExtDateEdit::MDY; - } else if ( ypos < mpos && mpos < dpos ) { - lOrder = ExtDateEdit::YMD; - } else if ( ypos < dpos && dpos < mpos ) { - lOrder = ExtDateEdit::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.contains( sep ) == 2 ) { - *lDateSep = sep; - } -#endif - } +enum { + Neither = -1, + AM = 0, + PM = 1, + PossibleAM = 2, + PossiblePM = 3, + PossibleBoth = 4 +}; -#ifndef Q_WS_WIN - QString t = QTime( 11, 22, 33 ).toString( Qt::LocalDate ); - dpos = t.find( "11" ); - mpos = t.find( "22" ); - ypos = t.find( "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; - } - } +#ifdef Q_WS_MAC +#include +extern QString qt_mac_from_pascal_string(const Str255); //qglobal.cpp #endif -} -static ExtDateEdit::Order localOrder() { - if ( !lDateSep ) { - readLocaleSettings(); - } - return lOrder; -} - -static QString localDateSep() { - if ( !lDateSep ) { - readLocaleSettings(); - } - return *lDateSep; -} - -static QString localTimeSep() { - if ( !lTimeSep ) { - readLocaleSettings(); - } - return *lTimeSep; -} +//#define EXTDATETIMEEDIT_EDTEDEBUG +#ifdef EXTDATETIMEEDIT_EDTEDEBUG +# define EDTEDEBUG qDebug() << QString("%1:%2").arg(__FILE__).arg(__LINE__) +# define EDTEDEBUGN qDebug +#else +# define EDTEDEBUG if (false) qDebug() +# define EDTEDEBUGN if (false) qDebug +#endif +#include -class ExtDateTimeEditorPrivate +class ExtDateTimeEditPrivate : public QAbstractSpinBoxPrivate { + Q_DECLARE_PUBLIC(ExtDateTimeEdit) public: - ExtDateTimeEditorPrivate() - : frm( TRUE ), - parag( new QTextParagraph( 0, 0, 0, FALSE ) ), - focusSec(0) - { - parag->formatter()->setWrapEnabled( FALSE ); - cursor = new QTextCursor( 0 ); - cursor->setParagraph( parag ); - offset = 0; - sep = localDateSep(); - refcount++; - } - ~ExtDateTimeEditorPrivate() - { - delete parag; - delete cursor; - if ( !--refcount ) - cleanup(); - } + enum Section { + NoSection = 0x0000, + AmPmSection = 0x0001, + MSecSection = 0x0002, + SecondSection = 0x0004, + MinuteSection = 0x0008, + HourSection = 0x0010, + TimeSectionMask = (AmPmSection|MSecSection|SecondSection|MinuteSection|HourSection), + Internal = 0x8000, + AmPmLowerCaseSection = AmPmSection|Internal, + DaySection = 0x0100, + MonthSection = 0x0200, + YearSection = 0x0400, + MonthShortNameSection = MonthSection|Internal, + YearTwoDigitsSection = YearSection|Internal, + DateSectionMask = (DaySection|MonthSection|YearSection), + FirstSection = 0x1000|Internal, + LastSection = 0x2000|Internal + }; // duplicated from qdatetimeedit.h + + struct SectionNode { + Section section; + int pos; + }; + + ExtDateTimeEditPrivate(); + + void readLocaleSettings(); + + void emitSignals(EmitPolicy ep, const QVariant &old); + QString textFromValue(const QVariant &f) const; + QVariant valueFromText(const QString &f) const; + QVariant validateAndInterpret(QString &input, int &, QValidator::State &state) const; + void editorCursorPositionChanged(int lastpos, int newpos); + + QVariant valueForPosition(int pos) const; + + void clearSection(Section s); + + int sectionSize(Section s) const; + int sectionPos(Section s) const; + + SectionNode sectionNode(Section t) const; + QVariant stepBy(Section s, int steps, bool test = false) const; + QString sectionText(const QString &text, Section s) const; + int getDigit(const QVariant &dt, Section s) const; + void setDigit(QVariant &t, Section s, int newval) const; + int sectionValue(Section s, QString &txt, QValidator::State &state) const; + int absoluteMax(Section s) const; + int absoluteMin(Section s) const; + Section sectionAt(int index) const; + Section closestSection(int index, bool forward) const; + SectionNode nextPrevSection(Section current, bool forward) const; + bool parseFormat(const QString &format); + void setSelected(Section s, bool forward = false); + QValidator::State checkIntermediate(const ExtDateTime &dt, const QString &str) const; + + bool addSection(QList &list, Section ds, int pos) const; + int findMonth(const QString &str1, int index = 1) const; + int findAmPm(QString &str1, Section s) const; + int maxChange(ExtDateTimeEditPrivate::Section s) const; + int potentialValue(const QString &str, int min, int max, Section s) const; + int potentialValueHelper(const QString &str, int min, int max, int size) const; + int multiplier(Section s) const; + QString sectionName(int s) const; + QString stateName(int s) const; + QString sectionFormat(int s) const; + + QString displayFormat; + QString defaultDateFormat, defaultTimeFormat, defaultDateTimeFormat; + QString escapedFormat; + // this format is the same amount of letters as the resulting string + // e.g. if the format is hh:ap and am/pm is translated to foobar/barfoo escapedFormat + // will be "hh:ap " + QList sectionNodes; + SectionNode first, last; + QStringList separators; + ExtDateTimeEdit::Sections display; + mutable int cachedDay; + mutable Section currentSection; + Qt::LayoutDirection layoutDirection; +}; - void appendSection( const QNumberSection& sec ) - { - sections.append( sec ); +// --- ExtDateTimeEdit --- - } - void clearSections() - { - sections.clear(); - } - void setSectionSelection( int sec, int selstart, int selend ) - { - if ( sec < 0 || sec > (int)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; } +/*! + \class ExtDateTimeEdit qdatetimeedit.h + \brief The ExtDateTimeEdit class provides a widget for editing dates and times. - void setFrame( bool f ) { frm = f; } - bool frame() const { return frm; } + \ingroup basic + \mainclass - int focusSection() const { return focusSec; } - int section( const QPoint& p ) - { - cursor->place( p + QPoint( offset, 0 ), parag ); - int idx = cursor->index(); - for ( uint 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; - } + ExtDateTimeEdit allows the user to edit dates by using the keyboard or + the arrow keys to increase and decrease date and time values. The + arrow keys can be used to move from section to section within the + ExtDateTimeEdit box. Dates and times appear in accordance with the + format set; see setDisplayFormat(). - bool inSectionSelection( int idx ) - { - for ( uint i = 0; i < sections.count(); ++i ) { - if ( idx >= sections[i].selectionStart() && - idx <= sections[i].selectionEnd() ) - return TRUE; - } - return FALSE; - } + \code + ExtDateTimeEdit *dateEdit = new ExtDateTimeEdit(ExtDate::currentDate()); + dateEdit->setMinimumDate(ExtDate::currentDate().addDays(-365)); + dateEdit->setMaximumDate(ExtDate::currentDate().addDays(365)); + dateEdit->setDisplayFormat("yyyy.MM.dd"); + \endcode - void paint( const QString& txt, bool focus, QPainter& p, - const QColorGroup& cg, 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( QTextDocument::Standard ); - else { - applyFocusSelection(); - } - - /* color all EXTDATETIMEEDIT_HIDDEN_CHAR chars to background color */ - QTextFormat *fb = parag->formatCollection()->format( p.font(), - cg.base() ); - QTextFormat *nf = parag->formatCollection()->format( p.font(), - cg.text() ); - for ( uint i = 0; i < txt.length(); ++i ) { - parag->setFormat( i, 1, nf ); - if ( inSectionSelection( i ) ) - continue; - if ( txt.at(i) == EXTDATETIMEEDIT_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, cg, 0, TRUE ); - if ( frm ) - p.translate( -xoff, -yoff ); - } - - void resize( const QSize& size ) { sz = size; } - - int mapSection( int sec ) - { - return sections[sec].index(); - } + Here we've created a new ExtDateTimeEdit object initialized 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. -protected: - void applyFocusSelection() - { - if ( focusSec > -1 ) { - int selstart = sections[ focusSec ].selectionStart(); - int selend = sections[ focusSec ].selectionEnd(); - parag->setSelection( QTextDocument::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; - QTextParagraph *parag; - QTextCursor *cursor; - QSize sz; - int focusSec; - Q3ValueList< QNumberSection > sections; - QString sep; - int offset; -}; + The maximum and minimum values for a date value in the date editor + default to the maximum and minimum values for a ExtDate. You can + change this by calling setMinimumDate(), setMaximumDate(), + setMinimumTime(), and setMaximumTime(). +*/ -class ExtDateTimeSpinWidget : public Q3SpinWidget -{ -public: - ExtDateTimeSpinWidget( QWidget *parent, const char *name ) - : Q3SpinWidget( parent, name ) - { - } +/*! + \enum ExtDateTimeEdit::Section -protected: -#ifndef QT_NO_WHEELEVENT - void wheelEvent( QWheelEvent *e ) - { - ExtDateTimeEditor *editor = (ExtDateTimeEditor*)editWidget()->qt_cast( "ExtDateTimeEditor" ); - Q_ASSERT( editor ); - if ( !editor ) - return; + \value NoSection + \value AmPmSection + \value MSecSection + \value SecondSection + \value MinuteSection + \value HourSection + \value DaySection + \value MonthSection + \value YearSection + \omitvalue DateSections_Mask + \omitvalue TimeSections_Mask +*/ - int section = editor->sectionAt( e->pos() ); - editor->setFocusSection( section ); +/*! + \fn void ExtDateTimeEdit::dateTimeChanged(const ExtDateTime &datetime) - if ( section == -1 ) - return; - Q3SpinWidget::wheelEvent( e ); - } -#endif -}; + This signal is emitted whenever the date or time is changed. The + new date and time is passed in \a datetime. +*/ /*! - Constructs an empty datetime editor with parent \a parent and - called \a name. + \fn void ExtDateTimeEdit::timeChanged(const QTime &time) + + This signal is emitted whenever the time is changed. The new time + is passed in \a time. */ -ExtDateTimeEditor::ExtDateTimeEditor( ExtDateTimeEditBase * parent, - const char * name ) - : QWidget( parent, name, Qt::WNoAutoErase ) -{ - d = new ExtDateTimeEditorPrivate(); - cw = parent; - init(); -} /*! - Destroys the object and frees any allocated resources. -*/ + \fn void ExtDateTimeEdit::dateChanged(const ExtDate &date) -ExtDateTimeEditor::~ExtDateTimeEditor() -{ - delete d; -} + This signal is emitted whenever the date is changed. The new date + is passed in \a date. +*/ -/*! \internal +/*! + Constructs an empty date time editor with a \a parent. */ -void ExtDateTimeEditor::init() +ExtDateTimeEdit::ExtDateTimeEdit(QWidget *parent) + : QAbstractSpinBox(*new ExtDateTimeEditPrivate, parent) { - setBackgroundMode( PaletteBase ); - setFocusSection( -1 ); - installEventFilter( this ); - setFocusPolicy( WheelFocus ); -} - + Q_D(ExtDateTimeEdit); -/*! \reimp + d->minimum = QVariant(DATETIME_MIN); + d->maximum = QVariant(DATETIME_MAX); + d->value = QVariant(ExtDateTime(DATE_INITIAL, TIME_MIN)); + setDisplayFormat(d->defaultDateTimeFormat); + if (d->displayFormat.isEmpty()) { + d->defaultDateTimeFormat = QLatin1String("MM/dd/yy hh:mm:ss"); + setDisplayFormat(d->defaultDateTimeFormat); + } +} +/*! + Constructs an empty date time editor with a \a parent. The value + is set to \a datetime. */ -bool ExtDateTimeEditor::event( QEvent *e ) +ExtDateTimeEdit::ExtDateTimeEdit(const ExtDateTime &datetime, QWidget *parent) + : QAbstractSpinBox(*new ExtDateTimeEditPrivate, parent) { - 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::AccelOverride ) { - QKeyEvent* ke = (QKeyEvent*) e; - switch ( ke->key() ) { - case Key_Delete: - case Key_Backspace: - case Key_Up: - case Key_Down: - case Key_Left: - case Key_Right: - ke->accept(); - default: - break; - } + Q_D(ExtDateTimeEdit); + d->minimum = QVariant(DATETIME_MIN); + d->maximum = QVariant(DATETIME_MAX); + d->value = datetime.isValid() ? QVariant(datetime) : QVariant(ExtDateTime(DATE_INITIAL, TIME_MIN)); + setDisplayFormat(d->defaultDateTimeFormat); + if (d->displayFormat.isEmpty()) { + d->defaultDateTimeFormat = QLatin1String("MM/dd/yy hh:mm:ss"); + setDisplayFormat(d->defaultDateTimeFormat); } - return QWidget::event( e ); } -/*! \reimp +/*! + \fn ExtDateTimeEdit::ExtDateTimeEdit(const ExtDate &date, QWidget *parent) + Constructs an empty date time editor with a \a parent. + The value is set to \a date. */ -void ExtDateTimeEditor::resizeEvent( QResizeEvent *e ) +ExtDateTimeEdit::ExtDateTimeEdit(const ExtDate &date, QWidget *parent) + : QAbstractSpinBox(*new ExtDateTimeEditPrivate, parent) { - d->resize( e->size() ); - QWidget::resizeEvent( e ); + Q_D(ExtDateTimeEdit); + d->minimum = QVariant(DATETIME_MIN); + d->maximum = QVariant(DATETIME_MAX); + d->value = QVariant(ExtDateTime(date.isValid() ? date : DATE_INITIAL, TIME_MIN)); + setDisplayFormat(d->defaultDateFormat); + if (d->displayFormat.isEmpty()) { + d->defaultDateFormat = QLatin1String("MM/dd/yy"); + setDisplayFormat(d->defaultDateFormat); + } } +/*! + \fn ExtDateTimeEdit::ExtDateTimeEdit(const QTime &time, QWidget *parent) -/*! \reimp - + Constructs an empty date time editor with a \a parent. + The value is set to \a time. */ -void ExtDateTimeEditor::paintEvent( QPaintEvent * ) +ExtDateTimeEdit::ExtDateTimeEdit(const QTime &time, QWidget *parent) + : QAbstractSpinBox(*new ExtDateTimeEditPrivate, parent) { - 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 += " "; - } + Q_D(ExtDateTimeEdit); + d->minimum = QVariant(DATETIME_MIN); + d->maximum = QVariant(DATETIME_MAX); + d->value = QVariant(ExtDateTime(DATE_INITIAL, time.isValid() ? time : TIME_MIN)); + setDisplayFormat(d->defaultTimeFormat); + if (d->displayFormat.isEmpty()) { + d->defaultDateFormat = QLatin1String("hh:mm:ss"); + setDisplayFormat(d->defaultTimeFormat); } +} - QSharedDoubleBuffer buffer( this ); - const QBrush &bg = - colorGroup().brush( isEnabled() ? QColorGroup::Base : QColorGroup::Background ); - buffer.painter()->fillRect( 0, 0, width(), height(), bg ); - d->paint( txt, hasFocus(), *buffer.painter(), colorGroup(), rect(), - style() ); - buffer.end(); +ExtDateTime ExtDateTimeEdit::dateTime() const +{ + Q_D(const ExtDateTimeEdit); + return d->value.toDateTime(); } +void ExtDateTimeEdit::setDateTime(const ExtDateTime &datetime) +{ + Q_D(ExtDateTimeEdit); + if (datetime.isValid()) { + d->cachedDay = -1; + d->setValue(QVariant(datetime), EmitIfChanged); + } +} /*! - Returns the section index at point \a p. + \property ExtDateTimeEdit::date + \brief the ExtDate that is set in the ExtDateTimeEdit + + \sa time */ -int ExtDateTimeEditor::sectionAt( const QPoint &p ) + +ExtDate ExtDateTimeEdit::date() const { - return d->section( p ); + Q_D(const ExtDateTimeEdit); + return d->value.toDate(); } -int ExtDateTimeEditor::mapSection( int sec ) +void ExtDateTimeEdit::setDate(const ExtDate &date) { - return d->mapSection( sec ); + Q_D(ExtDateTimeEdit); + if (date.isValid()) { + d->cachedDay = -1; + d->setValue(QVariant(ExtDateTime(date, d->value.toTime())), EmitIfChanged); + } } +/*! + \property ExtDateTimeEdit::time + \brief the QTime that is set in the ExtDateTimeEdit -/*! \reimp - + \sa date */ -void ExtDateTimeEditor::mousePressEvent( QMouseEvent *e ) +QTime ExtDateTimeEdit::time() const { - QPoint p( e->pos().x(), 0 ); - int sec = sectionAt( p ); - if ( sec != -1 ) { - cw->setFocusSection( sec ); - repaint( rect(), FALSE ); - } + Q_D(const ExtDateTimeEdit); + return d->value.toTime(); } -/*! \reimp - -*/ -bool ExtDateTimeEditor::eventFilter( QObject *o, QEvent *e ) +void ExtDateTimeEdit::setTime(const QTime &time) { - if ( o == this ) { - if ( e->type() == QEvent::KeyPress ) { - QKeyEvent *ke = (QKeyEvent*)e; - switch ( ke->key() ) { - case Key_Right: - if ( d->focusSection() < (int)d->sectionCount()-1 ) { - if ( cw->setFocusSection( focusSection()+1 ) ) - repaint( rect(), FALSE ); - } - return TRUE; - case Key_Left: - if ( d->focusSection() > 0 ) { - if ( cw->setFocusSection( focusSection()-1 ) ) - repaint( rect(), FALSE ); - } - return TRUE; - case Key_Up: - cw->stepUp(); - return TRUE; - case Key_Down: - cw->stepDown(); - return TRUE; - case Key_Backspace: - if ( ::qt_cast(cw) ) - ((ExtDateEdit*)cw)->removeFirstNumber( d->focusSection() ); - else if ( ::qt_cast(cw) ) - ((Q3TimeEdit*)cw)->removeFirstNumber( d->focusSection() ); - return TRUE; - case Key_Delete: - cw->removeLastNumber( d->focusSection() ); - return TRUE; - case Key_Tab: - case Key_BackTab: { - if ( ke->state() == Qt::ControlButton ) - return FALSE; + Q_D(ExtDateTimeEdit); + if (time.isValid()) { + d->cachedDay = -1; + d->setValue(QVariant(ExtDateTime(d->value.toDate(), time)), EmitIfChanged); + } +} - QWidget *w = this; - bool hadDateEdit = FALSE; - while ( w ) { - if ( ::qt_cast(w) && qstrcmp( w->name(), "qt_spin_widget" ) != 0 || - ::qt_cast(w) ) - break; - hadDateEdit = hadDateEdit || ::qt_cast(w); - w = w->parentWidget(); - } +/*! + \property ExtDateTimeEdit::dateTime + \brief the ExtDateTime that is set in the ExtDateTimeEdit - if ( w ) { - if ( !::qt_cast(w) ) { - w = w->parentWidget(); - } else { - ExtDateTimeEdit *ed = (ExtDateTimeEdit*)w; - if ( hadDateEdit && ke->key() == Key_Tab ) { - ed->timeEdit()->setFocus(); - return TRUE; - } else if ( !hadDateEdit && ke->key() == Key_BackTab ) { - ed->dateEdit()->setFocus(); - return TRUE; - } else { - while ( w && !::qt_cast(w) ) - w = w->parentWidget(); - } - } + \sa minimumDate, minimumTime, maximumDate, maximumTime +*/ - qApp->sendEvent( w, e ); - return TRUE; - } - } break; - default: - QString txt = ke->text().lower(); - 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(), FALSE ); - } - return TRUE; - } else if ( !txt.isEmpty() && ::qt_cast(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).lower()[0] && time.hour() >= 12 ) { - time.setHMS( time.hour()-12, time.minute(), time.second(), time.msec() ); - te->setTime( time ); - } else if ( txt[0] == (*lPM).lower()[0] && time.hour() < 12 ) { - time.setHMS( time.hour()+12, time.minute(), time.second(), time.msec() ); - te->setTime( time ); - } - } - } +/*! + \property ExtDateTimeEdit::minimumDate - int num = txt[0].digitValue(); - if ( num != -1 ) { - cw->addNumber( d->focusSection(), num ); - return TRUE; - } - } - } - } - return FALSE; -} + \brief the minimum date of the date time edit + When setting this property the \l maximumDate is adjusted if + necessary, to ensure that the range remains valid. If the date is + not a valid ExtDate object, this function does nothing. -/*! - Appends the number section \a sec to the editor. + \sa minimumTime, maximumTime, setDateRange() */ -void ExtDateTimeEditor::appendSection( const QNumberSection& sec ) +ExtDate ExtDateTimeEdit::minimumDate() const { - d->appendSection( sec ); + Q_D(const ExtDateTimeEdit); + return d->minimum.toDate(); } -/*! - Removes all sections from the editor. -*/ +void ExtDateTimeEdit::setMinimumDate(const ExtDate &min) +{ + Q_D(ExtDateTimeEdit); + if (min.isValid()) { + const QVariant m(ExtDateTime(min, d->minimum.toTime())); + d->setRange(m, qMax(d->maximum, m)); + } +} -void ExtDateTimeEditor::clearSections() +void ExtDateTimeEdit::clearMinimumDate() { - d->clearSections(); + setMinimumDate(DATE_MIN); } /*! - Sets the selection of \a sec to start at \a selstart and end at \a - selend. + \property ExtDateTimeEdit::maximumDate + + \brief the maximum date of the date time edit + + When setting this property the \l minimumDate is adjusted if + necessary to ensure that the range remains valid. If the date is + not a valid ExtDate object, this function does nothing. + + \sa minimumDate, minimumTime, maximumTime, setDateRange() */ -void ExtDateTimeEditor::setSectionSelection( int sec, int selstart, int selend ) +ExtDate ExtDateTimeEdit::maximumDate() const { - d->setSectionSelection( sec, selstart, selend ); + Q_D(const ExtDateTimeEdit); + return d->maximum.toDate(); } -/*! - Sets the separator for all numbered sections to \a s. Note that - currently, only the first character of \a s is used. -*/ - -void ExtDateTimeEditor::setSeparator( const QString& s ) +void ExtDateTimeEdit::setMaximumDate(const ExtDate &max) { - d->setSeparator( s ); - update(); + Q_D(ExtDateTimeEdit); + if (max.isValid()) { + const QVariant m(ExtDateTime(max, d->maximum.toTime())); + d->setRange(qMin(d->minimum, m), m); + } } +void ExtDateTimeEdit::clearMaximumDate() +{ + setMaximumDate(DATE_MAX); +} /*! - Returns the editor's separator. + \property ExtDateTimeEdit::minimumTime + + \brief the minimum time of the date time edit + + When setting this property the \l maximumTime is adjusted if + necessary, to ensure that the range remains valid. If the time is + not a valid QTime object, this function does nothing. + + \sa maximumTime, minimumDate, maximumDate, setTimeRange() */ -QString ExtDateTimeEditor::separator() const +QTime ExtDateTimeEdit::minimumTime() const { - return d->separator(); + Q_D(const ExtDateTimeEdit); + return d->minimum.toTime(); } -/*! - Returns the number of the section that has focus. -*/ - -int ExtDateTimeEditor::focusSection() const +void ExtDateTimeEdit::setMinimumTime(const QTime &min) { - return d->focusSection(); + Q_D(ExtDateTimeEdit); + if (min.isValid()) { + const QVariant m(ExtDateTime(d->minimum.toDate(), min)); + d->setRange(m, qMax(d->maximum, m)); + } } +void ExtDateTimeEdit::clearMinimumTime() +{ + setMinimumTime(TIME_MIN); +} /*! - Sets the focus to section \a sec. If \a sec does not exist, - nothing happens. + \property ExtDateTimeEdit::maximumTime + + \brief the maximum time of the date time edit + + When setting this property, the \l minimumTime is adjusted if + necessary to ensure that the range remains valid. If the time is + not a valid QTime object, this function does nothing. + + \sa minimumTime, minimumDate, maximumDate, setTimeRange() */ +QTime ExtDateTimeEdit::maximumTime() const +{ + Q_D(const ExtDateTimeEdit); + return d->maximum.toTime(); +} -bool ExtDateTimeEditor::setFocusSection( int sec ) +void ExtDateTimeEdit::setMaximumTime(const QTime &max) { - return d->setFocusSection( sec ); + Q_D(ExtDateTimeEdit); + if (max.isValid()) { + const QVariant m(ExtDateTime(d->maximum.toDate(), max)); + d->setRange(qMin(d->minimum, m), m); + } } -/*! \class ExtDateTimeEditBase ExtDatetimeedit.h - \brief The ExtDateTimeEditBase class provides an abstraction for date and edit editors. - \internal +void ExtDateTimeEdit::clearMaximumTime() +{ + setMaximumTime(TIME_MAX); +} - Small abstract class that provides some functions that are common - for both ExtDateEdit and QTimeEdit. Its used internally by - ExtDateTimeEditor. -*/ +/*! + Convenience function to set minimum and maximum date with one + function call. -/*! \fn QString ExtDateTimeEditBase::sectionFormattedText( int sec ) - \internal + \code + setDateRange(min, max); + \endcode - Pure virtual function which returns the formatted text of section \a - sec. + is analogous to: -*/ + \code + setMinimumDate(min); + setMaximumDate(max); + \endcode -/*! \fn void ExtDateTimeEditBase::stepUp() - \internal + If either \a min or \a max are not valid, this function does + nothing. - 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. + \sa setMinimumDate(), maximumDate(), setMaximumDate(), + clearMinimumDate(), setMinimumTime(), maximumTime(), + setMaximumTime(), clearMinimumTime(), ExtDate::isValid() */ -/*! \fn void ExtDateTimeEditBase::stepDown() - \internal +void ExtDateTimeEdit::setDateRange(const ExtDate &min, const ExtDate &max) +{ + Q_D(ExtDateTimeEdit); + if (min.isValid() && max.isValid()) { + d->setRange(QVariant(ExtDateTime(min, d->minimum.toTime())), + QVariant(ExtDateTime(max, d->maximum.toTime()))); + } +} - 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. +/*! + Convenience function to set minimum and maximum time with one + function call. -*/ + \code + setTimeRange(min, max); + \endcode -/*! \fn void ExtDateTimeEditBase::addNumber( int sec, int num ) - \internal + is analogous to: - 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. -*/ + \code + setMinimumTime(min); + setMaximumTime(max); + \endcode -/*! \fn void ExtDateTimeEditBase::removeLastNumber( int sec ) - \internal + If either \a min or \a max are not valid, this function does + nothing. - Pure virtual function which is called whenever the user tries to - remove the last number from \a sec by pressing the delete key. + \sa setMinimumDate(), maximumDate(), setMaximumDate(), + clearMinimumDate(), setMinimumTime(), maximumTime(), + setMaximumTime(), clearMinimumTime(), QTime::isValid() */ -//////////////// - -class ExtDateEditPrivate +void ExtDateTimeEdit::setTimeRange(const QTime &min, const QTime &max) { -public: - int y; - int m; - int d; - // remebers 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; - ExtDateEdit::Order ord; - bool overwrite; - bool adv; - int timerId; - bool typing; - ExtDate min; - ExtDate max; - bool changed; - ExtDateTimeEditor *ed; - Q3SpinWidget *controls; -}; - + Q_D(ExtDateTimeEdit); + if (min.isValid() && max.isValid()) { + d->setRange(QVariant(ExtDateTime(d->minimum.toDate(), min)), + QVariant(ExtDateTime(d->maximum.toDate(), max))); + } +} /*! - \class ExtDateEdit ExtDatetimeedit.h - \brief The ExtDateEdit class provides a date editor. - - \ingroup advanced - \ingroup time + \property ExtDateTimeEdit::displayedSections - ExtDateEdit 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 ExtDateEdit - 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 ExtDateEdit be initialised - with a date, e.g. + \brief the currently displayed fields of the date time edit - \code - ExtDateEdit *dateEdit = new ExtDateEdit( ExtDate::currentDate(), this ); - dateEdit->setRange( ExtDate::currentDate().addDays( -365 ), - ExtDate::currentDate().addDays( 365 ) ); - dateEdit->setOrder( ExtDateEdit::MDY ); - dateEdit->setAutoAdvance( TRUE ); - \endcode + Returns a bit set of the displayed sections for this format. + \a setDisplayFormat(), displayFormat() +*/ - Here we've created a new ExtDateEdit 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. +ExtDateTimeEdit::Sections ExtDateTimeEdit::displayedSections() const +{ + Q_D(const ExtDateTimeEdit); + return d->display; +} - The maximum and minimum values for a date value in the date editor - default to the maximum and minimum values for a ExtDate. You can - change this by calling setMinValue(), setMaxValue() or setRange(). +/*! + \property ExtDateTimeEdit::currentSection - Terminology: A ExtDateEdit widget comprises three 'sections', one - each for the year, month and day. You can change the separator - character using ExtDateTimeEditor::setSeparator(), by default the - separator will be taken from the systems settings. If that is - not possible, it defaults to "-". + \brief the current section of the spinbox + \a setCurrentSection() +*/ - \image html datetimewidgets.png "Date Time Widgets" +ExtDateTimeEdit::Section ExtDateTimeEdit::currentSection() const +{ + Q_D(const ExtDateTimeEdit); + switch (d->currentSection) { + case ExtDateTimeEditPrivate::NoSection: + case ExtDateTimeEditPrivate::FirstSection: + case ExtDateTimeEditPrivate::LastSection: + return ExtDateTimeEdit::NoSection; + default: + return (ExtDateTimeEdit::Section)(d->currentSection & (~ExtDateTimeEditPrivate::Internal)); + } +} - \sa ExtDate QTimeEdit ExtDateTimeEdit -*/ +void ExtDateTimeEdit::setCurrentSection(Section section) +{ + Q_D(ExtDateTimeEdit); + const ExtDateTimeEditPrivate::Section s = (ExtDateTimeEditPrivate::Section)section; + if (s != ExtDateTimeEditPrivate::NoSection) + d->edit->setCursorPosition(d->sectionNode(s).pos); +} /*! - \enum ExtDateEdit::Order + \fn QString ExtDateTimeEdit::sectionText(Section section) const - This enum defines the order in which the sections that comprise a - date appear. + Returns the text from the given \a section. + \sa currentSection() */ +QString ExtDateTimeEdit::sectionText(Section s) const +{ + Q_D(const ExtDateTimeEdit); + return d->sectionText(d->edit->displayText(), (ExtDateTimeEditPrivate::Section)s); +} /*! - \enum QTimeEdit::Display + \property ExtDateTimeEdit::displayFormat + + \brief the format used to display the time/date of the date time edit + + This format is a subset of the format described in ExtDateTime::toString() + + These expressions may be used: + + \table + \header \i Expression \i Output + \row \i hh + \i the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display) + \row \i mm \i the minute with a leading zero (00 to 59) + \row \i ss \i the second whith a leading zero (00 to 59) + \row \i zzz \i the milliseconds with leading zeroes (000 to 999) + \row \i AP + \i use AM/PM display. \e AP will be replaced by either "AM" or "PM". + \row \i ap + \i use am/pm display. \e ap will be replaced by either "am" or "pm". + \row \i dd \i the day as number with a leading zero (01 to 31) + \row \i MM \i the month as number with a leading zero (01 to 12) + \row \i MMM + \i the abbreviated localized month name (e.g. 'Jan' to 'Dec'). + Uses ExtDate::shortMonthName(). + \row \i yy \i the year as two digit number (00 to 99) + \row \i yyyy \i the year as four digit number (1752 to 8000) + \endtable + + All other input characters or sequence of characters that are + enclosed in singlequotes will be treated as text and can be used + as delimiters. + + Example format strings (assuming that the date is 20 July 1969): + + \table + \header \i Format \i Result + \row \i dd.MM.yyyy \i 20.07.1969 + \row \i MMM d yy \i Jul 20 69 + \endtable + + If you specify an invalid format the format will not be set. + + Multiple instances of the same field is not allowed.A format with + no valid fields is not allowed either. + + \warning Since ExtDateTimeEdit internally always operates on a + ExtDateTime, changing the format can change the minimum time or + date and the current time or date. For example: + + \code + ExtDateTimeEdit edit; // default format is "yyyy.MM.dd hh:mm:ss" + edit.setMinimumDate(ExtDate(2000, 1, 1)); + edit.setMaximumDate(ExtDate(2003, 1, 1)); + edit.setDateTime(ExtDateTime(ExtDate(2002, 5, 5), QTime(10, 10, 10))); + edit.setDisplayFormat("hh:mm:ss"); + + // edit can no longer display dates. This means that the + // minimum and maximum date will be set to the current date, + // e.g. 2002, 5, 5. + \endcode + + \sa ExtDateTime::toString(), displayedSections() +*/ + +QString ExtDateTimeEdit::displayFormat() const +{ + Q_D(const ExtDateTimeEdit); + return d->displayFormat; +} + +void ExtDateTimeEdit::setDisplayFormat(const QString &format) +{ + Q_D(ExtDateTimeEdit); + if (d->parseFormat(format)) { + d->cachedValue.clear(); + d->cachedText.clear(); + const bool timeShown = (d->display & ExtDateTimeEditPrivate::TimeSectionMask); + const bool dateShown = (d->display & ExtDateTimeEditPrivate::DateSectionMask); + Q_ASSERT(dateShown || timeShown); + if (timeShown && !dateShown) { + setDateRange(d->value.toDate(), d->value.toDate()); + } else if (dateShown && !timeShown) { + setTimeRange(TIME_MIN, TIME_MAX); + d->value = QVariant(ExtDateTime(d->value.toDate(), QTime())); + } + d->update(); + d->edit->setCursorPosition(0); + d->editorCursorPositionChanged(-1, 0); + } +} - This enum defines the sections that comprise a time +/*! + \reimp +*/ - \value Hours The hours section - \value Minutes The minutes section - \value Seconds The seconds section - \value AMPM The AM/PM section +QSize ExtDateTimeEdit::sizeHint() const +{ + Q_D(const QAbstractSpinBox); + ensurePolished(); + + const QFontMetrics fm(fontMetrics()); + int h = d->edit->sizeHint().height(); + int w = 0; + QString s; + s = d->textFromValue(d->minimum) + QLatin1String(" "); + w = qMax(w, fm.width(s)); + s = d->textFromValue(d->maximum) + QLatin1String(" "); + w = qMax(w, fm.width(s)); + if (d->specialValueText.size()) { + s = d->specialValueText; + w = qMax(w, fm.width(s)); + } + w += 2; // cursor blinking space - The values can be or'ed together to show any combination. -*/ + QStyleOptionSpinBox opt = d->getStyleOption(); + QSize hint(w, h); + QSize extra(35, 6); + opt.rect.setSize(hint + extra); + extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt, + QStyle::SC_SpinBoxEditField, this).size(); + // get closer to final result by repeating the calculation + opt.rect.setSize(hint + extra); + extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt, + QStyle::SC_SpinBoxEditField, this).size(); + hint += extra; + + opt.rect = rect(); + return style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this) + .expandedTo(QApplication::globalStrut()); +} /*! - Constructs an empty date editor which is a child of \a parent and - called name \a name. + \reimp */ -ExtDateEdit::ExtDateEdit( QWidget * parent, const char * name ) - : ExtDateTimeEditBase( parent, name ) +bool ExtDateTimeEdit::event(QEvent *e) { - init(); - updateButtons(); + Q_D(ExtDateTimeEdit); + switch (e->type()) { + case QEvent::ApplicationLayoutDirectionChange: + setDisplayFormat(d->displayFormat); + break; + default: + break; + } + return QAbstractSpinBox::event(e); } /*! - \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. + \reimp */ -ExtDateEdit::ExtDateEdit( const ExtDate& date, QWidget * parent, const char * name ) - : ExtDateTimeEditBase( parent, name ) +void ExtDateTimeEdit::clear() { - init(); - setDate( date ); + Q_D(ExtDateTimeEdit); + d->clearSection(d->currentSection); } +/*! + \reimp +*/ + +void ExtDateTimeEdit::keyPressEvent(QKeyEvent *e) +{ + Q_D(ExtDateTimeEdit); + const ExtDateTimeEditPrivate::Section oldCurrent = d->currentSection; + bool select = true; + + if ((e->key() == Qt::Key_Backspace || (e->key() == Qt::Key_H && e->key() & Qt::ControlModifier)) + && !d->edit->hasSelectedText()) { + const int pos = d->edit->cursorPosition(); + if (pos <= d->separators.first().size()) { + e->accept(); + return; + } + select = false; + const ExtDateTimeEditPrivate::Section s = d->sectionAt(pos); + const ExtDateTimeEditPrivate::Section closest = d->closestSection(pos - 1, false); + EDTEDEBUG << "found those two" << d->sectionName(s)<< d->sectionName(closest); + if ((s == ExtDateTimeEditPrivate::LastSection && d->separators.last().size() > 0) + || (s != ExtDateTimeEditPrivate::NoSection && pos == d->sectionPos(s))) { + QString copy = d->edit->displayText(); + int cursorCopy = pos; + if (validate(copy, cursorCopy) != QValidator::Acceptable) { + d->interpret(EmitIfChanged); + } + d->ignoreCursorPositionChanged = true; + d->edit->setCursorPosition(d->sectionPos(closest) + d->sectionSize(closest)); + d->currentSection = closest; + d->ignoreCursorPositionChanged = false; + } + } -/*! \internal -*/ -void ExtDateEdit::init() -{ - d = new ExtDateEditPrivate(); - d->controls = new ExtDateTimeSpinWidget( this, - qstrcmp( name(), "qt_datetime_dateedit" ) == 0 ? - "qt_spin_widget" : "date edit controls" ); - d->ed = new ExtDateTimeEditor( this, "date editor" ); - 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(const ExtDate&) ), - SLOT( updateButtons() ) ); - d->ed->appendSection( QNumberSection( 0,4 ) ); - d->ed->appendSection( QNumberSection( 5,7 ) ); - d->ed->appendSection( QNumberSection( 8,10 ) ); + bool forward = true; + switch ((Qt::Key)e->key()) { + case Qt::Key_Enter: + case Qt::Key_Return: + d->interpret(AlwaysEmit); + d->setSelected(d->currentSection); + e->ignore(); + emit editingFinished(); + return; + + case Qt::Key_Left: + forward = false; + case Qt::Key_Right: + if (!(e->modifiers() & Qt::ControlModifier)) { + select = false; + break; + } +#ifdef Q_WS_MAC + else { + select = (e->modifiers() & Qt::ShiftModifier); + break; + } +#endif - d->yearSection = -1; - d->monthSection = -1; - d->daySection = -1; + // fallthroughs intended + case Qt::Key_Backtab: + case Qt::Key_Tab: { + e->accept(); + if (d->specialValue()) { + d->edit->setSelection(d->edit->cursorPosition(), 0); + return; + } + if (e->key() == Qt::Key_Backtab || (e->key() == Qt::Key_Tab && e->modifiers() & Qt::ShiftModifier)) { + forward = false; + } + + const ExtDateTimeEditPrivate::SectionNode newSection = d->nextPrevSection(d->currentSection, forward); + if (select) { + d->setSelected(newSection.section); + } else { + d->edit->setCursorPosition(forward ? newSection.pos : d->sectionPos(d->currentSection)); + } + if (!select) + d->edit->deselect(); + return; } + default: + select = !e->text().isEmpty() && e->text().at(0).isPrint(); + break; + } - 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 = ExtDate( -50000, 1, 1 ); - d->max = ExtDate( 50000, 12, 31 ); - d->changed = FALSE; + QAbstractSpinBox::keyPressEvent(e); + if (select && d->currentSection != oldCurrent && !(e->modifiers() & Qt::ShiftModifier) && !d->edit->hasSelectedText()) { + d->setSelected(d->currentSection); + } + if (d->specialValue()) { + d->edit->setSelection(d->edit->cursorPosition(), 0); + } +} - setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ); +/*! + \reimp +*/ - refcount++; +#ifndef QT_NO_WHEELEVENT +void ExtDateTimeEdit::wheelEvent(QWheelEvent *e) +{ + Q_D(ExtDateTimeEdit); + int fw = d->frame ? style()->pixelMetric(QStyle::PM_SpinBoxFrameWidth) : 0; + QPoint pnt(e->pos() - QPoint(fw, fw)); + pnt.rx() -= d->edit->x(); + int index = d->edit->cursorPositionAt(pnt); + const ExtDateTimeEditPrivate::Section s = d->closestSection(index, d->edit->cursorPosition() > index); // should it be > pos? + if (s != d->currentSection) + d->edit->setCursorPosition(d->sectionNode(s).pos); + switch (s) { + case ExtDateTimeEditPrivate::NoSection: + case ExtDateTimeEditPrivate::FirstSection: + case ExtDateTimeEditPrivate::LastSection: + break; + default: + QAbstractSpinBox::wheelEvent(e); + break; + } } +#endif /*! - Destroys the object and frees any allocated resources. + \reimp */ -ExtDateEdit::~ExtDateEdit() +void ExtDateTimeEdit::focusInEvent(QFocusEvent *e) { - delete d; - if ( !--refcount ) - cleanup(); + Q_D(ExtDateTimeEdit); + QAbstractSpinBox::focusInEvent(e); + QString *frm = 0; + if (d->displayFormat == d->defaultTimeFormat) { + frm = &d->defaultTimeFormat; + } else if (d->displayFormat == d->defaultDateFormat) { + frm = &d->defaultDateFormat; + } else if (d->displayFormat == d->defaultDateTimeFormat) { + frm = &d->defaultDateTimeFormat; + } + + if (frm) { + d->readLocaleSettings(); + setDisplayFormat(*frm); + } + bool first; + switch (e->reason()) { + case Qt::ShortcutFocusReason: + case Qt::TabFocusReason: first = true; break; + case Qt::BacktabFocusReason: first = false; break; + default: return; + } + if (QApplication::isRightToLeft()) + first = !first; + d->setSelected(first ? d->sectionNodes.first().section : d->sectionNodes.at(d->sectionNodes.size() - 1).section); } /*! - \property ExtDateEdit::minValue + \reimp +*/ - \brief the editor's minimum value +bool ExtDateTimeEdit::focusNextPrevChild(bool next) +{ + Q_D(ExtDateTimeEdit); + if (!focusWidget()) + return false; - Setting the minimum date value is equivalent to calling - ExtDateEdit::setRange( \e d, maxValue() ), where \e d is the minimum - date. The default minimum date is 1752-09-14. + const ExtDateTimeEditPrivate::Section newSection = + d->nextPrevSection(d->currentSection, next).section; + switch (newSection) { + case ExtDateTimeEditPrivate::NoSection: + case ExtDateTimeEditPrivate::FirstSection: + case ExtDateTimeEditPrivate::LastSection: + break; + default: + d->setSelected(newSection); + return true; + } + return QAbstractSpinBox::focusNextPrevChild(next); +} - \sa maxValue setRange() +/*! + \reimp */ -ExtDate ExtDateEdit::minValue() const +void ExtDateTimeEdit::stepBy(int steps) { - return d->min; + Q_D(ExtDateTimeEdit); + const ExtDateTimeEditPrivate::Section s = d->currentSection; + d->setValue(d->stepBy(s, steps, false), EmitIfChanged); + d->setSelected(s); } /*! - \property ExtDateEdit::maxValue + This virtual function is used by the date time edit whenever it + needs to display \a dateTime. - \brief the editor's maximum value + If you reimplement this, you may also need to reimplement + valueFromText() and validate(). - Setting the maximum date value for the editor is equivalent to - calling ExtDateEdit::setRange( minValue(), \e d ), where \e d is the - maximum date. The default maximum date is 8000-12-31. - - \sa minValue setRange() + \sa dateTimeFromText(), validate() */ - -ExtDate ExtDateEdit::maxValue() const +QString ExtDateTimeEdit::textFromDateTime(const ExtDateTime &dateTime) const { - return d->max; + const char zero = '0'; + + Q_D(const ExtDateTimeEdit); + QVariant var(dateTime); + if (var == d->cachedValue) { + EDTEDEBUG << "cached and var is the same so returning cachedText" << dateTime << d->cachedText; + return d->cachedText; + } + QString ret = d->escapedFormat; + for (int i=0; isectionNodes.size(); ++i) { + int l = d->sectionSize(d->sectionNodes.at(i).section); + int pos = d->sectionNodes.at(i).pos; + const ExtDateTimeEditPrivate::Section s = d->sectionNodes.at(i).section; + switch (s) { + case ExtDateTimeEditPrivate::AmPmSection: + case ExtDateTimeEditPrivate::AmPmLowerCaseSection: { + QString input; + if (s == ExtDateTimeEditPrivate::AmPmSection) { + input = var.toTime().hour() > 11 + ? ExtDateTimeEdit::tr("PM") + : ExtDateTimeEdit::tr("AM"); + } else { + input = var.toTime().hour() > 11 ? + ExtDateTimeEdit::tr("pm") : + ExtDateTimeEdit::tr("am"); + } + input.truncate(l); + + ret.replace(pos, l, input); + break; } + case ExtDateTimeEditPrivate::MonthShortNameSection: + ret.replace(pos, l, ExtDate::shortMonthName(var.toDate().month())); + break; + case ExtDateTimeEditPrivate::YearTwoDigitsSection: + ret.replace(pos, l, + QString::number(d->getDigit(var, ExtDateTimeEditPrivate::YearTwoDigitsSection) - 2000) + .rightJustified(l, zero, true)); + break; + case ExtDateTimeEditPrivate::HourSection: + if (d->display & ExtDateTimeEditPrivate::AmPmSection) { + int h = var.toTime().hour(); + h = h % 12; + if (h == 0) + h = 12; + ret.replace(pos, l, + QString::number(h).rightJustified(l, zero, true)); + break; + } + default: + ret.replace(pos, l, + QString::number(d->getDigit(var, d->sectionNodes.at(i).section)). + rightJustified(l, zero)); + break; + } + } + + d->cachedValue = var; + d->cachedText = ret; +// qDebug() << "setting cached to" << d->cachedValue << " and cachedText to" << d->cachedText; + return ret; } /*! - 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. -*/ + Returns an appropriate datetime for the given \a text. + + This virtual function is used by the datetime edit whenever it + needs to interpret text entered by the user as a value. -void ExtDateEdit::setRange( const ExtDate& min, const ExtDate& max ) + \sa textFromDateTime(), validate() +*/ +ExtDateTime ExtDateTimeEdit::dateTimeFromText(const QString &text) const { - if ( min.isValid() ) - d->min = min; - if ( max.isValid() ) - d->max = max; + Q_D(const ExtDateTimeEdit); + QString copy = text; + int pos = d->edit->cursorPosition(); + QValidator::State state = QValidator::Acceptable; + return d->validateAndInterpret(copy, pos, state).toDateTime(); } /*! - Sets the separator to \a s. Note that currently only the first - character of \a s is used. + \reimp */ -void ExtDateEdit::setSeparator( const QString& s ) +QValidator::State ExtDateTimeEdit::validate(QString &text, int &pos) const { - d->ed->setSeparator( s ); -} + Q_D(const ExtDateTimeEdit); + QValidator::State state; + d->validateAndInterpret(text, pos, state); + return state; +}\ /*! - Returns the editor's separator. + \reimp */ -QString ExtDateEdit::separator() const +ExtDateTimeEdit::StepEnabled ExtDateTimeEdit::stepEnabled() const { - return d->ed->separator(); + Q_D(const ExtDateTimeEdit); + if (d->readOnly) + return StepEnabled(0); + if (d->specialValue()) { + if (d->minimum == d->maximum) + return StepEnabled(0); + return d->wrapping + ? StepEnabled(StepDownEnabled|StepUpEnabled) + : StepEnabled(StepUpEnabled); + } + switch (d->currentSection) { + case ExtDateTimeEditPrivate::NoSection: + case ExtDateTimeEditPrivate::FirstSection: + case ExtDateTimeEditPrivate::LastSection: return 0; + default: break; + } + if (!style()->styleHint(QStyle::SH_SpinControls_DisableOnBounds) + || d->wrapping) + return StepEnabled(StepUpEnabled | StepDownEnabled); + + QAbstractSpinBox::StepEnabled ret = 0; + + QVariant v = d->stepBy(d->currentSection, 1, true); + if (v != d->value) { + ret |= QAbstractSpinBox::StepUpEnabled; + } + v = d->stepBy(d->currentSection, -1, true); + if (v != d->value) { + ret |= QAbstractSpinBox::StepDownEnabled; + } + + return ret; } /*! - Enables/disables the push buttons according to the min/max date - for this widget. -*/ + \class QTimeEdit + \brief The QTimeEdit class provides a widget for editing times based on + the ExtDateTimeEdit widget. -void ExtDateEdit::updateButtons() -{ - if ( !isEnabled() ) - return; + \ingroup basic + \mainclass - fix(); - - bool upEnabled = date() < maxValue(); - bool downEnabled = date() > minValue(); + \sa ExtDateEdit ExtDateTimeEdit +*/ - d->controls->setUpEnabled( upEnabled ); - d->controls->setDownEnabled( downEnabled ); -} +/*! + Constructs an empty time editor with a \a parent. +*/ -/*! \reimp - */ -void ExtDateEdit::resizeEvent( QResizeEvent * ) + +QTimeEdit::QTimeEdit(QWidget *parent) + : ExtDateTimeEdit(TIME_MIN, parent) { - d->controls->resize( width(), height() ); } -/*! \reimp - +/*! + Constructs an empty time editor with a \a parent. The time is set + to \a time. */ -QSize ExtDateEdit::sizeHint() const -{ - constPolish(); - QFontMetrics fm( font() ); - int fw = style().pixelMetric( QStyle::PM_DefaultFrameWidth, this ); - int h = QMAX( fm.lineSpacing(), 14 ) + 2; - int w = 2 + fm.width( '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() ); +QTimeEdit::QTimeEdit(const QTime &time, QWidget *parent) + : ExtDateTimeEdit(time, parent) +{ } -/*! \reimp +/*! + \class ExtDateEdit + \brief The ExtDateEdit class provides a widget for editing dates based on + the ExtDateTimeEdit widget. + + \ingroup basic + \mainclass + + \sa QTimeEdit ExtDateTimeEdit +*/ +/*! + Constructs an empty date editor with a \a parent. */ -QSize ExtDateEdit::minimumSizeHint() const + +ExtDateEdit::ExtDateEdit(QWidget *parent) + : ExtDateTimeEdit(DATE_INITIAL, parent) { - 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() + Constructs an empty date editor with a \a parent. The date is set + to \a date. */ -QString ExtDateEdit::sectionFormattedText( int sec ) +ExtDateEdit::ExtDateEdit(const ExtDate &date, QWidget *parent) + : ExtDateTimeEdit(date, parent) { - 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.rightJustify( sectionLength( sec ), EXTDATETIMEEDIT_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. +// --- ExtDateTimeEditPrivate --- - \sa setOrder() +/*! + \internal + Constructs a ExtDateTimeEditPrivate object */ -int ExtDateEdit::sectionLength( int sec ) const + +ExtDateTimeEditPrivate::ExtDateTimeEditPrivate() { - 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; + type = QVariant::DateTime; + display = (ExtDateTimeEdit::Sections)0; + cachedDay = -1; + currentSection = NoSection; + layoutDirection = QApplication::layoutDirection(); + first.section = FirstSection; + last.section = LastSection; + first.pos = 0; + last.pos = -1; + readLocaleSettings(); } /*! - 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() + \internal + \reimp */ -QString ExtDateEdit::sectionText( int sec ) const +void ExtDateTimeEditPrivate::emitSignals(EmitPolicy ep, const QVariant &old) { - 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 ); + Q_Q(ExtDateTimeEdit); + if (ep == NeverEmit) { + return; + } + pendingEmit = false; + + const bool dodate = value.toDate().isValid() && (display & DateSectionMask); + const bool datechanged = (ep == AlwaysEmit || old.toDate() != value.toDate()); + const bool dotime = value.toTime().isValid() && (display & TimeSectionMask); + const bool timechanged = (ep == AlwaysEmit || old.toTime() != value.toTime()); + + if (dodate && dotime && (datechanged || timechanged)) + emit q->dateTimeChanged(value.toDateTime()); + if (dodate && datechanged) + emit q->dateChanged(value.toDate()); + if (dotime && timechanged) + emit q->timeChanged(value.toTime()); } -/*! \internal +/*! + \internal + \reimp +*/ + +void ExtDateTimeEditPrivate::editorCursorPositionChanged(int oldpos, int newpos) +{ + Q_Q(ExtDateTimeEdit); + if (ignoreCursorPositionChanged || specialValue()) + return; + const bool allowChange = !edit->hasSelectedText(); + ignoreCursorPositionChanged = true; + Section s = sectionAt(newpos); + int c = newpos; + + const int selstart = edit->selectionStart(); + const Section selSection = sectionAt(selstart); + const int l = sectionSize(selSection); + + if (s == NoSection) { + if (l > 0 && selstart == sectionPos(selSection) && edit->selectedText().size() == l) { + s = selSection; + if (allowChange) + setSelected(selSection, true); + c = -1; + } else { + const SectionNode &sn = sectionNode(closestSection(newpos, oldpos < newpos)); + c = sn.pos + (oldpos < newpos ? 0 : qMax(0, sectionSize(sn.section) - 1)); + if (allowChange) + edit->setCursorPosition(c); + s = sn.section; + } + } + + if (allowChange && currentSection != s) { + QString tmp = edit->displayText(); + int pos = edit->cursorPosition(); + if (q->validate(tmp, pos) != QValidator::Acceptable) { + interpret(EmitIfChanged); + if (c == -1) { + setSelected(s, true); + } else { + edit->setCursorPosition(pos); + } + } + updateSpinBox(); + } + currentSection = s; + ignoreCursorPositionChanged = false; + +} + +#ifdef Q_WS_MAC +static QString macParseDateLocale(QVariant::Type type) +{ + CFGregorianDate macGDate; + macGDate.year = 2999; + macGDate.month = 11; + macGDate.day = 22; + macGDate.hour = 10; + macGDate.minute = 34; + macGDate.second = 56.0; + QCFType myDate = CFDateCreate(0, CFGregorianDateGetAbsoluteTime(macGDate, QCFType + (CFTimeZoneCopySystem()))); + switch (type) { + case QVariant::Date: { +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3) + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_3) { + QCFType mylocale = CFLocaleCopyCurrent(); + QCFType myFormatter = CFDateFormatterCreate(kCFAllocatorDefault, + mylocale, kCFDateFormatterShortStyle, + kCFDateFormatterNoStyle); + return QCFString(CFDateFormatterCreateStringWithDate(0, myFormatter, myDate)); + + } else +#endif + { + Handle intlHandle = GetIntlResource(0); + LongDateTime oldDate; + UCConvertCFAbsoluteTimeToLongDateTime(CFGregorianDateGetAbsoluteTime(macGDate, 0), + &oldDate); + Str255 pString; + LongDateString(&oldDate, shortDate, pString, intlHandle); + return qt_mac_from_pascal_string(pString); + } + } + case QVariant::DateTime: { +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3) + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_3) { + QCFType mylocale = CFLocaleCopyCurrent(); + QCFType myFormatter = CFDateFormatterCreate(kCFAllocatorDefault, + mylocale, kCFDateFormatterShortStyle, + kCFDateFormatterMediumStyle); + return QCFString(CFDateFormatterCreateStringWithDate(0, myFormatter, myDate)); + + } else +#endif + { + Handle intlHandle = GetIntlResource(0); + LongDateTime oldDate; + UCConvertCFAbsoluteTimeToLongDateTime(CFGregorianDateGetAbsoluteTime(macGDate, 0), + &oldDate); + Str255 pString; + LongDateString(&oldDate, shortDate, pString, intlHandle); + QString final = qt_mac_from_pascal_string(pString); + LongTimeString(&oldDate, true, pString, intlHandle); + return final + QLatin1Char(' ') + qt_mac_from_pascal_string(pString); + } + } + default: return QString(); + } +} +#endif - Returns the end of the section offset \a sec. +/*! + \internal + Try to get the format from the local settings */ - -int ExtDateEdit::sectionOffsetEnd( int sec ) const +void ExtDateTimeEditPrivate::readLocaleSettings() { - 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 ); + EDTEDEBUG << ExtDateTimeEdit::tr("PM") + << ExtDateTimeEdit::tr("AM") + << ExtDateTimeEdit::tr("pm") + << ExtDateTimeEdit::tr("am"); + + // Time + QString str = QTime(10, 34, 56).toString(Qt::LocalDate); + int index = str.indexOf(QLatin1String("10")); + if (index != -1) + str.replace(index, 2, QLatin1String("hh")); + + index = str.indexOf(QLatin1String("34")); + if (index != -1) + str.replace(index, 2, QLatin1String("mm")); + + index = str.indexOf(QLatin1String("56")); + if (index != -1) + str.replace(index, 2, QLatin1String("ss")); + + QString am = QLatin1String("am"); + index = str.indexOf(am); + if (index != -1) { + str.replace(index, am.size(), QLatin1String("ap")); + } else { + am = QLatin1String("AM"); + + index = str.indexOf(am); + if (index != -1) + str.replace(index, am.size(), QLatin1String("AP")); } - } 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 ); + + defaultTimeFormat = str; + + // Date + + const ExtDate date(2999, 11, 22); + const QString shortMonthName = ExtDate::shortMonthName(date.month()); + const QString longMonthName = ExtDate::longMonthName(date.month()); + const QString shortDayName = ExtDate::shortDayName(date.dayOfWeek()); + const QString longDayName = ExtDate::longDayName(date.dayOfWeek()); + +#ifdef Q_WS_MAC + str = macParseDateLocale(QVariant::Date); +#else + str = date.toString(Qt::LocalDate); +#endif + + index = str.indexOf(QLatin1String("22")); + if (index != -1) + str.replace(index, 2, QLatin1String("dd")); + + index = str.indexOf(shortDayName); + if (index != -1) + str.remove(index, shortDayName.size()); + + index = str.indexOf(longDayName); + if (index != -1) + str.remove(index, longDayName.size()); + + index = str.indexOf(QLatin1String("11")); + if (index != -1) { + str.replace(index, 2, QLatin1String("MM")); + } else if ((index = str.indexOf(longMonthName)) != -1) { + str.replace(index, longMonthName.size(), QLatin1String("MMM")); + } else if ((index = str.indexOf(shortMonthName)) != -1) { + str.replace(index, shortMonthName.size(), QLatin1String("MMM")); } - } 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 ); + + index = str.indexOf(QLatin1String("2999")); + if (index != -1) { + str.replace(index, 4, QLatin1String("yyyy")); + } else { + index = str.indexOf(QLatin1String("99")); + if (index != -1) + str.replace(index, 2, QLatin1String("yy")); } - } - return 0; -} + defaultDateFormat = str; -/*! - \property ExtDateEdit::order - \brief the order in which the year, month and day appear + // DateTime +#ifdef Q_WS_MAC + str = macParseDateLocale(QVariant::DateTime); +#else + str = ExtDateTime(ExtDate(2999, 11, 22), QTime(10, 34, 56)).toString(Qt::LocalDate); +#endif + index = str.indexOf(QLatin1String("10")); + if (index != -1) + str.replace(index, 2, QLatin1String("hh")); - The default order is locale dependent. + index = str.indexOf(QLatin1String("34")); + if (index != -1) + str.replace(index, 2, QLatin1String("mm")); - \sa Order -*/ + index = str.indexOf(QLatin1String("56")); + if (index != -1) + str.replace(index, 2, QLatin1String("ss")); -void ExtDateEdit::setOrder( ExtDateEdit::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(), FALSE ); -} + am = QLatin1String("am"); + index = str.indexOf(am); + if (index != -1) { + str.replace(index, am.size(), QLatin1String("ap")); + } else { + am = QLatin1String("AM"); -ExtDateEdit::Order ExtDateEdit::order() const -{ - return d->ord; + index = str.indexOf(am); + if (index != -1) + str.replace(index, am.size(), QLatin1String("AP")); + } + + index = str.indexOf(QLatin1String("22")); + if (index != -1) + str.replace(index, 2, QLatin1String("dd")); + + index = str.indexOf(shortDayName); + if (index != -1) + str.remove(index, shortDayName.size()); + + index = str.indexOf(longDayName); + if (index != -1) + str.remove(index, longDayName.size()); + + index = str.indexOf(QLatin1String("11")); + if (index != -1) { + str.replace(index, 2, QLatin1String("MM")); + } else if ((index = str.indexOf(longMonthName)) != -1) { + str.replace(index, longMonthName.size(), QLatin1String("MMM")); + } else if ((index = str.indexOf(shortMonthName)) != -1) { + str.replace(index, shortMonthName.size(), QLatin1String("MMM")); + } + + index = str.indexOf(QLatin1String("2999")); + if (index != -1) { + str.replace(index, 4, QLatin1String("yyyy")); + } else { + index = str.indexOf(QLatin1String("99")); + if (index != -1) + str.replace(index, 2, QLatin1String("yy")); + } + + defaultDateTimeFormat = str; + + EDTEDEBUG << "default Time:" << defaultTimeFormat << "default date:" << defaultDateFormat << "default date/time" << defaultDateTimeFormat; } +/*! + \internal + Gets the digit from a corevariant. E.g. + + QVariant var(ExtDate(2004, 02, 02)); + int digit = getDigit(var, Year); + // digit = 2004 + */ + +int ExtDateTimeEditPrivate::getDigit(const QVariant &t, Section s) const +{ + switch (s) { + case HourSection: return t.toTime().hour(); + case MinuteSection: return t.toTime().minute(); + case SecondSection: return t.toTime().second(); + case MSecSection: return t.toTime().msec(); + case YearTwoDigitsSection: + case YearSection: return t.toDate().year(); + case MonthShortNameSection: + case MonthSection: return t.toDate().month(); + case DaySection: return t.toDate().day(); + case AmPmSection: + case AmPmLowerCaseSection: + return t.toTime().hour() > 11 ? 1 : 0; + + default: break; + } + qFatal("%s passed to getDigit. This should never happen", sectionName(s).toLatin1().constData()); + return -1; +} -/*! \reimp +/*! + \internal + Sets a digit in a variant. E.g. + + QVariant var(ExtDate(2004, 02, 02)); + int digit = getDigit(var, Year); + // digit = 2004 + setDigit(&var, Year, 2005); + digit = getDigit(var, Year); + // digit = 2005 + + returns true if the newVal was changed to make it work. E.g. If you set 31st when you're in february +*/ + +void ExtDateTimeEditPrivate::setDigit(QVariant &v, Section section, int newVal) const +{ + int year, month, day, hour, minute, second, msec; + const ExtDateTime &dt = v.toDateTime(); + year = dt.date().year(); + month = dt.date().month(); + day = dt.date().day(); + hour = dt.time().hour(); + minute = dt.time().minute(); + second = dt.time().second(); + msec = dt.time().msec(); + + switch (section) { + case HourSection: hour = newVal; break; + case MinuteSection: minute = newVal; break; + case SecondSection: second = newVal; break; + case MSecSection: msec = newVal; break; + case YearTwoDigitsSection: + case YearSection: year = newVal; break; + case MonthSection: + case MonthShortNameSection: month = newVal; break; + case DaySection: day = newVal; break; + case AmPmSection: + case AmPmLowerCaseSection: hour = (newVal == 0 ? hour % 12 : (hour % 12) + 12); break; + default: + qFatal("%s passed to setDigit. This should never happen", sectionName(section).toLatin1().constData()); + break; + } -*/ -void ExtDateEdit::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 ); + if (section != DaySection) { + day = qMax(cachedDay, day); } - } 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 (!ExtDate::isValid(year, month, day)) { + if (year <= DATE_MIN.year() && (month < DATE_MIN.month() || (month == DATE_MIN.month() && day < DATE_MIN.day()))) { + month = DATE_MIN.month(); + day = DATE_MIN.day(); + } else { + day = qMin(day, ExtDate(year, month, 1).daysInMonth()); + } } - } - if ( accepted ) { - d->changed = TRUE; - emit valueChanged( date() ); - } - - d->ed->repaint( d->ed->rect(), FALSE ); + v = QVariant(ExtDateTime(ExtDate(year, month, day), QTime(hour, minute, second, msec))); } +/*! + \internal -/*! \reimp + Internal function called by ExtDateTimeEdit::stepBy(). Also takes a + Section for which section to step on and a bool \a test for + whether or not to modify the internal cachedDay variable. This is + necessary because the function is called from the const function + ExtDateTimeEdit::stepEnabled() as well as ExtDateTimeEdit::stepBy(). +*/ + +QVariant ExtDateTimeEditPrivate::stepBy(Section s, int steps, bool test) const +{ + Q_Q(const ExtDateTimeEdit); + QVariant v = value; + QString str = edit->displayText(); + int pos = edit->cursorPosition(); + bool specVal = specialValue(); + + int val; + // to make sure it behaves reasonably when typing something and then stepping in non-tracking mode + if (!test && pendingEmit) { + if (q->validate(str, pos) != QValidator::Acceptable) { + v = value; + } else { + v = valueFromText(str); + } + val = getDigit(v, s); + } else { + QValidator::State state; + if (!specVal) { + val = sectionValue(s, str, state); + if (state == QValidator::Invalid) { + return value; + } + } else { + val = getDigit(v, s); + } + } -*/ + val += steps; -void ExtDateEdit::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 ); + const int min = absoluteMin(s); + const int max = absoluteMax(s); + + if (val < min) { + val = (wrapping ? max - (min - val) + 1 : min); + } else if (val > max) { + val = (wrapping ? min + val - max - 1 : max); } - } else if ( sec == d->monthSection ) { - if ( !outOfRange( d->y, d->m-1, d->d ) ) { - accepted = TRUE; - setMonth( d->m-1 ); + + const int tmp = v.toDate().day(); + setDigit(v, s, val); // if this sets year or month it will make + // sure that days are lowered if needed. + + // changing one section should only modify that section, if possible + if (s != AmPmSection && (v < minimum || v > maximum)) { + + const int localmin = getDigit(minimum, s); + const int localmax = getDigit(maximum, s); + + if (wrapping) { + // just because we hit the roof in one direction, it + // doesn't mean that we hit the floor in the other + if (steps > 0) { + setDigit(v, s, min); + if (s != DaySection) { + int daysInMonth = v.toDate().daysInMonth(); + if (v.toDate().day() < tmp && v.toDate().day() < daysInMonth) + setDigit(v, DaySection, qMin(tmp, daysInMonth)); + } + + if (v < minimum) { + setDigit(v, s, localmin); + if (v < minimum) + setDigit(v, s, localmin + 1); + } + } else { + setDigit(v, s, max); + if (s != DaySection) { + int daysInMonth = v.toDate().daysInMonth(); + if (v.toDate().day() < tmp && v.toDate().day() < daysInMonth) + setDigit(v, DaySection, qMin(tmp, daysInMonth)); + } + + if (v > maximum) { + setDigit(v, s, localmax); + if (v > maximum) + setDigit(v, s, localmax - 1); + } + } + } else { + setDigit(v, s, (steps > 0 ? localmax : localmin)); + } + } + if (!test && tmp != v.toDate().day() && s != DaySection) { + // this should not happen when called from stepEnabled + cachedDay = qMax(tmp, cachedDay); } - } else if ( sec == d->daySection ) { - if ( !outOfRange( d->y, d->m, d->d-1 ) ) { - accepted = TRUE; - setDay( d->d-1 ); + + if (v < minimum) { + if (wrapping) { + QVariant t = v; + setDigit(t, s, steps < 0 ? max : min); + if (t >= minimum && t <= maximum) { + v = t; + } else { + setDigit(t, s, getDigit(steps < 0 ? maximum : minimum, s)); + if (t >= minimum && t <= maximum) { + v = t; + } + } + } else { + v = value; + } + } else if (v > maximum) { + if (wrapping) { + QVariant t = v; + setDigit(t, s, steps > 0 ? min : max); + if (t >= minimum && t <= maximum) { + v = t; + } else { + setDigit(t, s, getDigit(steps > 0 ? minimum : maximum, s)); + if (t >= minimum && t <= maximum) { + v = t; + } + } + } else { + v = value; + } } - } - if ( accepted ) { - d->changed = TRUE; - emit valueChanged( date() ); - } - - d->ed->repaint( d->ed->rect(), FALSE ); + + return bound(v, value, steps); } /*! - Sets the year to \a year, which must be a valid year. The range - currently supported is from 1752 to 8000. + \internal - \sa ExtDate + Returns the absolute maximum for a section */ -void ExtDateEdit::setYear( int year ) +int ExtDateTimeEditPrivate::absoluteMax(Section s) const { - if ( !outOfRange( year, d->m, d->d ) ) { - d->y = year; - setMonth( d->m ); - } -} + switch (s) { + case HourSection: return 23; + case MinuteSection: + case SecondSection: return 59; + case MSecSection: return 999; + case YearTwoDigitsSection: return 2099; + case YearSection: return 7999; + case MonthSection: + case MonthShortNameSection: return 12; + case DaySection: return 31; + case AmPmSection: + case AmPmLowerCaseSection: return 1; + default: break; + } + qFatal("%s passed to max. This should never happen", sectionName(s).toLatin1().constData()); + return -1; +} /*! - Sets the month to \a month, which must be a valid month, i.e. - between 1 and 12. + \internal + + Returns the absolute minimum for a section */ -void ExtDateEdit::setMonth( int month ) +int ExtDateTimeEditPrivate::absoluteMin(Section s) const { - if ( month < 1 ) - month = 1; - if ( month > 12 ) - month = 12; - if ( !outOfRange( d->y, month, d->d ) ) { - d->m = month; - setDay( d->d ); - } + switch (s) { + case HourSection: + case MinuteSection: + case SecondSection: + case MSecSection: return 0; + case YearTwoDigitsSection: return 2000; + case YearSection: return 1753; + case MonthSection: + case MonthShortNameSection: + case DaySection: return 1; + case AmPmSection: + case AmPmLowerCaseSection: return 0; + default: break; + } + qFatal("%s passed to min. This should never happen", sectionName(s).toLatin1().constData()); + return -1; } - /*! - 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. + \internal + + Returns a copy of the sectionNode for the Section \a s. */ -void ExtDateEdit::setDay( int day ) +ExtDateTimeEditPrivate::SectionNode ExtDateTimeEditPrivate::sectionNode(Section s) const { - ExtDate test = ExtDate( d->y, d->m, 1 ); - - if ( day < 1 ) - day = 1; - if ( day > test.daysInMonth() ) - day = test.daysInMonth(); - - d->dayCache = d->d; - d->d = day; -} + if (s == FirstSection) { + return first; + } else if (s == LastSection) { + return last; + } + for (int i=0; iy = 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(), FALSE ); -} - -ExtDate ExtDateEdit::date() const -{ - if ( ExtDate::isValid( d->y, d->m, d->d ) ) - return ExtDate( d->y, d->m, d->d ); - return ExtDate(); -} - -/*! \internal - - Returns TRUE if \a y, \a m, \a d is out of range, otherwise returns - FALSE. - - \sa setRange() - -*/ - -bool ExtDateEdit::outOfRange( int y, int m, int d ) const -{ - if ( ExtDate::isValid( y, m, d ) ) { - ExtDate currentDate( y, m, d ); - if ( currentDate > maxValue() || currentDate < minValue() ) { - //## outOfRange should set overwrite? - return TRUE; - } - return FALSE; - } - return FALSE; /* assume ok */ -} - -/*! \reimp - -*/ - -void ExtDateEdit::addNumber( int sec, int num ) -{ - if ( sec == -1 ) - return; - killTimer( d->timerId ); - 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 ) { - int val = txt.toInt(); - if ( val < 1792 ) - d->y = 1792; - else if ( val > 8000 ) - d->y = 8000; - else 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 = TRUE; - emit valueChanged( date() ); - } - d->overwrite = overwrite; - d->timerId = startTimer( qApp->doubleClickInterval()*4 ); - d->ed->repaint( d->ed->rect(), FALSE ); -} - - -/*! \reimp - -*/ - -bool ExtDateEdit::setFocusSection( int s ) -{ - if ( s != d->ed->focusSection() ) { - killTimer( d->timerId ); - 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: - - - if the day is larger than the number of days in the month, - - it is reset to that number - - If the year has four digits it is left unchanged. - - If the year has two digits, the year will be changed to four - digits in the range current year - 70 to current year + 29. - - 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. - -*/ - -void ExtDateEdit::fix() -{ - bool changed = FALSE; - - ExtDate test = ExtDate( d->y, d->m, 1 ); - if ( d->d > test.daysInMonth() ) { - - d->d = test.daysInMonth(); - changed = TRUE; - } - - int currentYear = ExtDate::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; - } - if ( changed && 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(); - } - } else if ( changed ) - setYear( year ); - - if ( changed ) { -// emit valueChanged( date() ); -// d->changed = FALSE; - } -} + if (s == FirstSection) { + return first.pos; + } else if (s == LastSection) { + return last.pos; + } + for (int i=0; i &list, Section ds, int pos) const { - if( e->type() == QEvent::FocusOut ) { - d->typing = FALSE; - // the following can't be done in fix() because fix() called - // from all over the place and it will break the old behaviour - if ( !ExtDate::isValid( d->y, d->m, d->d ) ) { - d->dayCache = d->d; - int i = d->d; - for ( ; i > 0; i-- ) { - d->d = i; - if ( ExtDate::isValid( d->y, d->m, d->d ) ) - break; - } - d->changed = TRUE; + for (int i=0; ichanged ) { - fix(); - emit valueChanged( date() ); - d->changed = FALSE; - } - } else if ( e->type() == QEvent::LocaleChange ) { - readLocaleSettings(); - d->ed->setSeparator( localDateSep() ); - setOrder( localOrder() ); - } + SectionNode s; + s.section = ds; + s.pos = pos; + list << s; - bool result = ExtDateTimeEditBase::event( e ); - - return result; + return true; } + /*! \internal - Function which is called whenever the user tries to - remove the first number from \a sec by pressing the backspace key. + Selects the section \a s. If \a forward is false selects backwards. */ -void ExtDateEdit::removeFirstNumber( int sec ) +void ExtDateTimeEditPrivate::setSelected(Section s, bool forward) { - if ( sec == -1 ) - return; - QString txt; - if ( sec == d->yearSection ) { - txt = QString::number( d->y ); - txt = txt.mid( 1, txt.length() ) + "0"; - d->y = txt.toInt(); - } else if ( sec == d->monthSection ) { - txt = QString::number( d->m ); - txt = txt.mid( 1, txt.length() ) + "0"; - d->m = txt.toInt(); - } else if ( sec == d->daySection ) { - txt = QString::number( d->d ); - txt = txt.mid( 1, txt.length() ) + "0"; - d->d = txt.toInt(); - d->dayCache = d->d; + if (s == NoSection) + return; + if (specialValue()) + edit->selectAll(); + if (forward) { + edit->setSelection(sectionPos(s), sectionSize(s)); + } else { + edit->setSelection(sectionPos(s) + sectionSize(s), -sectionSize(s)); } - d->ed->repaint( d->ed->rect(), FALSE ); } -/*! \reimp +/*! + \internal helper function for parseFormat. removes quotes that are + not escaped and removes the escaping on those that are escaped + +*/ + +static QString unquote(const QString &str) +{ + const char quote = '\''; + const char slash = '\\'; + const char zero = '0'; + QString ret; + QChar status = zero; + for (int i=0; i newSectionNodes; + ExtDateTimeEdit::Sections newDisplay = 0; + QStringList newSeparators; + int i, index = 0; + int add = 0; + QChar status = zero; + for (i = 0; i YY_MAX))) { + return false; + } + + newSeparators << unquote(newFormat.mid(index, i - index)); + index = (i += (four ? 3 : 1)) + 1; + newDisplay |= ExtDateTimeEdit::YearSection; + } + break; + case 'M': + if (newFormat.at(i+1) == QLatin1Char('M')) { + const bool three = (i + 2 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; + newSeparators << (index < newFormat.size() ? unquote(newFormat.mid(index)) : QString()); + + display = newDisplay; + last.pos = newFormat.size(); + + if (!QApplication::isRightToLeft()) { + displayFormat = newFormat; + separators = newSeparators; + sectionNodes = newSectionNodes; + } else { + displayFormat.clear();; + int total = newFormat.size(); + int i; + sectionNodes.clear(); + separators.clear(); + + for (i=newSectionNodes.size() - 1; i>=0; --i) { + displayFormat += newSeparators.at(i + 1); + displayFormat += sectionFormat(newSectionNodes.at(i).section); + SectionNode sn = newSectionNodes.at(i); + sn.pos = total - sn.pos - sectionSize(sn.section); + + sectionNodes.append(sn); + separators.append(newSeparators.at(i + 1)); + } + displayFormat += newSeparators.at(0); + separators.append(newSeparators.at(0)); + } + escapedFormat.clear(); + status = zero; + int ampmsize = sectionSize(AmPmSection); + for (int i = 0; i < displayFormat.size(); ++i) { + if (displayFormat.at(i) == quote){ + if (status == quote) { + if (!escapedFormat.isEmpty() && displayFormat.at(i - 1) == slash) { + escapedFormat[escapedFormat.size() - 1] = quote; + } else { + status = zero; + } + } else { + status = quote; + } + } else { + escapedFormat += displayFormat.at(i); + if (i > 1 && ampmsize != 2 + && ((displayFormat.at(i - 1) == QLatin1Char('a') && displayFormat.at(i) == 'p') + || (displayFormat.at(i - 1) == QLatin1Char('A') && displayFormat.at(i) == 'P'))) { + if (ampmsize > 2) { + escapedFormat.append(QString().leftJustified(ampmsize - 2, space)); + } else if (ampmsize == 1) { + escapedFormat.remove(i, 1); + } else { + qWarning("Translating am/pm to an empty string will " + "cause problems for ExtDateTimeEdit"); + } + } + } + } + + if (QApplication::isRightToLeft()) { + // we want displayFormat to return what you set with + // setDisplayFormat() in rtol mode as well. I needed to + // reverse it to calculate the escapedFormat correctly. Set it + // back here. + displayFormat = newFormat; } - d->ed->repaint( d->ed->rect(), FALSE ); + + +// qDebug() << newFormat << displayFormat; +// qDebug("escapedFormat = [%s]", escapedFormat.toLatin1().constData()); +// qDebug("separators:\n'%s'", separators.join("|").toLatin1().constData()); + +// qDebug("display is [%0x]", (uint)display); + + return true; } /*! - \property ExtDateEdit::autoAdvance - \brief whether the editor automatically advances to the next - section + \internal - 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. + Returns the section at index \a index or NoSection if there are no sections there. */ -void ExtDateEdit::setAutoAdvance( bool advance ) +ExtDateTimeEditPrivate::Section ExtDateTimeEditPrivate::sectionAt(int index) const { - d->adv = advance; -} + if (index < separators.first().size()) { + return (index == 0 ? FirstSection : NoSection); + } else if (escapedFormat.size() - index < separators.last().size() + 1) { + if (separators.last().size() == 0) { + return sectionNodes.last().section; + } + return (index == last.pos ? LastSection : NoSection); + } +// QString deb; + for (int i=0; iadv; + if (index < tmp + sectionSize(sectionNodes.at(i).section)) { + return (index < tmp ? NoSection : sectionNodes.at(i).section); + } + } +// qDebug() << deb; + return NoSection; } -/*! \reimp +/*! + \internal + + Returns the closest section of index \a index. Searches forward + for a section if \a forward is true. Otherwise searches backwards. */ -void ExtDateEdit::timerEvent( QTimerEvent * ) +ExtDateTimeEditPrivate::Section ExtDateTimeEditPrivate::closestSection(int index, bool forward) const { - d->overwrite = TRUE; + Q_ASSERT(index >= 0); + if (index < separators.first().size()) { + return forward ? sectionNodes.first().section : FirstSection; + } else if (last.pos - index < separators.last().size() + 1) { + return forward ? LastSection : sectionNodes.last().section; + } + for (int i=0; i tmp) { + return sectionNodes.at(i).section; + } + } + qWarning("2index return NoSection. This should not happen"); + return NoSection; } /*! - \fn void ExtDateEdit::valueChanged( const ExtDate& date ) + \internal - This signal is emitted whenever the editor's value changes. The \a - date parameter is the new value. + Returns a copy of the section that is before or after \a current, depending on \a forward. */ -/////////// - -class QTimeEditPrivate +ExtDateTimeEditPrivate::SectionNode ExtDateTimeEditPrivate::nextPrevSection(Section current, bool forward) const { -public: - int h; - int m; - int s; - uint display; - bool adv; - bool overwrite; - int timerId; - bool typing; - QTime min; - QTime max; - bool changed; - ExtDateTimeEditor *ed; - Q3SpinWidget *controls; -}; + if (QApplication::isRightToLeft()) + forward = !forward; + if (current == FirstSection) { + return (forward ? sectionNodes.first() : first); + } else if (current == LastSection) { + return (forward ? last : sectionNodes.last()); + } + for (int i=0; i= 0 && index < sectionNodes.size()) { + return sectionNodes.at(index); + } else { + break; + } + } + } + return (forward ? last : first); +} /*! - \class QTimeEdit ExtDatetimeedit.h - \brief The QTimeEdit class provides a time editor. + \internal - \ingroup advanced - \ingroup time - \mainclass + Clears the text of section \a s. +*/ - QTimeEdit 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 QTimeEdit - 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 QTimeEdit - is initialised with a time, e.g. - \code - QTime timeNow = QTime::currentTime(); - QTimeEdit *timeEdit = new QTimeEdit( timeNow, this ); - timeEdit->setRange( timeNow, timeNow.addSecs( 60 * 60 ) ); - \endcode - Here we've created a QTimeEdit 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 ExtDateEdit ExtDateTimeEdit -*/ - - -// /*! -// Constructs an empty time edit with parent \a parent and called \a -// name. -// */ -// -// QTimeEdit::QTimeEdit( QWidget * parent, const char * name ) -// : ExtDateTimeEditBase( parent, name ) -// { -// init(); -// } -// -// /*! -// \overload -// -// Constructs a time edit with the initial time value, \a time, -// parent \a parent and called \a name. -// */ -// -// QTimeEdit::QTimeEdit( const QTime& time, QWidget * parent, const char * name ) -// : ExtDateTimeEditBase( parent, name ) -// { -// init(); -// setTime( time ); -// } -// -// /*! \internal -// */ -// -// void QTimeEdit::init() -// { -// d = new QTimeEditPrivate(); -// d->ed = new ExtDateTimeEditor( this, "time edit base" ); -// d->controls = new ExtDateTimeSpinWidget( this, qstrcmp( name(), "qt_datetime_timeedit" ) == 0 ? "qt_spin_widget" : "time edit controls" ); -// 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. -// */ -// -// QTimeEdit::~QTimeEdit() -// { -// delete d; -// if ( !--refcount ) -// cleanup(); -// } -// -// /*! -// \property QTimeEdit::minValue -// \brief the minimum time value -// -// Setting the minimum time value is equivalent to calling -// QTimeEdit::setRange( \e t, maxValue() ), where \e t is the minimum -// time. The default minimum time is 00:00:00. -// -// \sa maxValue setRange() -// */ -// -// QTime QTimeEdit::minValue() const -// { -// return d->min; -// } -// -// /*! -// \property QTimeEdit::maxValue -// \brief the maximum time value -// -// Setting the maximum time value is equivalent to calling -// QTimeEdit::setRange( minValue(), \e t ), where \e t is the maximum -// time. The default maximum time is 23:59:59. -// -// \sa minValue setRange() -// */ -// -// QTime QTimeEdit::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 QTimeEdit::setRange( const QTime& min, const QTime& max ) -// { -// if ( min.isValid() ) -// d->min = min; -// if ( max.isValid() ) -// d->max = max; -// } -// -// /*! -// \property QTimeEdit::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 QTimeEdit::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 QTimeEdit::display() const -// { -// return d->display; -// } -// -// /*! -// \property QTimeEdit::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 QTimeEdit::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(), FALSE ); -// } -// -// QTime QTimeEdit::time() const -// { -// if ( QTime::isValid( d->h, d->m, d->s ) ) -// return QTime( d->h, d->m, d->s ); -// return QTime(); -// } -// -// /*! -// \property QTimeEdit::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 QTimeEdit::setAutoAdvance( bool advance ) -// { -// d->adv = advance; -// } -// -// bool QTimeEdit::autoAdvance() const -// { -// return d->adv; -// } -// -// /*! -// Sets the separator to \a s. Note that currently only the first -// character of \a s is used. -// */ -// -// void QTimeEdit::setSeparator( const QString& s ) -// { -// d->ed->setSeparator( s ); -// } -// -// /*! -// Returns the editor's separator. -// */ -// -// QString QTimeEdit::separator() const -// { -// return d->ed->separator(); -// } -// -// -// /*! -// \fn void QTimeEdit::valueChanged( const QTime& time ) -// -// This signal is emitted whenever the editor's value changes. The \a -// time parameter is the new value. -// */ -// -// /*! \reimp -// -// */ -// -// bool QTimeEdit::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 ExtDateTimeEditBase::event( e ); -// } -// -// /*! \reimp -// -// */ -// -// void QTimeEdit::timerEvent( QTimerEvent * ) -// { -// d->overwrite = TRUE; -// } -// -// -// /*! \reimp -// -// */ -// -// void QTimeEdit::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; -// #ifdef QT_CHECK_RANGE -// qWarning( "QTimeEdit::stepUp: Focus section out of range!" ); -// #endif -// break; -// } -// if ( accepted ) { -// d->changed = TRUE; -// emit valueChanged( time() ); -// } -// d->ed->repaint( d->ed->rect(), FALSE ); -// } -// -// -// /*! \reimp -// -// */ -// -// void QTimeEdit::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; -// #ifdef QT_CHECK_RANGE -// qWarning( "QTimeEdit::stepDown: Focus section out of range!" ); -// #endif -// break; -// } -// if ( accepted ) { -// d->changed = TRUE; -// emit valueChanged( time() ); -// } -// d->ed->repaint( d->ed->rect(), FALSE ); -// } -// -// -// /*! -// Returns the formatted number for section \a sec. This will -// correspond to either the hour, minute or second section, depending -// on \a sec. -// */ -// -// QString QTimeEdit::sectionFormattedText( int sec ) -// { -// QString txt; -// txt = sectionText( sec ); -// txt = txt.rightJustify( 2, EXTDATETIMEEDIT_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; -// } -// -// -// /*! \reimp -// -// */ -// -// bool QTimeEdit::setFocusSection( int sec ) -// { -// if ( sec != d->ed->focusSection() ) { -// killTimer( d->timerId ); -// d->overwrite = TRUE; -// d->typing = FALSE; -// QString txt = sectionText( sec ); -// txt = txt.rightJustify( 2, EXTDATETIMEEDIT_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 QTimeEdit::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 QTimeEdit::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 QTimeEdit::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 QTimeEdit::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 = "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 QTimeEdit::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; -// } -// -// /*! \reimp -// -// */ -// -// void QTimeEdit::addNumber( int sec, int num ) -// { -// if ( sec == -1 ) -// return; -// sec = d->ed->mapSection( sec ); -// killTimer( d->timerId ); -// 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(), FALSE ); -// } -// -// -// /*! -// \internal -// -// Function which is called whenever the user tries to -// remove the first number from \a sec by pressing the backspace key. -// */ -// -// void QTimeEdit::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() ) + "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(), FALSE ); -// } -// -// /*! \reimp -// -// */ -// void QTimeEdit::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(), FALSE ); -// } -// -// /*! \reimp -// */ -// void QTimeEdit::resizeEvent( QResizeEvent * ) -// { -// d->controls->resize( width(), height() ); -// } -// -// /*! \reimp -// */ -// QSize QTimeEdit::sizeHint() const -// { -// constPolish(); -// QFontMetrics fm( font() ); -// int fw = style().pixelMetric( QStyle::PM_DefaultFrameWidth, this ); -// int h = fm.lineSpacing() + 2; -// int w = 2 + fm.width( '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 QTimeEdit::minimumSizeHint() const -// { -// return sizeHint(); -// } -// -// /*! -// \internal -// Enables/disables the push buttons according to the min/max time -// for this widget. -// */ -// -// // ### Remove in 4.0? -// -// void QTimeEdit::updateButtons() -// { -// if ( !isEnabled() ) -// return; -// -// bool upEnabled = time() < maxValue(); -// bool downEnabled = time() > minValue(); -// -// d->controls->setUpEnabled( upEnabled ); -// d->controls->setDownEnabled( downEnabled ); -// } - - -class ExtDateTimeEditPrivate +void ExtDateTimeEditPrivate::clearSection(Section s) { -public: - bool adv; -}; + const char space = ' '; + int cursorPos = edit->cursorPosition(); + bool blocked = edit->blockSignals(true); + QString t = edit->text(); + t.replace(sectionPos(s), sectionSize(s), QString().fill(space, sectionSize(s))); + edit->setText(t); + edit->setCursorPosition(cursorPos); + edit->blockSignals(blocked); +} /*! - \class ExtDateTimeEdit ExtDatetimeedit.h - \brief The ExtDateTimeEdit class combines a ExtDateEdit and QTimeEdit - widget into a single widget for editing datetimes. + \internal - \ingroup advanced - \ingroup time + Returns the size of section \a s. +*/ - ExtDateTimeEdit consists of a ExtDateEdit and QTimeEdit 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 ExtDateTimeEdit widget, and - the user can be moved automatically when they complete a section - using setAutoAdvance(). The datetime can be set with - setDateTime(). +int ExtDateTimeEditPrivate::sectionSize(Section s) const +{ + switch (s) { + case FirstSection: + case NoSection: + case LastSection: return 0; - 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 - ExtDateEdit::setOrder() to change this. Times appear in the order - hours, minutes, seconds using the 24 hour clock. + case AmPmSection: + case AmPmLowerCaseSection: { + int lower = qMin(ExtDateTimeEdit::tr("pm").size(), ExtDateTimeEdit::tr("am").size()); + int upper = qMin(ExtDateTimeEdit::tr("PM").size(), ExtDateTimeEdit::tr("AM").size()); + return qMin(4, qMin(lower, upper)); + } - It is recommended that the ExtDateTimeEdit is initialised with a - datetime, e.g. - \code - ExtDateTimeEdit *dateTimeEdit = new ExtDateTimeEdit( ExtDateTime::currentDateTime(), this ); - dateTimeEdit->dateEdit()->setRange( ExtDateTime::currentDate(), - ExtDateTime::currentDate().addDays( 7 ) ); - \endcode - Here we've created a new ExtDateTimeEdit 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. + case HourSection: + case MinuteSection: + case SecondSection: + case DaySection: + case MonthSection: + case YearTwoDigitsSection: return 2; - Terminology: A ExtDateEdit widget consists of three 'sections', one - each for the year, month and day. Similarly a QTimeEdit 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. + case MonthShortNameSection: + case MSecSection: return 3; - \image html datetimewidgets.png "Date Time Widgets" + case YearSection: return 4; - \sa ExtDateEdit QTimeEdit -*/ + case Internal: + case TimeSectionMask: + case DateSectionMask: qWarning("Invalid section %s", sectionName(s).toLatin1().constData()); + } + return -1; +} /*! - Constructs an empty datetime edit with parent \a parent and called - \a name. + \internal + + Returns the text of section \a s. This function operates on the + arg text rather than edit->text(). */ -ExtDateTimeEdit::ExtDateTimeEdit( QWidget * parent, const char * name ) - : QWidget( parent, name ) + + +QString ExtDateTimeEditPrivate::sectionText(const QString &text, Section s) const { - init(); + const SectionNode sn = sectionNode(s); + return sn.section == NoSection ? QString() : text.mid(sn.pos, sectionSize(s)); } - /*! - \overload + \internal - Constructs a datetime edit with the initial value \a datetime, - parent \a parent and called \a name. + Parses the part of \a text that corresponds to \a s and returns + the value of that field. Sets *stateptr to the right state if + stateptr != 0. */ -ExtDateTimeEdit::ExtDateTimeEdit( const ExtDateTime& datetime, - QWidget * parent, const char * name ) - : QWidget( parent, name ) + +int ExtDateTimeEditPrivate::sectionValue(Section s, QString &text, QValidator::State &state) const { - init(); - setDateTime( datetime ); -} + const char space = ' '; + state = QValidator::Invalid; + int num = 0; + QString st = sectionText(text, s); + EDTEDEBUG << "sectionValue for" << sectionName(s) + << "with text" << text << "and st" << st; + if (st.trimmed().isEmpty()) { + state = QValidator::Intermediate; + } else { + const int index = sectionNode(s).pos; + const int size = sectionSize(s); + const bool done = !st.contains(space); + switch (s) { + case AmPmSection: + case AmPmLowerCaseSection: { + int ampm = findAmPm(st, s); + switch (ampm) { + case AM: // st == AM + case PM: // st == PM + num = ampm; + state = QValidator::Acceptable; + break; + case PossibleAM: // st => AM + case PossiblePM: // st => PM + num = ampm - 2; + state = QValidator::Intermediate; + break; + case PossibleBoth: // st => AM|PM + num = 0; + state = QValidator::Intermediate; + break; + case Neither: + state = QValidator::Invalid; + EDTEDEBUG << "invalid because findAmPm(" << st << ") returned -1"; + break; + default: + EDTEDEBUGN("This should never happen (findAmPm returned %d", ampm); + break; + } + if (state != QValidator::Invalid) { + text.replace(index, size, st); + } + break; + } + case MonthShortNameSection: { + st = st.toLower(); + int tmp = findMonth(st); + if (tmp != -1) { + num = tmp; + if (done) { + state = QValidator::Acceptable; + st = ExtDate::shortMonthName(num); + text.replace(index, size, st); + } else { + state = QValidator::Intermediate; + } + } else { + state = QValidator::Invalid; + EDTEDEBUG << "invalid because" << st << "doesn't match any month name"; + } + break; + } + case YearTwoDigitsSection: num = 2000; + case YearSection: + case MonthSection: + case HourSection: + case MinuteSection: + case SecondSection: + case MSecSection: + case DaySection: { + bool ok; + num += (int)(st.toUInt(&ok)); + if (!ok) { + state = QValidator::Invalid; + EDTEDEBUG << "invalid because" << st << "can't become a uint"; + } else { + if (s == HourSection && display & AmPmSection) { + bool pm = (sectionText(text, AmPmSection).toLower() == "pm"); + if (pm && num < 12) { + num += 12; + } else if (!pm && num == 12) { + num = 0; + } else if (num > 12) { + state = QValidator::Invalid; + EDTEDEBUG << "invalid because" << st << "num is" << num; + + break; + } + } + if (num < absoluteMin(s) || num > absoluteMax(s)) { + state = done ? QValidator::Invalid : QValidator::Intermediate; + if (done) + EDTEDEBUG << "invalid because" << st << "num is" << num + << "outside absoluteMin and absoluteMax" << absoluteMin(s) << absoluteMax(s); + + } else { + state = QValidator::Acceptable; + } + } + break; + } + default: qFatal("NoSection or Internal. This should never happen"); break; } + } + return (state != QValidator::Invalid ? num : -1); +} /*! - Destroys the object and frees any allocated resources. + \internal + \reimp */ -ExtDateTimeEdit::~ExtDateTimeEdit() +QVariant ExtDateTimeEditPrivate::validateAndInterpret(QString &input, + int &pos, QValidator::State &state) const { - delete d; + const char space = ' '; + if (cachedText == input) { + state = cachedState; + EDTEDEBUG << "state" << state << "cachedText" << cachedText << "cachedValue" << cachedValue; + return cachedValue; + } + QVariant tmp; + SectionNode sn = {NoSection, 0}; + int index = 0; + + EDTEDEBUG << "validateAndInterpret" << input; + int diff = input.size() - escapedFormat.size(); + bool specval = false; + if (!specialValueText.isEmpty() && input == specialValueText) { + specval = true; + state = QValidator::Acceptable; + tmp = minimum; + goto end; + } + if (diff > 0) { + const Section s = closestSection(pos - 1, false); + if (s == FirstSection && s == LastSection) { + EDTEDEBUG << "invalid because s ==" << sectionName(s); + return QValidator::Invalid; + } + sn = sectionNode(s); + const int sectionstart = sn.pos; + const int sectionsize = sectionSize(s); + + QString sub = input.mid(sectionstart, sectionsize + diff); + if (sub.count(space) < diff) { + EDTEDEBUGN("sub is '%s' diff is %d sub.count is %d", sub.toLatin1().constData(), diff, sub.count(space)); + state = QValidator::Invalid; + goto end; + } + + sub.remove(space); + input.replace(sectionstart, sectionsize + diff, sub.leftJustified(sectionsize, space)); + } else if (diff < 0) { + const Section s = closestSection(pos, false); + if (s == FirstSection && s == LastSection) { + EDTEDEBUG << "invalid because s == " << sectionName(s); + state = QValidator::Invalid; + goto end; + } + sn = sectionNode(s); + const int sectionstart = sn.pos; + const int sectionsize = sectionSize(s); + + QString sub = input.mid(sectionstart, sectionsize + diff); + sub.remove(space); + input.replace(sectionstart, sectionsize + diff, sub.leftJustified(sectionsize, space)); + + sn = sectionNode(currentSection); + } + + for (int i=0; i day) { + day = cachedDay; + fixday = true; + } + + if (!ExtDate::isValid(year, month, day)) { + if (day < 32) { + cachedDay = day; + } else if (day > 28 && ExtDate::isValid(year, month, 1)) { + fixday = true; + } + } + if (fixday) { + day = qMin(day, ExtDate(year, month, 1).daysInMonth()); + const SectionNode &sn = sectionNode(DaySection); + input.replace(sn.pos, sectionSize(DaySection), QString::number(day)); + } + + EDTEDEBUG << year << month << day << hour << minute << second << msec; + tmp = QVariant(ExtDateTime(ExtDate(year, month, day), QTime(hour, minute, second, msec))); + } + EDTEDEBUGN("'%s' => '%s' (%s)", input.toLatin1().constData(), + tmp.toString().toLatin1().constData(), stateName(state).toLatin1().constData()); + } +end: + if (tmp.toDateTime().isValid()) { + if (!specval && state != QValidator::Invalid && tmp < minimum) { + state = checkIntermediate(tmp.toDateTime(), input); + } else { + if (tmp > maximum) + state = QValidator::Invalid; + EDTEDEBUG << "not checking intermediate because tmp is" << tmp << minimum << maximum; + } + } + cachedText = input; + cachedState = state; + cachedValue = tmp; + return tmp; } +/*! + \internal + finds the first possible monthname that \a str1 can match. Starting from \a index; +*/ + +int ExtDateTimeEditPrivate::findMonth(const QString &str1, int index) const +{ + Q_ASSERT(str1.size() == 3); + + for (int month=index; month<=12; ++month) { + QString str2 = ExtDate::shortMonthName(month).toLower(); + bool found = true; + for (int i=0; isizeHint().width(); - int tw = te->sizeHint().width(); - int w = width(); - int h = height(); - int extra = w - ( dw + tw ); + const char space = ' '; + const int size = sectionSize(AmPmSection); + Q_ASSERT(str.size() == size); - if ( tw + extra < 0 ) { - dw = w; + enum { + amindex = 0, + pmindex = 1 + }; + QString ampm[2]; + if (s == AmPmSection) { + ampm[amindex] = ExtDateTimeEdit::tr("AM"); + ampm[pmindex] = ExtDateTimeEdit::tr("PM"); } else { - dw += 9 * extra / 16; + ampm[amindex] = ExtDateTimeEdit::tr("am"); + ampm[pmindex] = ExtDateTimeEdit::tr("pm"); + } + for (int i=0; i<2; ++i) + ampm[i].truncate(size); + + EDTEDEBUG << "findAmPm" << str << ampm[0] << ampm[1]; + + if (str.indexOf(ampm[amindex], 0, Qt::CaseInsensitive) == 0) { + str = ampm[amindex]; + return AM; + } else if (str.indexOf(ampm[pmindex], 0, Qt::CaseInsensitive) == 0) { + str = ampm[pmindex]; + return PM; + } else if (str.count(space) == 0) { + return Neither; } - tw = w - dw; - de->setGeometry( 0, 0, dw, h ); - te->setGeometry( dw, 0, tw, h ); + bool broken[2] = {false, false}; + for (int i=0; iminimumSizeHint(); - QSize tsh = te->minimumSizeHint(); - return QSize( dsh.width() + tsh.width(), - QMAX( dsh.height(), tsh.height() ) ); -} + switch (s) { + // Time. unit is msec + case MSecSection: return 999; + case SecondSection: return 59 * 1000; + case MinuteSection: return 59 * 60 * 1000; + case HourSection: return 59 * 60 * 60 * 1000; -/*! \internal - */ + // Date. unit is day + case DaySection: return 30; + case MonthShortNameSection: + case MonthSection: return 365 - 31; + case YearSection: return (7999 - 1753) * 365; + case YearTwoDigitsSection: return 100 * 365; -void ExtDateTimeEdit::init() -{ - d = new ExtDateTimeEditPrivate(); - de = new ExtDateEdit( this, "qt_datetime_dateedit" ); - te = new Q3TimeEdit( this, "qt_datetime_timeedit" ); - d->adv = FALSE; - connect( de, SIGNAL( valueChanged( const ExtDate& ) ), - this, SLOT( newValue( const ExtDate& ) ) ); - connect( te, SIGNAL( valueChanged( const QTime& ) ), - this, SLOT( newValue( const QTime& ) ) ); - setFocusProxy( de ); - setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ); + default: break; + } + qFatal("%s passed to maxChange. This should never happen", sectionName(s).toLatin1().constData()); + return -1; } -/*! \reimp - */ -QSize ExtDateTimeEdit::sizeHint() const +int ExtDateTimeEditPrivate::multiplier(ExtDateTimeEditPrivate::Section s) const { - constPolish(); - QSize dsh = de->sizeHint(); - QSize tsh = te->sizeHint(); - return QSize( dsh.width() + tsh.width(), - QMAX( dsh.height(), tsh.height() ) ); + switch (s) { + // Time. unit is msec + case MSecSection: return 1; + case SecondSection: return 1000; + case MinuteSection: return 60 * 1000; + case HourSection: return 60 * 60 * 1000; + + // Date. unit is day + case DaySection: return 1; + case MonthShortNameSection: + case MonthSection: return 30; + case YearSection: return 365; + case YearTwoDigitsSection: return 365; + + default: break; + } + qFatal("%s passed to multiplier. This should never happen", sectionName(s).toLatin1().constData()); + return -1; } /*! - \property ExtDateTimeEdit::dateTime - \brief the editor's datetime value + \internal Get a number that str can become which is between min + and max or -1 if this is not possible. +*/ + +QString ExtDateTimeEditPrivate::sectionFormat(int s) const +{ + switch (s) { + case AmPmSection: return QLatin1String("AP"); + case MSecSection: return QLatin1String("zzz"); + case SecondSection: return QLatin1String("ss"); + case MinuteSection: return QLatin1String("mm"); + case HourSection: return QLatin1String("hh"); + case AmPmLowerCaseSection: return QLatin1String("ap"); + case DaySection: return QLatin1String("dd"); + case MonthSection: return QLatin1String("MM"); + case YearSection: return QLatin1String("yyyy"); + case MonthShortNameSection: return QLatin1String("MMM"); + case YearTwoDigitsSection: return QLatin1String("yy"); + default: break; + } + qFatal("%s passed to sectionFormat. This should never happen", sectionName(s).toLatin1().constData()); + return QString(); +} - The datetime edit's datetime which may be an invalid datetime. +/*! + \internal Get a number that str can become which is between min + and max or -1 if this is not possible. */ -void ExtDateTimeEdit::setDateTime( const ExtDateTime & dt ) +int ExtDateTimeEditPrivate::potentialValue(const QString &str, int min, int max, Section s) const { - if ( dt.isValid() ) { - de->setDate( dt.date() ); - te->setTime( dt.time() ); - emit valueChanged( dt ); + int size = sectionSize(s); + if (s == YearTwoDigitsSection) { + min -= 2000; + max -= 2000; // doesn't matter if max is -1 checking for < 0 + } + QString simplified = str.simplified(); + Q_ASSERT(str != simplified); + if (simplified.isEmpty()) { + return min + (s == YearTwoDigitsSection ? 2000 : 0); + } else if (simplified.toInt() > max && max >= 0) { + return -1; + } else { + QString temp = simplified; + while (temp.size() < size) + temp.prepend(QLatin1Char('9')); + int t = temp.toInt(); + if (t < min) { + return -1; + } else if (t <= max || max < 0) { + return t + (s == YearTwoDigitsSection ? 2000 : 0); + } } -} -ExtDateTime ExtDateTimeEdit::dateTime() const -{ - return ExtDateTime( de->date(), te->time() ); + int ret = potentialValueHelper(simplified, min, max, size); + if (ret == -1) + return -1; + return ret + (s == YearTwoDigitsSection ? 2000 : 0); } /*! - \fn void ExtDateTimeEdit::valueChanged( const ExtDateTime& datetime ) - - This signal is emitted every time the date or time changes. The \a - datetime argument is the new datetime. + \internal internal helper function called by potentialValue */ - -/*! \internal - - Re-emits the value \a d. - */ - -void ExtDateTimeEdit::newValue( const ExtDate& ) +int ExtDateTimeEditPrivate::potentialValueHelper(const QString &str, int min, int max, int size) const { - ExtDateTime dt = dateTime(); - emit valueChanged( dt ); -} - -/*! \internal - \overload - Re-emits the value \a t. - */ + if (str.size() == size) { + const int val = str.toInt(); + if (val < min || val > max) + return -1; + EDTEDEBUG << "SUCCESS" << val << "is >=" << min << "and <=" << max; + return val; + } -void ExtDateTimeEdit::newValue( const QTime& ) -{ - ExtDateTime dt = dateTime(); - emit valueChanged( dt ); + for (int i=0; i<=str.size(); ++i) { + for (int j=0; j<10; ++j) { + QString tmp = str; + if (i == str.size()) { + tmp.append(QChar('0' + j)); + } else { + tmp.insert(i, QChar('0' + j)); + } + int ret = potentialValueHelper(tmp, min, max, size); + if (ret != -1) + return ret; + } + } + return -1; } - /*! - 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. + \internal + \reimp */ -void ExtDateTimeEdit::setAutoAdvance( bool advance ) +QString ExtDateTimeEditPrivate::textFromValue(const QVariant &f) const { - de->setAutoAdvance( advance ); - te->setAutoAdvance( advance ); + Q_Q(const ExtDateTimeEdit); + return q->textFromDateTime(f.toDateTime()); } /*! - Returns TRUE if auto-advance is enabled, otherwise returns FALSE. - - \sa setAutoAdvance() + \internal + \reimp */ -bool ExtDateTimeEdit::autoAdvance() const +QVariant ExtDateTimeEditPrivate::valueFromText(const QString &f) const { - return de->autoAdvance(); + Q_Q(const ExtDateTimeEdit); + return QVariant(q->dateTimeFromText(f)); } /*! - \fn ExtDateEdit* ExtDateTimeEdit::dateEdit() - - Returns the internal widget used for editing the date part of the - datetime. -*/ + \internal Returns whether \a str is a string which value cannot be + parsed but still might turn into something valid. +*/ + +QValidator::State ExtDateTimeEditPrivate::checkIntermediate(const ExtDateTime &dt, + const QString &s) const +{ + const char space = ' '; + + Q_ASSERT(dt < minimum); + + bool found = false; + for (int i=0; i= minimum && copy <= maximum) + break; + } + if (tmp == -1) + return QValidator::Invalid; + } + case AmPmSection: + case AmPmLowerCaseSection: + if (t.count(space) == 2 || t.contains('m')) { + const QVariant copy(dt.addSecs(12 * 60 * 60)); + if (copy >= minimum && copy <= maximum) + break; + } + return QValidator::Invalid; + default: { + int toMin; + int toMax; + int multi = multiplier(sn.section); + + if (sn.section & TimeSectionMask) { + if (dt.daysTo(minimum.toDateTime()) != 0) { + EDTEDEBUG << "if (dt.daysTo(minimum.toDateTime()) != 0)" << dt.daysTo(minimum.toDateTime()); + return QValidator::Invalid; + } + toMin = dt.time().msecsTo(minimum.toDateTime().time()); + if (dt.daysTo(maximum.toDateTime()) > 0) { + toMax = -1; // can't get to max + } else { + toMax = dt.time().msecsTo(maximum.toDateTime().time()); + } + } else { + toMin = dt.daysTo(minimum.toDateTime()); + toMax = dt.daysTo(maximum.toDateTime()); + } + int maxChange = ExtDateTimeEditPrivate::maxChange(sn.section); + int maxChangeUnits = maxChange * multi; + if (toMin > maxChangeUnits) { + EDTEDEBUG << "invalid because toMin > maxChangeUnits" << toMin + << maxChangeUnits << t << dt << minimum.toDateTime() + << multi; + + return QValidator::Invalid; + } else if (toMax > maxChangeUnits) { + toMax = -1; // can't get to max + } + + int min = getDigit(minimum, sn.section); + int max = toMax != -1 ? getDigit(maximum, sn.section) : -1; + int tmp = potentialValue(t, min, max, sn.section); + EDTEDEBUG << tmp << t << min << max << sectionName(sn.section) << minimum.toDate() << maximum.toDate(); + if (tmp == -1) { + EDTEDEBUG << "invalid because potentialValue(" << t << min << max + << sectionName(sn.section) << "returned" << tmp; + return QValidator::Invalid; + } + + QVariant var(dt); + setDigit(var, sn.section, tmp); + if (var > maximum) { + EDTEDEBUG << "invalid because" << var.toString() << ">" << maximum.toString(); + return QValidator::Invalid; + } + break; } + } + } + } + return found ? QValidator::Intermediate : QValidator::Invalid; +} /*! - \fn QTimeEdit* ExtDateTimeEdit::timeEdit() + \internal + For debugging. Returns the name of the section \a s. +*/ + +QString ExtDateTimeEditPrivate::sectionName(int s) const +{ + switch (s) { + case ExtDateTimeEditPrivate::AmPmSection: return "AmPmSection"; + case ExtDateTimeEditPrivate::AmPmLowerCaseSection: return "AmPmLowerCaseSection"; + case ExtDateTimeEditPrivate::DaySection: return "DaySection"; + case ExtDateTimeEditPrivate::HourSection: return "HourSection"; + case ExtDateTimeEditPrivate::MSecSection: return "MSecSection"; + case ExtDateTimeEditPrivate::MinuteSection: return "MinuteSection"; + case ExtDateTimeEditPrivate::MonthSection: return "MonthSection"; + case ExtDateTimeEditPrivate::MonthShortNameSection: return "MonthShortNameSection"; + case ExtDateTimeEditPrivate::SecondSection: return "SecondSection"; + case ExtDateTimeEditPrivate::YearSection: return "YearSection"; + case ExtDateTimeEditPrivate::YearTwoDigitsSection: return "YearTwoDigitsSection"; + case ExtDateTimeEditPrivate::NoSection: return "NoSection"; + case ExtDateTimeEditPrivate::FirstSection: return "FirstSection"; + case ExtDateTimeEditPrivate::LastSection: return "LastSection"; + default: return "Unknown section " + QString::number(s); + } +} - Returns the internal widget used for editing the time part of the - datetime. +/*! + \internal + For debugging. Returns the name of the state \a s. */ +QString ExtDateTimeEditPrivate::stateName(int s) const +{ + switch (s) { + case QValidator::Invalid: return "Invalid"; + case QValidator::Intermediate: return "Intermediate"; + case QValidator::Acceptable: return "Acceptable"; + default: return "Unknown state " + QString::number(s); + } +} + #include "extdatetimeedit.moc" -#endif +#endif // QT_NO_DATETIMEEDIT + +#endif //0 diff --git a/extdate/extdatetimeedit.h b/extdate/extdatetimeedit.h index c636356..3717157 100644 --- a/extdate/extdatetimeedit.h +++ b/extdate/extdatetimeedit.h @@ -1,347 +1,171 @@ +/***** --==>> Commenting out entire class. +See extdatetimeedit.cpp for details. +******/ + +#if 0 +--- COMMENTING OUT ENTIRE CLASS --- + /**************************************************************************** ** +** Copyright (C) 1992-2005 Trolltech AS. All rights reserved. ** -** Definition of date and time edit classes -** -** Created : 001103 -** -** Original QDateTimeEdit Copyright (C) 2000 Trolltech AS. All rights reserved. +** This file is part of the QtGui module of the Qt Toolkit. ** -** >> modifications to introduce ExtDate (C) 2004 Jason Harris -** >> ExtDate modifications are licensed under the GPL: http://www.gnu.org/licenses/gpl.html +** This file may be used under the terms of the GNU General Public +** License version 2.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 GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html ** -** This file may be distributed and/or modified under the terms of the -** GNU General Public License version 2 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** -** See http://www.trolltech.com/gpl/ for GPL licensing information. -** -**********************************************************************/ +****************************************************************************/ #ifndef EXTDATETIMEEDIT_H #define EXTDATETIMEEDIT_H -#ifndef QT_H -#include -#include -#endif // QT_H - #include "extdatetime.h" -//Added by qt3to4: -#include -#include -#include -#include -#include +#include -#ifndef QT_NO_DATETIMEEDIT +//JH: Comnmented out +//QT_MODULE(Gui) -class Q3TimeEdit; +#ifndef QT_NO_DATETIMEEDIT -class ExtDateTimeEditBase : public QWidget +class ExtDateTimeEditPrivate; +class ExtDateTimeEdit : public QAbstractSpinBox { Q_OBJECT -public: - ExtDateTimeEditBase( QWidget* parent=0, const char* name=0 ) - : QWidget( parent, name ) {} - virtual bool setFocusSection( int sec ) = 0; - virtual QString sectionFormattedText( int sec ) = 0; - virtual void addNumber( int sec, int num ) = 0; - virtual void removeLastNumber( int sec ) = 0; - -public slots: - virtual void stepUp() = 0; - virtual void stepDown() = 0; - -private: -#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator= - ExtDateTimeEditBase( const ExtDateTimeEditBase & ); - ExtDateTimeEditBase &operator=( const ExtDateTimeEditBase & ); -#endif -}; - -class ExtDateEditPrivate; - -class KDE_EXPORT ExtDateEdit : public ExtDateTimeEditBase -{ - Q_OBJECT - Q_ENUMS( Order ) - Q_PROPERTY( Order order READ order WRITE setOrder ) -// Q_PROPERTY( ExtDate date READ date WRITE setDate ) - Q_PROPERTY( bool autoAdvance READ autoAdvance WRITE setAutoAdvance ) -// Q_PROPERTY( ExtDate maxValue READ maxValue WRITE setMaxValue ) -// Q_PROPERTY( ExtDate minValue READ minValue WRITE setMinValue ) +/* JH: commenting out designer macros + Q_ENUMS(Section) + Q_FLAGS(Sections) + Q_PROPERTY(QDateTime dateTime READ dateTime WRITE setDateTime NOTIFY dateTimeChanged) + Q_PROPERTY(QDate date READ date WRITE setDate NOTIFY dateChanged) + Q_PROPERTY(QTime time READ time WRITE setTime NOTIFY timeChangedu) + Q_PROPERTY(QDate maximumDate READ maximumDate WRITE setMaximumDate RESET clearMaximumDate) + Q_PROPERTY(QDate minimumDate READ minimumDate WRITE setMinimumDate RESET clearMinimumDate) + Q_PROPERTY(QTime maximumTime READ maximumTime WRITE setMaximumTime RESET clearMaximumTime) + Q_PROPERTY(QTime minimumTime READ minimumTime WRITE setMinimumTime RESET clearMinimumTime) + Q_PROPERTY(Section currentSection READ currentSection WRITE setCurrentSection) + Q_PROPERTY(Sections displayedSections READ displayedSections) + Q_PROPERTY(QString displayFormat READ displayFormat WRITE setDisplayFormat) +*/ public: - ExtDateEdit( QWidget* parent=0, const char* name=0 ); - ExtDateEdit( const ExtDate& date, QWidget* parent=0, const char* name=0 ); - ~ExtDateEdit(); - - enum Order { DMY /**< Day-Month-Year */, - MDY /**< Month-Day-Year */, - YMD /**< Year-Month-Day, also the default */, - YDM /**< Year-Day-Month @deprecated Included for completeness. */ }; + enum Section { + NoSection = 0x0000, + AmPmSection = 0x0001, + MSecSection = 0x0002, + SecondSection = 0x0004, + MinuteSection = 0x0008, + HourSection = 0x0010, + DaySection = 0x0100, + MonthSection = 0x0200, + YearSection = 0x0400, + TimeSections_Mask = AmPmSection|MSecSection|SecondSection|MinuteSection|HourSection, + DateSections_Mask = DaySection|MonthSection|YearSection + }; + + Q_DECLARE_FLAGS(Sections, Section) + + explicit ExtDateTimeEdit(QWidget *parent = 0); + explicit ExtDateTimeEdit(const ExtDateTime &dt, QWidget *parent = 0); + explicit ExtDateTimeEdit(const ExtDate &d, QWidget *parent = 0); + explicit ExtDateTimeEdit(const QTime &t, QWidget *parent = 0); - QSize sizeHint() const; - QSize minimumSizeHint() const; - -public slots: - virtual void setDate( const ExtDate& date ); - -public: + ExtDateTime dateTime() const; ExtDate date() const; - virtual void setOrder( Order order ); - Order order() const; - virtual void setAutoAdvance( bool advance ); - bool autoAdvance() const; - - virtual void setMinValue( const ExtDate& d ) { setRange( d, maxValue() ); } - ExtDate minValue() const; - virtual void setMaxValue( const ExtDate& d ) { setRange( minValue(), d ); } - ExtDate maxValue() const; - virtual void setRange( const ExtDate& min, const ExtDate& max ); - QString separator() const; - virtual void setSeparator( const QString& s ); - - // Make removeFirstNumber() virtual in ExtDateTimeEditBase in 4.0 - void removeFirstNumber( int sec ); - -signals: - void valueChanged( const ExtDate& date ); + QTime time() const; -protected: - bool event( QEvent *e ); - void timerEvent( QTimerEvent * ); - void resizeEvent( QResizeEvent * ); - void stepUp(); - void stepDown(); - QString sectionFormattedText( int sec ); - void addNumber( int sec, int num ); - - void removeLastNumber( int sec ); - bool setFocusSection( int s ); - - virtual void setYear( int year ); - virtual void setMonth( int month ); - virtual void setDay( int day ); - virtual void fix(); - virtual bool outOfRange( int y, int m, int d ) const; - -protected slots: - void updateButtons(); + ExtDate minimumDate() const; + void setMinimumDate(const ExtDate &min); + void clearMinimumDate(); -private: - void init(); - int sectionOffsetEnd( int sec ) const; - int sectionLength( int sec ) const; - QString sectionText( int sec ) const; - ExtDateEditPrivate* d; - -#if defined(Q_DISABLE_COPY) - ExtDateEdit( const ExtDateEdit & ); - ExtDateEdit &operator=( const ExtDateEdit & ); -#endif -}; + ExtDate maximumDate() const; + void setMaximumDate(const ExtDate &max); + void clearMaximumDate(); -// class QTimeEditPrivate; -// -// class Q_EXPORT QTimeEdit : public ExtDateTimeEditBase -// { -// Q_OBJECT -// Q_SETS( Display ) -// Q_PROPERTY( QTime time READ time WRITE setTime ) -// Q_PROPERTY( bool autoAdvance READ autoAdvance WRITE setAutoAdvance ) -// Q_PROPERTY( QTime maxValue READ maxValue WRITE setMaxValue ) -// Q_PROPERTY( QTime minValue READ minValue WRITE setMinValue ) -// Q_PROPERTY( Display display READ display WRITE setDisplay ) -// -// public: -// enum Display { -// Hours = 0x01, -// Minutes = 0x02, -// Seconds = 0x04, -// /*Reserved = 0x08,*/ -// AMPM = 0x10 -// }; -// -// QTimeEdit( QWidget* parent=0, const char* name=0 ); -// QTimeEdit( const QTime& time, QWidget* parent=0, const char* name=0 ); -// ~QTimeEdit(); -// -// QSize sizeHint() const; -// QSize minimumSizeHint() const; -// -// public slots: -// virtual void setTime( const QTime& time ); -// -// public: -// QTime time() const; -// virtual void setAutoAdvance( bool advance ); -// bool autoAdvance() const; -// -// virtual void setMinValue( const QTime& d ) { setRange( d, maxValue() ); } -// QTime minValue() const; -// virtual void setMaxValue( const QTime& d ) { setRange( minValue(), d ); } -// QTime maxValue() const; -// virtual void setRange( const QTime& min, const QTime& max ); -// QString separator() const; -// virtual void setSeparator( const QString& s ); -// -// uint display() const; -// void setDisplay( uint disp ); -// -// // Make removeFirstNumber() virtual in ExtDateTimeEditBase in 4.0 -// void removeFirstNumber( int sec ); -// -// signals: -// void valueChanged( const QTime& time ); -// -// protected: -// bool event( QEvent *e ); -// void timerEvent( QTimerEvent *e ); -// void resizeEvent( QResizeEvent * ); -// void stepUp(); -// void stepDown(); -// QString sectionFormattedText( int sec ); -// void addNumber( int sec, int num ); -// void removeLastNumber( int sec ); -// bool setFocusSection( int s ); -// -// virtual bool outOfRange( int h, int m, int s ) const; -// virtual void setHour( int h ); -// virtual void setMinute( int m ); -// virtual void setSecond( int s ); -// -// protected slots: -// void updateButtons(); -// -// private: -// void init(); -// QString sectionText( int sec ); -// QTimeEditPrivate* d; -// -// #if defined(Q_DISABLE_COPY) -// QTimeEdit( const QTimeEdit & ); -// QTimeEdit &operator=( const QTimeEdit & ); -// #endif -// }; -// + void setDateRange(const ExtDate &min, const ExtDate &max); -class ExtDateTimeEditPrivate; + QTime minimumTime() const; + void setMinimumTime(const QTime &min); + void clearMinimumTime(); -class KDE_EXPORT ExtDateTimeEdit : public QWidget -{ - Q_OBJECT -// Q_PROPERTY( ExtDateTime dateTime READ dateTime WRITE setDateTime ) + QTime maximumTime() const; + void setMaximumTime(const QTime &max); + void clearMaximumTime(); -public: - ExtDateTimeEdit( QWidget* parent=0, const char* name=0 ); - ExtDateTimeEdit( const ExtDateTime& datetime, QWidget* parent=0, - const char* name=0 ); - ~ExtDateTimeEdit(); + void setTimeRange(const QTime &min, const QTime &max); - QSize sizeHint() const; - QSize minimumSizeHint() const; + Sections displayedSections() const; + Section currentSection() const; + void setCurrentSection(Section section); -public slots: - virtual void setDateTime( const ExtDateTime & dt ); + QString sectionText(Section s) const; -public: - ExtDateTime dateTime() const; + QString displayFormat() const; + void setDisplayFormat(const QString &format); - ExtDateEdit* dateEdit() { return de; } - Q3TimeEdit* timeEdit() { return te; } + QSize sizeHint() const; - virtual void setAutoAdvance( bool advance ); - bool autoAdvance() const; + virtual void clear(); + virtual void stepBy(int steps); + bool event(QEvent *e); signals: - void valueChanged( const ExtDateTime& datetime ); + void dateTimeChanged(const ExtDateTime &date); + void timeChanged(const QTime &date); + void dateChanged(const ExtDate &date); -protected: - // ### make init() private in Qt 4.0 - void init(); - void resizeEvent( QResizeEvent * ); - -protected slots: - // ### make these two functions private in Qt 4.0, - // and merge them into one with no parameter - void newValue( const ExtDate& d ); - void newValue( const QTime& t ); +public slots: + void setDateTime(const ExtDateTime &dateTime); + void setDate(const ExtDate &date); + void setTime(const QTime &time); -private: - ExtDateEdit* de; - Q3TimeEdit* te; - ExtDateTimeEditPrivate* d; - -#if defined(Q_DISABLE_COPY) - ExtDateTimeEdit( const ExtDateTimeEdit & ); - ExtDateTimeEdit &operator=( const ExtDateTimeEdit & ); -#endif -}; +protected: + virtual void keyPressEvent(QKeyEvent *e); + virtual void wheelEvent(QWheelEvent *e); + virtual void focusInEvent(QFocusEvent *e); + virtual bool focusNextPrevChild(bool next); + virtual QValidator::State validate(QString &input, int &pos) const; + virtual ExtDateTime dateTimeFromText(const QString &text) const; + virtual QString textFromDateTime(const ExtDateTime &dt) const; + virtual StepEnabled stepEnabled() const; -class 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: - int selstart :12; - int selend :12; - int act :7; - bool sep :1; + Q_DECLARE_PRIVATE(ExtDateTimeEdit) + Q_DISABLE_COPY(ExtDateTimeEdit) }; -class ExtDateTimeEditorPrivate; +//JH: Don't need to re-do QTimeEdit +//class Q_GUI_EXPORT QTimeEdit : public ExtDateTimeEdit +//{ +// Q_OBJECT +//public: +// QTimeEdit(QWidget *parent = 0); +// QTimeEdit(const QTime &t, QWidget *parent = 0); +//}; -class ExtDateTimeEditor : public QWidget +class ExtDateEdit : public ExtDateTimeEdit { Q_OBJECT public: - ExtDateTimeEditor( ExtDateTimeEditBase * parent=0, - const char * name=0 ); - ~ExtDateTimeEditor(); - -// void setControlWidget( ExtDateTimeEditBase * widget ); -// ExtDateTimeEditBase * controlWidget() const; - - void setSeparator( const QString& s ); - QString separator() const; + ExtDateEdit(QWidget *parent = 0); + ExtDateEdit(const ExtDate &t, QWidget *parent = 0); +}; - 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 ); +Q_DECLARE_OPERATORS_FOR_FLAGS(ExtDateTimeEdit::Sections) -protected: - void init(); - bool event( QEvent *e ); - void resizeEvent( QResizeEvent * ); - void paintEvent( QPaintEvent * ); - void mousePressEvent( QMouseEvent *e ); -private: - ExtDateTimeEditBase* cw; - ExtDateTimeEditorPrivate* d; -}; +#endif // QT_NO_DATETIMEEDIT +#endif // EXTDATETIMEEDIT_H -#endif -#endif +#endif //0 diff --git a/extdate/extdatewidget.cpp b/extdate/extdatewidget.cpp index 77ba9ac..238760a 100644 --- a/extdate/extdatewidget.cpp +++ b/extdate/extdatewidget.cpp @@ -20,11 +20,11 @@ */ -#include -#include -#include +#include +//#include //Added by qt3to4: #include +#include #include #include @@ -38,7 +38,7 @@ public: ExtDateWidgetSpinBox(int min, int max, QWidget *parent) : QSpinBox(min, max, 1, parent) { - editor()->setAlignment(AlignRight); + setAlignment(Qt::AlignRight); } }; diff --git a/extdate/test_extdate.cc b/extdate/test_extdate.cc index b21e228..16456df 100644 --- a/extdate/test_extdate.cc +++ b/extdate/test_extdate.cc @@ -53,9 +53,9 @@ void test2_unit(int y, int m, int d) int q_day_of_year = q.dayOfYear(); int e_day_of_year = e.dayOfYear(); std::cout << "(" << y << ", " << m << ", " << d << ") :: " - << q.toString("dd.MMM.yyyy").local8Bit() << " : " + << q.toString("dd.MMM.yyyy").toLocal8Bit().data() << " : " << q.dayOfWeek() << " : " << q_week_number << " : " << q_day_of_year << " :: " - << e.toString("%d.%b.%Y").local8Bit() << " : " + << e.toString("%d.%b.%Y").toLocal8Bit().data() << " : " << e.dayOfWeek() << " : " << e_week_number << " : " << e_day_of_year << std::endl; } @@ -132,9 +132,9 @@ void test3_unit(int y, int m, int d, int dm) ExtDate e(y, m, d); QDate q2 = q.addMonths(dm); ExtDate e2 = e.addMonths(dm); - std::cout << e.toString("%d.%b.%Y").local8Bit() << " + " << dm - << " months :: ExtDate : " << e2.toString("%d.%b.%Y").local8Bit() - << " QDate : " << q2.toString("dd.MMM.yyyy").local8Bit() << std::endl; + std::cout << e.toString("%d.%b.%Y").toLocal8Bit().data() << " + " << dm + << " months :: ExtDate : " << e2.toString("%d.%b.%Y").toLocal8Bit().data() + << " QDate : " << q2.toString("dd.MMM.yyyy").toLocal8Bit().data() << std::endl; } void test3() @@ -161,9 +161,9 @@ void test4_unit(int y, int m, int d, int dy) ExtDate e(y, m, d); QDate q2 = q.addYears(dy); ExtDate e2 = e.addYears(dy); - std::cout << e.toString("%d.%m.%Y").local8Bit() << " + " << dy << " years :: ExtDate : " - << e2.toString().local8Bit() << " QDate : " - << q2.toString().local8Bit() << std::endl; + std::cout << e.toString("%d.%m.%Y").toLocal8Bit().data() << " + " << dy << " years :: ExtDate : " + << e2.toString().toLocal8Bit().data() << " QDate : " + << q2.toString().toLocal8Bit().data() << std::endl; } void test4() @@ -193,11 +193,11 @@ void test5_unit(int y, int m, int d, const char *qformat, const char *eformat) ExtDate e(y, m, d); if ( QString(qformat) == "" ) - std::cout << eformat << " : " << e.toString().local8Bit() << " :: " - << qformat << " : " << q.toString().local8Bit() << std::endl; + std::cout << eformat << " : " << e.toString().toLocal8Bit().data() << " :: " + << qformat << " : " << q.toString().toLocal8Bit().data() << std::endl; else - std::cout << eformat << " : " << e.toString(eformat).local8Bit() << " :: " - << qformat << " : " << q.toString(qformat).local8Bit() << std::endl; + std::cout << eformat << " : " << e.toString(eformat).toLocal8Bit().data() << " :: " + << qformat << " : " << q.toString(qformat).toLocal8Bit().data() << std::endl; } void test5() @@ -279,16 +279,16 @@ void test7() std::cout << "Express the current date:\n" << std::endl; QDate q = QDate::currentDate(Qt::LocalTime); ExtDate e = ExtDate::currentDate(Qt::TimeSpec(Qt::LocalTime)); - std::cout << "Qt::LocalTime :: ExtDate : " << e.toString().local8Bit() << " QDate : " - << q.toString().local8Bit() << std::endl; + std::cout << "Qt::LocalTime :: ExtDate : " << e.toString().toLocal8Bit().data() << " QDate : " + << q.toString().toLocal8Bit().data() << std::endl; q = QDate::currentDate(Qt::UTC); e = ExtDate::currentDate(Qt::UTC); - std::cout << "Qt::UTC :: ExtDate : " << e.toString().local8Bit() << " QDate : " - << q.toString().local8Bit() << std::endl; + std::cout << "Qt::UTC :: ExtDate : " << e.toString().toLocal8Bit().data() << " QDate : " + << q.toString().toLocal8Bit().data() << std::endl; q = QDate::currentDate(); e = ExtDate::currentDate(); - std::cout << " :: ExtDate : " << e.toString().local8Bit() << " QDate : " - << q.toString().local8Bit() << std::endl; + std::cout << " :: ExtDate : " << e.toString().toLocal8Bit().data() << " QDate : " + << q.toString().toLocal8Bit().data() << std::endl; std::cout << "--------------------" << std::endl; } @@ -301,8 +301,8 @@ void test8() { QDate test1( 2004, m, d ); ExtDate test2( 2004, m, d ); - std::cout << test1.toString( "ddd dd.MMM.yy" ).local8Bit() << " : " - << test2.toString( "%a %d.%b.%y" ).local8Bit() << std::endl; + std::cout << test1.toString( "ddd dd.MMM.yy" ).toLocal8Bit().data() << " : " + << test2.toString( "%a %d.%b.%y" ).toLocal8Bit().data() << std::endl; } } @@ -314,7 +314,7 @@ void test9() { QDateTime q = QDateTime::currentDateTime(); ExtDateTime e = ExtDateTime::currentDateTime(); - std::cout << q.toString().local8Bit() << " : " << e.toString().local8Bit() << std::endl; + std::cout << q.toString().toLocal8Bit().data() << " : " << e.toString().toLocal8Bit().data() << std::endl; std::cout << "--------------------" << std::endl; } -- 2.47.3