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   if ( mHandleInvalid || value.isValid() )
00141     return value;
00142   return defaultValue;
00143 }
00144 
00145 QDate KDateEdit::defaultDate() const
00146 {
00147   return defaultValue;
00148 }
00149 
00150 void KDateEdit::setDefaultDate(const QDate& date)
00151 {
00152   defaultValue = date;
00153 }
00154 
00155 void KDateEdit::popup()
00156 {
00157   if (mReadOnly)
00158     return;
00159 
00160   QRect desk = KGlobalSettings::desktopGeometry(this);
00161 
00162   QPoint popupPoint = mapToGlobal( QPoint( 0,0 ) );
00163 
00164   int dateFrameHeight = mDateFrame->sizeHint().height();
00165   if ( popupPoint.y() + height() + dateFrameHeight > desk.bottom() ) {
00166     popupPoint.setY( popupPoint.y() - dateFrameHeight );
00167   } else {
00168     popupPoint.setY( popupPoint.y() + height() );
00169   }
00170   int dateFrameWidth = mDateFrame->sizeHint().width();
00171   if ( popupPoint.x() + dateFrameWidth > desk.right() ) {
00172     popupPoint.setX( desk.right() - dateFrameWidth );
00173   }
00174 
00175   if ( popupPoint.x() < desk.left() ) popupPoint.setX( desk.left() );
00176   if ( popupPoint.y() < desk.top() ) popupPoint.setY( desk.top() );
00177 
00178   mDateFrame->move( popupPoint );
00179 
00180   if (value.isValid()) {
00181     mDatePicker->setDate( value );
00182   } else {
00183     mDatePicker->setDate( defaultValue );
00184   }
00185 
00186   mDateFrame->show();
00187 
00188   // The combo box is now shown pressed. Make it show not pressed again
00189   // by causing its (invisible) list box to emit a 'selected' signal.
00190   QListBox *lb = listBox();
00191   if (lb) {
00192     lb->setCurrentItem(0);
00193     QKeyEvent* keyEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_Enter, 0, 0);
00194     QApplication::postEvent(lb, keyEvent);
00195   }
00196 }
00197 
00198 void KDateEdit::dateSelected(QDate newDate)
00199 {
00200   if ((mHandleInvalid || newDate.isValid()) && validate(newDate)) {
00201     setDate(newDate);
00202     emit dateChanged(newDate);
00203     mDateFrame->hide();
00204   }
00205 }
00206 
00207 void KDateEdit::dateEntered(QDate newDate)
00208 {
00209   if ((mHandleInvalid || newDate.isValid()) && validate(newDate)) {
00210     setDate(newDate);
00211     emit dateChanged(newDate);
00212   }
00213 }
00214 
00215 void KDateEdit::lineEnterPressed()
00216 {
00217   QDate date;
00218   if (readDate(date) && (mHandleInvalid || date.isValid()) && validate(date))
00219   {
00220     // Update the edit. This is needed if the user has entered a
00221     // word rather than the actual date.
00222     setDate(date);
00223     emit(dateChanged(date));
00224   }
00225   else {
00226     // Invalid or unacceptable date - revert to previous value
00227     KNotifyClient::beep();
00228     setDate(value);
00229     emit invalidDateEntered();
00230   }
00231 }
00232 
00233 bool KDateEdit::inputIsValid() const
00234 {
00235   QDate date;
00236   return readDate(date) && date.isValid();
00237 }
00238 
00239 /* Reads the text from the line edit. If the text is a keyword, the
00240  * word will be translated to a date. If the text is not a keyword, the
00241  * text will be interpreted as a date.
00242  * Returns true if the date text is blank or valid, false otherwise.
00243  */
00244 bool KDateEdit::readDate(QDate& result) const
00245 {
00246   QString text = currentText();
00247 
00248   if (text.isEmpty()) {
00249     result = QDate();
00250   }
00251   else if (mKeywordMap.contains(text.lower()))
00252   {
00253     QDate today = QDate::currentDate();
00254     int i = mKeywordMap[text.lower()];
00255     if (i >= 100)
00256     {
00257       /* A day name has been entered. Convert to offset from today.
00258        * This uses some math tricks to figure out the offset in days
00259        * to the next date the given day of the week occurs. There
00260        * are two cases, that the new day is >= the current day, which means
00261        * the new day has not occurred yet or that the new day < the current day,
00262        * which means the new day is already passed (so we need to find the
00263        * day in the next week).
00264        */
00265       i -= 100;
00266       int currentDay = today.dayOfWeek();
00267       if (i >= currentDay)
00268         i -= currentDay;
00269       else
00270         i += 7 - currentDay;
00271     }
00272     result = today.addDays(i);
00273   }
00274   else
00275   {
00276     result = KGlobal::locale()->readDate(text);
00277     return result.isValid();
00278   }
00279 
00280   return true;
00281 }
00282 
00283 /* Checks for a focus out event. The display of the date is updated
00284  * to display the proper date when the focus leaves.
00285  */
00286 bool KDateEdit::eventFilter(QObject *obj, QEvent *e)
00287 {
00288   if (obj == lineEdit()) {
00289     // We only process the focus out event if the text has changed
00290     // since we got focus
00291     if ((e->type() == QEvent::FocusOut) && mTextChanged)
00292     {
00293       lineEnterPressed();
00294       mTextChanged = false;
00295     }
00296     else if (e->type() == QEvent::KeyPress)
00297     {
00298       // Up and down arrow keys step the date
00299       QKeyEvent* ke = (QKeyEvent*)e;
00300 
00301       if (ke->key() == Qt::Key_Return)
00302       {
00303         lineEnterPressed();
00304         return true;
00305       }
00306 
00307       int step = 0;
00308       if (ke->key() == Qt::Key_Up)
00309         step = 1;
00310       else if (ke->key() == Qt::Key_Down)
00311         step = -1;
00312       if (step && !mReadOnly)
00313       {
00314         QDate date;
00315         if (readDate(date) && date.isValid()) {
00316           date = date.addDays(step);
00317           if (validate(date)) {
00318             setDate(date);
00319             emit(dateChanged(date));
00320             return true;
00321           }
00322         }
00323       }
00324     }
00325   }
00326   else {
00327     // It's a date picker event
00328     switch (e->type()) {
00329       case QEvent::MouseButtonDblClick:
00330       case QEvent::MouseButtonPress: {
00331         QMouseEvent *me = (QMouseEvent*)e;
00332         if (!mDateFrame->rect().contains(me->pos())) {
00333           QPoint globalPos = mDateFrame->mapToGlobal(me->pos());
00334           if (QApplication::widgetAt(globalPos, true) == this) {
00335             // The date picker is being closed by a click on the
00336             // KDateEdit widget. Avoid popping it up again immediately.
00337             mDiscardNextMousePress = true;
00338           }
00339         }
00340         break;
00341       }
00342       default:
00343         break;
00344     }
00345   }
00346 
00347   return false;
00348 }
00349 
00350 void KDateEdit::mousePressEvent(QMouseEvent *e)
00351 {
00352   if (e->button() == Qt::LeftButton  &&  mDiscardNextMousePress) {
00353     mDiscardNextMousePress = false;
00354     return;
00355   }
00356   QComboBox::mousePressEvent(e);
00357 }
00358 
00359 void KDateEdit::slotTextChanged(const QString &)
00360 {
00361   mTextChanged = true;
00362 }
KDE Logo
This file is part of the documentation for libkdepim Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jan 31 15:53:22 2007 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003