libkdepim Library API Documentation

kdateedit.cpp

00001 /*
00002     This file is part of libkdepim.
00003 
00004     Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Library General Public License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to
00018     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019     Boston, MA 02111-1307, USA.
00020 */
00021 
00022 #include <qevent.h>
00023 #include <qlineedit.h>
00024 #include <qapplication.h>
00025 #include <qlistbox.h>
00026 
00027 #include <kdatepicker.h>
00028 #include <knotifyclient.h>
00029 #include <kglobalsettings.h>
00030 #include <kdebug.h>
00031 #include <kglobal.h>
00032 #include <klocale.h>
00033 #include <kcalendarsystem.h>
00034 
00035 #include "kdateedit.h"
00036 #include "kdateedit.moc"
00037 
00038 
00039 KDateEdit::KDateEdit(QWidget *parent, const char *name)
00040   : QComboBox(true, parent, name),
00041     defaultValue(QDate::currentDate()),
00042     mReadOnly(false),
00043     mDiscardNextMousePress(false)
00044 {
00045   setMaxCount(1);       // need at least one entry for popup to work
00046   value = defaultValue;
00047   QString today = KGlobal::locale()->formatDate(value, true);
00048   insertItem(today);
00049   setCurrentItem(0);
00050   changeItem(today, 0);
00051   setMinimumSize(sizeHint());
00052 
00053   mDateFrame = new QVBox(0,0,WType_Popup);
00054   mDateFrame->setFrameStyle(QFrame::PopupPanel | QFrame::Raised);
00055   mDateFrame->setLineWidth(3);
00056   mDateFrame->hide();
00057   mDateFrame->installEventFilter(this);
00058 
00059   mDatePicker = new KDatePicker(mDateFrame, value);
00060 
00061   connect(lineEdit(),SIGNAL(returnPressed()),SLOT(lineEnterPressed()));
00062   connect(this,SIGNAL(textChanged(const QString &)),
00063           SLOT(slotTextChanged(const QString &)));
00064 
00065   connect(mDatePicker,SIGNAL(dateEntered(QDate)),SLOT(dateEntered(QDate)));
00066   connect(mDatePicker,SIGNAL(dateSelected(QDate)),SLOT(dateSelected(QDate)));
00067 
00068   // Create the keyword list. This will be used to match against when the user
00069   // enters information.
00070   mKeywordMap[i18n("tomorrow")] = 1;
00071   mKeywordMap[i18n("today")] = 0;
00072   mKeywordMap[i18n("yesterday")] = -1;
00073 
00074   QString dayName;
00075   for (int i = 1; i <= 7; ++i)
00076   {
00077     dayName = KGlobal::locale()->calendar()->weekDayName(i).lower();
00078     mKeywordMap[dayName] = i + 100;
00079   }
00080   lineEdit()->installEventFilter(this);   // handle keyword entry
00081 
00082   mTextChanged = false;
00083   mHandleInvalid = false;
00084 }
00085 
00086 KDateEdit::~KDateEdit()
00087 {
00088   delete mDateFrame;
00089 }
00090 
00091 void KDateEdit::setDate(const QDate& newDate)
00092 {
00093   if (!newDate.isValid() && !mHandleInvalid)
00094     return;
00095 
00096   QString dateString = "";
00097   if(newDate.isValid())
00098     dateString = KGlobal::locale()->formatDate( newDate, true );
00099 
00100   mTextChanged = false;
00101 
00102   // We do not want to generate a signal here, since we explicitly setting
00103   // the date
00104   bool b = signalsBlocked();
00105   blockSignals(true);
00106   changeItem(dateString, 0);
00107   blockSignals(b);
00108 
00109   value = newDate;
00110 }
00111 
00112 void KDateEdit::setHandleInvalid(bool handleInvalid)
00113 {
00114   mHandleInvalid = handleInvalid;
00115 }
00116 
00117 bool KDateEdit::handlesInvalid() const
00118 {
00119   return mHandleInvalid;
00120 }
00121 
00122 void KDateEdit::setReadOnly(bool readOnly)
00123 {
00124   mReadOnly = readOnly;
00125   lineEdit()->setReadOnly(readOnly);
00126 }
00127 
00128 bool KDateEdit::isReadOnly() const
00129 {
00130   return mReadOnly;
00131 }
00132 
00133 bool KDateEdit::validate( const QDate & )
00134 {
00135   return true;
00136 }
00137 
00138 QDate KDateEdit::date() const
00139 {
00140   QDate dt;
00141   if (readDate(dt) && (mHandleInvalid || dt.isValid())) {
00142     return dt;
00143   }
00144   return defaultValue;
00145 }
00146 
00147 QDate KDateEdit::defaultDate() const
00148 {
00149   return defaultValue;
00150 }
00151 
00152 void KDateEdit::setDefaultDate(const QDate& date)
00153 {
00154   defaultValue = date;
00155 }
00156 
00157 void KDateEdit::popup()
00158 {
00159   if (mReadOnly)
00160     return;
00161 
00162   QRect desk = KGlobalSettings::desktopGeometry(this);
00163 
00164   QPoint popupPoint = mapToGlobal( QPoint( 0,0 ) );
00165   if ( popupPoint.x() < desk.left() ) popupPoint.setX( desk.x() );
00166 
00167   int dateFrameHeight = mDateFrame->sizeHint().height();
00168 
00169   if ( popupPoint.y() + height() + dateFrameHeight > desk.bottom() ) {
00170     popupPoint.setY( popupPoint.y() - dateFrameHeight );
00171   } else {
00172     popupPoint.setY( popupPoint.y() + height() );
00173   }
00174 
00175   mDateFrame->move( popupPoint );
00176 
00177   QDate date;
00178   readDate(date);
00179   if (date.isValid()) {
00180     mDatePicker->setDate( date );
00181   } else {
00182     mDatePicker->setDate( defaultValue );
00183   }
00184 
00185   mDateFrame->show();
00186 
00187   // The combo box is now shown pressed. Make it show not pressed again
00188   // by causing its (invisible) list box to emit a 'selected' signal.
00189   QListBox *lb = listBox();
00190   if (lb) {
00191     lb->setCurrentItem(0);
00192     QKeyEvent* keyEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_Enter, 0, 0);
00193     QApplication::postEvent(lb, keyEvent);
00194   }
00195 }
00196 
00197 void KDateEdit::dateSelected(QDate newDate)
00198 {
00199   if ((mHandleInvalid || newDate.isValid()) && validate(newDate)) {
00200     setDate(newDate);
00201     emit dateChanged(newDate);
00202     mDateFrame->hide();
00203   }
00204 }
00205 
00206 void KDateEdit::dateEntered(QDate newDate)
00207 {
00208   if ((mHandleInvalid || newDate.isValid()) && validate(newDate)) {
00209     setDate(newDate);
00210     emit dateChanged(newDate);
00211   }
00212 }
00213 
00214 void KDateEdit::lineEnterPressed()
00215 {
00216   QDate date;
00217   if (readDate(date) && (mHandleInvalid || date.isValid()) && validate(date))
00218   {
00219     // Update the edit. This is needed if the user has entered a
00220     // word rather than the actual date.
00221     setDate(date);
00222     emit(dateChanged(date));
00223   }
00224   else {
00225     // Invalid or unacceptable date - revert to previous value
00226     KNotifyClient::beep();
00227     setDate(value);
00228     emit invalidDateEntered();
00229   }
00230 }
00231 
00232 bool KDateEdit::inputIsValid() const
00233 {
00234   QDate date;
00235   return readDate(date) && date.isValid();
00236 }
00237 
00238 /* Reads the text from the line edit. If the text is a keyword, the
00239  * word will be translated to a date. If the text is not a keyword, the
00240  * text will be interpreted as a date.
00241  * Returns true if the date text is blank or valid, false otherwise.
00242  */
00243 bool KDateEdit::readDate(QDate& result) const
00244 {
00245   QString text = currentText();
00246 
00247   if (text.isEmpty()) {
00248     result = QDate();
00249   }
00250   else if (mKeywordMap.contains(text.lower()))
00251   {
00252     QDate today = QDate::currentDate();
00253     int i = mKeywordMap[text.lower()];
00254     if (i >= 100)
00255     {
00256       /* A day name has been entered. Convert to offset from today.
00257        * This uses some math tricks to figure out the offset in days
00258        * to the next date the given day of the week occurs. There
00259        * are two cases, that the new day is >= the current day, which means
00260        * the new day has not occurred yet or that the new day < the current day,
00261        * which means the new day is already passed (so we need to find the
00262        * day in the next week).
00263        */
00264       i -= 100;
00265       int currentDay = today.dayOfWeek();
00266       if (i >= currentDay)
00267         i -= currentDay;
00268       else
00269         i += 7 - currentDay;
00270     }
00271     result = today.addDays(i);
00272   }
00273   else
00274   {
00275     result = KGlobal::locale()->readDate(text);
00276     return result.isValid();
00277   }
00278 
00279   return true;
00280 }
00281 
00282 /* Checks for a focus out event. The display of the date is updated
00283  * to display the proper date when the focus leaves.
00284  */
00285 bool KDateEdit::eventFilter(QObject *obj, QEvent *e)
00286 {
00287   if (obj == lineEdit()) {
00288     // We only process the focus out event if the text has changed
00289     // since we got focus
00290     if ((e->type() == QEvent::FocusOut) && mTextChanged)
00291     {
00292       lineEnterPressed();
00293       mTextChanged = false;
00294     }
00295     else if (e->type() == QEvent::KeyPress)
00296     {
00297       // Up and down arrow keys step the date
00298       QKeyEvent* ke = (QKeyEvent*)e;
00299 
00300       if (ke->key() == Qt::Key_Return)
00301       {
00302         lineEnterPressed();
00303         return true;
00304       }
00305 
00306       int step = 0;
00307       if (ke->key() == Qt::Key_Up)
00308         step = 1;
00309       else if (ke->key() == Qt::Key_Down)
00310         step = -1;
00311       if (step && !mReadOnly)
00312       {
00313         QDate date;
00314         if (readDate(date) && date.isValid()) {
00315           date = date.addDays(step);
00316           if (validate(date)) {
00317             setDate(date);
00318             emit(dateChanged(date));
00319             return true;
00320           }
00321         }
00322       }
00323     }
00324   }
00325   else {
00326     // It's a date picker event
00327     switch (e->type()) {
00328       case QEvent::MouseButtonDblClick:
00329       case QEvent::MouseButtonPress: {
00330         QMouseEvent *me = (QMouseEvent*)e;
00331         if (!mDateFrame->rect().contains(me->pos())) {
00332           QPoint globalPos = mDateFrame->mapToGlobal(me->pos());
00333           if (QApplication::widgetAt(globalPos, true) == this) {
00334             // The date picker is being closed by a click on the
00335             // KDateEdit widget. Avoid popping it up again immediately.
00336             mDiscardNextMousePress = true;
00337           }
00338         }
00339         break;
00340       }
00341       default:
00342         break;
00343     }
00344   }
00345 
00346   return false;
00347 }
00348 
00349 void KDateEdit::mousePressEvent(QMouseEvent *e)
00350 {
00351   if (e->button() == Qt::LeftButton  &&  mDiscardNextMousePress) {
00352     mDiscardNextMousePress = false;
00353     return;
00354   }
00355   QComboBox::mousePressEvent(e);
00356 }
00357 
00358 void KDateEdit::slotTextChanged(const QString &)
00359 {
00360   mTextChanged = true;
00361 }
KDE Logo
This file is part of the documentation for libkdepim Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat May 1 11:36:31 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003