ktimeedit.cpp
00001 /* 00002 This file is part of libtdepim. 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 TQt, and distribute the resulting executable, 00024 without including the source code for TQt in the source distribution. 00025 */ 00026 00027 #include <tqkeycode.h> 00028 #include <tqcombobox.h> 00029 #include <tqdatetime.h> 00030 #include <tqlineedit.h> 00031 00032 #include <tdemessagebox.h> 00033 #include <tdeglobal.h> 00034 #include <kdebug.h> 00035 #include <tdelocale.h> 00036 00037 #include "ktimeedit.h" 00038 #include <tqvalidator.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 TQValidator 00044 { 00045 public: 00046 KOTimeValidator(TQWidget* parent, const char* name=0) : TQValidator(TQT_TQOBJECT(parent), name) {} 00047 00048 virtual State validate(TQString& 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 /*TQTime time =*/ TDEGlobal::locale()->readTime(str, TDELocale::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 TQChar 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 TQString 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 TQString 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 ( TQString & input ) const { 00093 bool ok = false; 00094 TDEGlobal::locale()->readTime( input, TDELocale::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 = TDEGlobal::locale()->formatTime( TQTime( tm / 100, tm % 100, 0 ) ); 00100 } 00101 } 00102 } 00103 }; 00104 00105 // KTimeWidget/TQTimeEdit provide nicer editing, but don't provide a combobox. 00106 // Difficult to get all in one... 00107 // But TQt-3.2 will offer TQLineEdit::setMask, so a "99:99" mask would help. 00108 KTimeEdit::KTimeEdit( TQWidget *parent, TQTime qt, const char *name ) 00109 : TQComboBox( 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 TQTime timeEntry(0,0,0); 00121 do { 00122 insertItem(TDEGlobal::locale()->formatTime(timeEntry)); 00123 timeEntry = timeEntry.addSecs(60*15); 00124 } while (!timeEntry.isNull()); 00125 // Add end of day. 00126 insertItem( TDEGlobal::locale()->formatTime( TQTime( 23, 59, 59 ) ) ); 00127 00128 updateText(); 00129 setFocusPolicy(TQ_StrongFocus); 00130 00131 connect(this, TQT_SIGNAL(activated(int)), this, TQT_SLOT(active(int))); 00132 connect(this, TQT_SIGNAL(highlighted(int)), this, TQT_SLOT(hilit(int))); 00133 connect(this, TQT_SIGNAL(textChanged(const TQString&)),this,TQT_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 TQTime KTimeEdit::getTime() const 00150 { 00151 //kdDebug(5300) << "KTimeEdit::getTime(), currentText() = " << currentText() << endl; 00152 // TODO use TDELocale::WithoutSeconds in HEAD 00153 bool ok = false; 00154 TQTime time = TDEGlobal::locale()->readTime( currentText(), TDELocale::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 TQSizePolicy 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 TQSizePolicy sizePolicy(TQSizePolicy::Fixed,TQSizePolicy::Fixed); 00173 00174 return sizePolicy; 00175 } 00176 00177 void KTimeEdit::setTime(TQTime newTime) 00178 { 00179 if ( mTime != newTime ) 00180 { 00181 kdDebug(5300) << "KTimeEdit::setTime(): " << TQString(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 = TQTime( 23, 59, 0 ); 00193 else 00194 mTime = TQTime(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(TQTime 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(TQTime 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 TQTime 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(TQKeyEvent *qke) 00237 { 00238 switch(qke->key()) { 00239 case Key_Down: 00240 addTime(TQTime(0,1,0)); 00241 break; 00242 case Key_Up: 00243 subTime(TQTime(0,1,0)); 00244 break; 00245 case Key_Prior: 00246 subTime(TQTime(1,0,0)); 00247 break; 00248 case Key_Next: 00249 addTime(TQTime(1,0,0)); 00250 break; 00251 default: 00252 TQComboBox::keyPressEvent(qke); 00253 break; 00254 } // switch 00255 } 00256 00257 void KTimeEdit::updateText() 00258 { 00259 // kdDebug(5300) << "KTimeEdit::updateText() " << endl; 00260 TQString s = TDEGlobal::locale()->formatTime(mTime); 00261 // Set the text but without emitting signals, nor losing the cursor position 00262 TQLineEdit *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 TQString str = currentText(); 00281 return validator()->validate( str, cursorPos ) == TQValidator::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 }