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