libkdepim

ktimeedit.cpp

00001 /*
00002     This file is part of libkdepim.
00003 
00004     Copyright (c) 1999 Preston Brown <pbrown@kde.org>
00005     Copyright (c) 1999 Ian Dawes <iadawes@globalserve.net>
00006     Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00021 
00022     As a special exception, permission is given to link this program
00023     with any edition of Qt, and distribute the resulting executable,
00024     without including the source code for Qt in the source distribution.
00025 */
00026 
00027 #include <qkeycode.h>
00028 #include <qcombobox.h>
00029 #include <qdatetime.h>
00030 #include <qlineedit.h>
00031 
00032 #include <kmessagebox.h>
00033 #include <kglobal.h>
00034 #include <kdebug.h>
00035 #include <klocale.h>
00036 
00037 #include "ktimeedit.h"
00038 #include <qvalidator.h>
00039 #include "ktimeedit.moc"
00040 
00041 // Validator for a time value with only hours and minutes (no seconds)
00042 // Mostly locale aware. Author: David Faure <faure@kde.org>
00043 class KOTimeValidator : public QValidator
00044 {
00045 public:
00046     KOTimeValidator(QWidget* parent, const char* name=0) : QValidator(parent, name) {}
00047 
00048     virtual State validate(QString& str, int& /*cursorPos*/) const
00049     {
00050         int length = str.length();
00051         // empty string is intermediate so one can clear the edit line and start from scratch
00052         if ( length <= 0 )
00053             return Intermediate;
00054 
00055         bool ok = false;
00056         /*QTime time =*/ KGlobal::locale()->readTime(str, KLocale::WithoutSeconds, &ok);
00057         if ( ok )
00058             return Acceptable;
00059 //         kdDebug(5300)<<"Time "<<str<<" not directly acceptable, trying military format "<<endl;
00060         // Also try to accept times in "military format", i.e. no delimiter, like 1200
00061         int tm = str.toInt( &ok );
00062         if ( ok && ( 0 <= tm ) ) {
00063           if ( ( tm < 2400 ) && ( tm%100 < 60 ) )
00064             return Acceptable;
00065           else
00066             return Intermediate;
00067         }
00068 //         kdDebug(5300)<<str<<" not acceptable or intermediate for military format, either "<<str<<endl;
00069 
00070         // readTime doesn't help knowing when the string is "Intermediate".
00071         // HACK. Not fully locale aware etc. (esp. the separator is '.' in sv_SE...)
00072         QChar sep = ':';
00073         // I want to allow "HH:", ":MM" and ":" to make editing easier
00074         if ( str[0] == sep )
00075         {
00076             if ( length == 1 ) // just ":"
00077                 return Intermediate;
00078             QString minutes = str.mid(1);
00079             int m = minutes.toInt(&ok);
00080             if ( ok && m >= 0 && m < 60 )
00081                 return Intermediate;
00082         } else if ( str[str.length()-1] == sep )
00083         {
00084             QString hours = str.left(length-1);
00085             int h = hours.toInt(&ok);
00086             if ( ok && h >= 0 && h < 24 )
00087                 return Intermediate;
00088         }
00089 //        return Invalid;
00090         return Intermediate;
00091     }
00092     virtual void fixup ( QString & input ) const {
00093       bool ok = false;
00094       KGlobal::locale()->readTime( input, KLocale::WithoutSeconds, &ok );
00095       if ( !ok ) {
00096         // Also try to accept times in "military format", i.e. no delimiter, like 1200
00097         int tm = input.toInt( &ok );
00098         if ( ( 0 <= tm ) && ( tm < 2400 ) && ( tm%100 < 60 ) && ok ) {
00099           input = KGlobal::locale()->formatTime( QTime( tm / 100, tm % 100, 0 ) );
00100         }
00101       }
00102     }
00103 };
00104 
00105 // KTimeWidget/QTimeEdit provide nicer editing, but don't provide a combobox.
00106 // Difficult to get all in one...
00107 // But Qt-3.2 will offer QLineEdit::setMask, so a "99:99" mask would help.
00108 KTimeEdit::KTimeEdit( QWidget *parent, QTime qt, const char *name )
00109   : QComboBox( true, parent, name )
00110 {
00111   setInsertionPolicy( NoInsertion );
00112   setValidator( new KOTimeValidator( this ) );
00113 
00114   mTime = qt;
00115 
00116 //  mNoTimeString = i18n("No Time");
00117 //  insertItem( mNoTimeString );
00118 
00119   // Fill combo box with selection of times in localized format.
00120   QTime timeEntry(0,0,0);
00121   do {
00122     insertItem(KGlobal::locale()->formatTime(timeEntry));
00123     timeEntry = timeEntry.addSecs(60*15);
00124   } while (!timeEntry.isNull());
00125   // Add end of day.
00126   insertItem( KGlobal::locale()->formatTime( QTime( 23, 59, 59 ) ) );
00127 
00128   updateText();
00129   setFocusPolicy(QWidget::StrongFocus);
00130 
00131   connect(this, SIGNAL(activated(int)), this, SLOT(active(int)));
00132   connect(this, SIGNAL(highlighted(int)), this, SLOT(hilit(int)));
00133   connect(this, SIGNAL(textChanged(const QString&)),this,SLOT(changedText()));
00134 }
00135 
00136 KTimeEdit::~KTimeEdit()
00137 {
00138 }
00139 
00140 bool KTimeEdit::hasTime() const
00141 {
00142   // Can't happen
00143   if ( currentText().isEmpty() ) return false;
00144   //if ( currentText() == mNoTimeString ) return false;
00145 
00146   return true; // always
00147 }
00148 
00149 QTime KTimeEdit::getTime() const
00150 {
00151   //kdDebug(5300) << "KTimeEdit::getTime(), currentText() = " << currentText() << endl;
00152   // TODO use KLocale::WithoutSeconds in HEAD
00153   bool ok = false;
00154   QTime time = KGlobal::locale()->readTime( currentText(), KLocale::WithoutSeconds, &ok );
00155   if ( !ok ) {
00156     // Also try to accept times in "military format", i.e. no delimiter, like 1200
00157     int tm = currentText().toInt( &ok );
00158     if ( ( 0 <= tm ) && ( tm < 2400 ) && ( tm%100 < 60 ) && ok ) {
00159       time.setHMS( tm / 100, tm % 100, 0 );
00160     } else {
00161       ok = false;
00162     }
00163   }
00164   kdDebug(5300) << "KTimeEdit::getTime(): " << time.toString() << endl;
00165   return time;
00166 }
00167 
00168 QSizePolicy  KTimeEdit::sizePolicy() const
00169 {
00170   // Set size policy to Fixed, because edit cannot contain more text than the
00171   // string representing the time. It doesn't make sense to provide more space.
00172   QSizePolicy sizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);
00173 
00174   return sizePolicy;
00175 }
00176 
00177 void KTimeEdit::setTime(QTime newTime)
00178 {
00179   if ( mTime != newTime )
00180   {
00181     kdDebug(5300) << "KTimeEdit::setTime(): " << newTime.toString() << endl;
00182 
00183     mTime = newTime;
00184     updateText();
00185   }
00186 }
00187 
00188 void KTimeEdit::active(int i)
00189 {
00190     // The last entry, 23:59, is a special case
00191     if( i == count() - 1 )
00192         mTime = QTime( 23, 59, 0 );
00193     else
00194         mTime = QTime(0,0,0).addSecs(i*15*60);
00195     emit timeChanged(mTime);
00196 }
00197 
00198 void KTimeEdit::hilit(int )
00199 {
00200   // we don't currently need to do anything here.
00201 }
00202 
00203 void KTimeEdit::addTime(QTime qt)
00204 {
00205   // Calculate the new time.
00206   mTime = qt.addSecs(mTime.minute()*60+mTime.hour()*3600);
00207   updateText();
00208   emit timeChanged(mTime);
00209 }
00210 
00211 void KTimeEdit::subTime(QTime qt)
00212 {
00213   int h, m;
00214 
00215   // Note that we cannot use the same method for determining the new
00216   // time as we did in addTime, because QTime does not handle adding
00217   // negative seconds well at all.
00218   h = mTime.hour()-qt.hour();
00219   m = mTime.minute()-qt.minute();
00220 
00221   if(m < 0) {
00222     m += 60;
00223     h -= 1;
00224   }
00225 
00226   if(h < 0) {
00227     h += 24;
00228   }
00229 
00230   // store the newly calculated time.
00231   mTime.setHMS(h, m, 0);
00232   updateText();
00233   emit timeChanged(mTime);
00234 }
00235 
00236 void KTimeEdit::keyPressEvent(QKeyEvent *qke)
00237 {
00238   switch(qke->key()) {
00239   case Key_Down:
00240     addTime(QTime(0,1,0));
00241     break;
00242   case Key_Up:
00243     subTime(QTime(0,1,0));
00244     break;
00245   case Key_Prior:
00246     subTime(QTime(1,0,0));
00247     break;
00248   case Key_Next:
00249     addTime(QTime(1,0,0));
00250     break;
00251   default:
00252     QComboBox::keyPressEvent(qke);
00253     break;
00254   } // switch
00255 }
00256 
00257 void KTimeEdit::updateText()
00258 {
00259 //  kdDebug(5300) << "KTimeEdit::updateText() " << endl;
00260   QString s = KGlobal::locale()->formatTime(mTime);
00261   // Set the text but without emitting signals, nor losing the cursor position
00262   QLineEdit *line = lineEdit();
00263   line->blockSignals(true);
00264   int pos = line->cursorPosition();
00265 
00266   // select item with nearest time, must be done while line edit is blocked
00267   // as setCurrentItem() calls setText() with triggers KTimeEdit::changedText()
00268   setCurrentItem((mTime.hour()*4)+((mTime.minute()+7)/15));
00269 
00270   line->setText(s);
00271   line->setCursorPosition(pos);
00272   line->blockSignals(false);
00273 
00274 //  kdDebug(5300) << "KTimeEdit::updateText(): " << s << endl;
00275 }
00276 
00277 bool KTimeEdit::inputIsValid() const
00278 {
00279   int cursorPos = lineEdit()->cursorPosition();
00280   QString str = currentText();
00281   return validator()->validate( str, cursorPos ) == QValidator::Acceptable;
00282 }
00283 
00284 void KTimeEdit::changedText()
00285 {
00286   //kdDebug(5300) << "KTimeEdit::changedText()" << endl;
00287   if ( inputIsValid() )
00288   {
00289     mTime = getTime();
00290     emit timeChanged(mTime);
00291   }
00292 }
KDE Home | KDE Accessibility Home | Description of Access Keys