-rw-r--r-- | korganizer/ktimeedit.cpp | 528 |
1 files changed, 528 insertions, 0 deletions
diff --git a/korganizer/ktimeedit.cpp b/korganizer/ktimeedit.cpp new file mode 100644 index 0000000..f9720f6 --- a/dev/null +++ b/korganizer/ktimeedit.cpp | |||
@@ -0,0 +1,528 @@ | |||
1 | /* | ||
2 | This file is part of KOrganizer. | ||
3 | Copyright (c) 1999 Preston Brown, Ian Dawes | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | |||
19 | As a special exception, permission is given to link this program | ||
20 | with any edition of Qt, and distribute the resulting executable, | ||
21 | without including the source code for Qt in the source distribution. | ||
22 | */ | ||
23 | |||
24 | #include <qkeycode.h> | ||
25 | #include <qcombobox.h> | ||
26 | #include <qdatetime.h> | ||
27 | #include <qlineedit.h> | ||
28 | #include <qapplication.h> | ||
29 | |||
30 | #include <kmessagebox.h> | ||
31 | #include <kglobal.h> | ||
32 | #include <kdebug.h> | ||
33 | #include <klocale.h> | ||
34 | |||
35 | #include "ktimeedit.h" | ||
36 | #include "koprefs.h" | ||
37 | #include <qvalidator.h> | ||
38 | #include "ktimeedit.moc" | ||
39 | |||
40 | // Validator for a time value with only hours and minutes (no seconds) | ||
41 | // Mostly locale aware. Author: David Faure <faure@kde.org> | ||
42 | class KOTimeValidator : public QValidator | ||
43 | { | ||
44 | public: | ||
45 | KOTimeValidator(QWidget* parent, const char* name=0) : QValidator(parent, name) {} | ||
46 | |||
47 | virtual State validate(QString& str, int& /*cursorPos*/) const | ||
48 | { | ||
49 | return Acceptable; | ||
50 | bool ok = false; | ||
51 | // TODO use KLocale::WithoutSeconds in HEAD | ||
52 | /*QTime time =*/ KGlobal::locale()->readTime(str, &ok); | ||
53 | if ( ok ) | ||
54 | return Acceptable; | ||
55 | // readTime doesn't help knowing when the string is "Intermediate". | ||
56 | int length = str.length(); | ||
57 | if ( !str ) // empty string? | ||
58 | return Invalid; // there should always be a ':' in it, right? | ||
59 | // HACK. Not fully locale aware etc. (esp. the separator is '.' in sv_SE...) | ||
60 | QChar sep = ':'; | ||
61 | // I want to allow "HH:", ":MM" and ":" to make editing easier | ||
62 | if ( str[0] == sep ) | ||
63 | { | ||
64 | if ( length == 1 ) // just ":" | ||
65 | return Intermediate; | ||
66 | QString minutes = str.mid(1); | ||
67 | int m = minutes.toInt(&ok); | ||
68 | if ( ok && m >= 0 && m < 60 ) | ||
69 | return Intermediate; | ||
70 | } else if ( str.at(str.length()-1) == sep ) | ||
71 | { | ||
72 | QString hours = str.left(length-1); | ||
73 | int h = hours.toInt(&ok); | ||
74 | if ( ok && h >= 0 && h < 24 ) | ||
75 | return Intermediate; | ||
76 | } | ||
77 | return Invalid; | ||
78 | } | ||
79 | }; | ||
80 | |||
81 | // KTimeWidget/QTimeEdit provide nicer editing, but don't provide a combobox. | ||
82 | // Difficult to get all in one... | ||
83 | // But Qt-3.2 will offer QLineEdit::setMask, so a "99:99" mask would help. | ||
84 | KOTimeEdit::KOTimeEdit(QWidget *parent, QTime qt, const char *name) | ||
85 | : QComboBox(TRUE, parent, name) | ||
86 | { | ||
87 | setInsertionPolicy(NoInsertion); | ||
88 | setValidator( new KOTimeValidator( this ) ); | ||
89 | mFlagKeyPressed = false; | ||
90 | |||
91 | if ( QApplication::desktop()->width() < 650 ) | ||
92 | setSizeLimit ( 6 ); | ||
93 | mTime = qt; | ||
94 | |||
95 | // mNoTimeString = i18n("No Time"); | ||
96 | // insertItem( mNoTimeString ); | ||
97 | |||
98 | // Fill combo box with selection of times in localized format. | ||
99 | QTime timeEntry(0,0,0); | ||
100 | do { | ||
101 | insertItem(KGlobal::locale()->formatTime(timeEntry)); | ||
102 | timeEntry = timeEntry.addSecs(60*15); | ||
103 | } while (!timeEntry.isNull()); | ||
104 | // Add end of day. | ||
105 | insertItem( KGlobal::locale()->formatTime( QTime( 23, 59, 59 ) ) ); | ||
106 | |||
107 | updateText(); | ||
108 | setFocusPolicy(QWidget::StrongFocus); | ||
109 | |||
110 | connect(this, SIGNAL(activated(int)), this, SLOT(activ(int))); | ||
111 | connect(this, SIGNAL(highlighted(int)), this, SLOT(hilit(int))); | ||
112 | connect(this,SIGNAL(textChanged(const QString&)),this,SLOT(changedText())); | ||
113 | QFontMetrics fm ( font() ); | ||
114 | QString timeString = "24:00"; | ||
115 | if ( KOPrefs::instance()->mPreferredTime == 1 ) | ||
116 | timeString = "02:00pm"; | ||
117 | int addSpace = 32; | ||
118 | if ( QApplication::desktop()->width() > 320 ) | ||
119 | timeString += ":00"; | ||
120 | setFixedWidth(fm.width( timeString ) + 32 ); | ||
121 | |||
122 | // Highlight Background and Textcolor change from default | ||
123 | QPalette palette = QWidget::palette(); | ||
124 | unsigned char red, green, blue; | ||
125 | red = palette.color( QPalette::Normal , QColorGroup::Background ).red() - 10; | ||
126 | green = palette.color( QPalette::Normal , QColorGroup::Background ).green() - 10; | ||
127 | blue = palette.color( QPalette::Normal , QColorGroup::Background ).blue() - 10; | ||
128 | palette.setColor( QColorGroup::Highlight, QColor(red,green,blue) ); | ||
129 | palette.setColor( QColorGroup::HighlightedText, palette.color( QPalette::Normal , QColorGroup::Foreground ) ); | ||
130 | setPalette( palette ); | ||
131 | } | ||
132 | |||
133 | KOTimeEdit::~KOTimeEdit() | ||
134 | { | ||
135 | } | ||
136 | |||
137 | bool KOTimeEdit::hasTime() const | ||
138 | { | ||
139 | // Can't happen | ||
140 | if ( currentText().isEmpty() ) return false; | ||
141 | //if ( currentText() == mNoTimeString ) return false; | ||
142 | |||
143 | return true; // always | ||
144 | } | ||
145 | |||
146 | QTime KOTimeEdit::getTime() const | ||
147 | { | ||
148 | //kdDebug(5850) << "KOTimeEdit::getTime(), currentText() = " << currentText() << endl; | ||
149 | // TODO use KLocale::WithoutSeconds in HEAD | ||
150 | QTime time = KGlobal::locale()->readTime(currentText()); | ||
151 | // kdDebug(5850) << "KOTimeEdit::getTime(): " << time.toString() << endl; | ||
152 | return time; | ||
153 | } | ||
154 | /* | ||
155 | QSizePolicy KOTimeEdit::sizePolicy() const | ||
156 | { | ||
157 | // Set size policy to Fixed, because edit cannot contain more text than the | ||
158 | // string representing the time. It doesn't make sense to provide more space. | ||
159 | QSizePolicy sizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); | ||
160 | |||
161 | return sizePolicy; | ||
162 | } | ||
163 | */ | ||
164 | void KOTimeEdit::setTime(QTime newTime) | ||
165 | { | ||
166 | if ( mTime != newTime ) | ||
167 | { | ||
168 | kdDebug(5850) << "KOTimeEdit::setTime(): " << newTime.toString() << endl; | ||
169 | |||
170 | mTime = newTime; | ||
171 | updateText(); | ||
172 | } | ||
173 | |||
174 | } | ||
175 | |||
176 | void KOTimeEdit::activ(int i) | ||
177 | { | ||
178 | // The last entry, 23:59, is a special case | ||
179 | if( i == count() - 1 ) | ||
180 | mTime = QTime( 23, 59, 0 ); | ||
181 | else | ||
182 | mTime = QTime(0,0,0).addSecs(i*15*60); | ||
183 | emit timeChanged(mTime); | ||
184 | } | ||
185 | |||
186 | void KOTimeEdit::hilit(int ) | ||
187 | { | ||
188 | // we don't currently need to do anything here. | ||
189 | } | ||
190 | |||
191 | void KOTimeEdit::addTime(QTime qt, bool update) | ||
192 | { | ||
193 | // Calculate the new time. | ||
194 | //qDebug("add h %d min %d ", qt.hour(),qt.minute() ); | ||
195 | mTime = mTime.addSecs(qt.minute()*60+qt.hour()*3600); | ||
196 | // if ( update ) | ||
197 | updateText(); | ||
198 | emit timeChanged(mTime); | ||
199 | } | ||
200 | |||
201 | void KOTimeEdit::subTime(QTime qt, bool update) | ||
202 | { | ||
203 | int h, m; | ||
204 | //qDebug("sub h %d min %d ", qt.hour(),qt.minute() ); | ||
205 | |||
206 | mTime = mTime.addSecs(-(qt.minute()*60+qt.hour()*3600)); | ||
207 | // store the newly calculated time. | ||
208 | // mTime.setHMS(h, m, 0); | ||
209 | //if ( update ) | ||
210 | updateText(); | ||
211 | emit timeChanged(mTime); | ||
212 | } | ||
213 | |||
214 | // void KOTimeEdit::mouseReleaseEvent ( QMouseEvent * ) | ||
215 | // { | ||
216 | // qDebug("mouseReleaseEvent ( QMouseEvent * ) "); | ||
217 | // } | ||
218 | |||
219 | // void KOTimeEdit::focusInEvent ( QFocusEvent * ) | ||
220 | // { | ||
221 | // qDebug("focusInEvent ( QFocusEvent * ) "); | ||
222 | // } | ||
223 | |||
224 | void KOTimeEdit::keyReleaseEvent(QKeyEvent *e) | ||
225 | { | ||
226 | if ( !e->isAutoRepeat() ) { | ||
227 | mFlagKeyPressed = false; | ||
228 | } | ||
229 | |||
230 | } | ||
231 | void KOTimeEdit::setSelect( int from, int to ) | ||
232 | { | ||
233 | if ( KOPrefs::instance()->mHightlightDateTimeEdit) | ||
234 | lineEdit()->setSelection( from , to ); | ||
235 | } | ||
236 | |||
237 | |||
238 | void KOTimeEdit::keyPressEvent(QKeyEvent *e) | ||
239 | { | ||
240 | |||
241 | qApp->processEvents(); | ||
242 | bool hour12Format = ( KOPrefs::instance()->mPreferredTime == 1 ); | ||
243 | int maxpos = hour12Format?7:5; | ||
244 | if ( e->isAutoRepeat() && !mFlagKeyPressed ) { | ||
245 | e->ignore(); | ||
246 | // qDebug(" ignore %d",e->isAutoRepeat() ); | ||
247 | return; | ||
248 | } | ||
249 | if (! e->isAutoRepeat() ) { | ||
250 | mFlagKeyPressed = true; | ||
251 | } | ||
252 | // Tap -> Focus Next Widget | ||
253 | if ( e->key() == Key_Tab ) { | ||
254 | QComboBox::keyPressEvent(e); | ||
255 | return; | ||
256 | } | ||
257 | |||
258 | // save Text from QLineEdit and CursorPosition | ||
259 | QString text = lineEdit()->text(); | ||
260 | int cpos = lineEdit()->cursorPosition(); | ||
261 | // qDebug("cpos %d ", cpos); | ||
262 | |||
263 | // Switch for arrows, backspace and escape | ||
264 | switch(e->key()) { | ||
265 | case Key_Escape: | ||
266 | lineEdit()->deselect(); | ||
267 | case Key_Tab: | ||
268 | QComboBox::keyPressEvent(e); | ||
269 | break; | ||
270 | case Key_Up: | ||
271 | if ( e->state () == Qt::ControlButton ) { | ||
272 | addTime(QTime(0,15,0), false ); | ||
273 | lineEdit()->setCursorPosition(3); | ||
274 | setSelect( 3 , 2 ); | ||
275 | } | ||
276 | else | ||
277 | if ( e->state () == Qt::ShiftButton ) { | ||
278 | addTime(QTime(1,0,0), false ); | ||
279 | lineEdit()->setCursorPosition(0); | ||
280 | setSelect( 0 , 2 ); | ||
281 | } | ||
282 | else | ||
283 | // switch time up, cursor location depend | ||
284 | switch (cpos) { | ||
285 | case 7: | ||
286 | case 6: | ||
287 | case 5: | ||
288 | if(!hour12Format) { | ||
289 | lineEdit()->setCursorPosition(cpos = 4); | ||
290 | } else { | ||
291 | addTime(QTime(12,0,0), false ); | ||
292 | setSelect ( 5 , 2 ); | ||
293 | break; | ||
294 | } | ||
295 | case 4: | ||
296 | addTime(QTime(0,1,0), false ); | ||
297 | setSelect ( cpos , 1 ); | ||
298 | break; | ||
299 | case 3: | ||
300 | addTime(QTime(0,10,0), false ); | ||
301 | setSelect ( cpos , 1 ); | ||
302 | break; | ||
303 | case 2: | ||
304 | lineEdit()->setCursorPosition(--cpos); | ||
305 | case 1: | ||
306 | case 0: | ||
307 | addTime(QTime(1,0,0), false ); | ||
308 | setSelect ( 0, 2 ); | ||
309 | break; | ||
310 | } | ||
311 | break; | ||
312 | case Key_Down: | ||
313 | if ( e->state () == Qt::ControlButton ) { | ||
314 | subTime(QTime(0,15,0), false ); | ||
315 | lineEdit()->setCursorPosition(3); | ||
316 | setSelect( 3 , 2 ); | ||
317 | } | ||
318 | else | ||
319 | if ( e->state () == Qt::ShiftButton ) { | ||
320 | subTime(QTime(1,0,0), false ); | ||
321 | lineEdit()->setCursorPosition(0); | ||
322 | setSelect( 0 , 2 ); | ||
323 | } | ||
324 | else | ||
325 | // switch time down, cursor location depend | ||
326 | switch (cpos) { | ||
327 | case 7: | ||
328 | case 6: | ||
329 | case 5: | ||
330 | if(!hour12Format) { | ||
331 | lineEdit()->setCursorPosition(cpos = 4); | ||
332 | } else { | ||
333 | subTime(QTime(12,0,0), false ); | ||
334 | setSelect ( 5 , 2 ); | ||
335 | break; | ||
336 | } | ||
337 | case 4: | ||
338 | subTime(QTime(0,1,0), false ); | ||
339 | setSelect ( cpos , 1 ); | ||
340 | break; | ||
341 | case 3: | ||
342 | subTime(QTime(0,10,0), false ); | ||
343 | setSelect ( cpos , 1 ); | ||
344 | break; | ||
345 | case 2: | ||
346 | lineEdit()->setCursorPosition(--cpos); | ||
347 | case 1: | ||
348 | case 0: | ||
349 | subTime(QTime(1,0,0), false ); | ||
350 | setSelect ( 0 , 2 ); | ||
351 | break; | ||
352 | } | ||
353 | break; | ||
354 | // set cursor to correct place | ||
355 | case Key_Left: | ||
356 | if ( cpos == 3 ) | ||
357 | --cpos; | ||
358 | if ( cpos > 0) { | ||
359 | lineEdit()->setCursorPosition(--cpos); | ||
360 | setSelect ( cpos , 1 ); | ||
361 | } | ||
362 | else | ||
363 | setSelect ( 0 , 1 ); | ||
364 | break; | ||
365 | // set cursor to correct place | ||
366 | case Key_Right: | ||
367 | if ( cpos == 1 ) | ||
368 | ++cpos; | ||
369 | if ( cpos < maxpos ) { | ||
370 | lineEdit()->setCursorPosition(++cpos); | ||
371 | setSelect ( cpos , 1 ); | ||
372 | } | ||
373 | break; | ||
374 | // rest | ||
375 | case Key_Prior: | ||
376 | subTime(QTime(1,0,0)); | ||
377 | break; | ||
378 | case Key_Next: | ||
379 | addTime(QTime(1,0,0)); | ||
380 | break; | ||
381 | case Key_Backspace: | ||
382 | if ( cpos > 0) { | ||
383 | if ( cpos == 3 ) | ||
384 | --cpos; | ||
385 | if ( cpos > 5) | ||
386 | cpos = 5; | ||
387 | text.at( cpos-1 ) = '0'; | ||
388 | lineEdit()->setText( text ); | ||
389 | lineEdit()->setCursorPosition(--cpos); | ||
390 | setSelect ( cpos , 1 ); | ||
391 | changedText(); | ||
392 | } | ||
393 | break; | ||
394 | } // switch arrows | ||
395 | |||
396 | // if cursor at string end, alltext market and keyEvent don't ArrowLeft -> deselect and cpos | ||
397 | if( cpos > 4 && lineEdit()->markedText().length() == 5 && e->key() != Key_Left ) { | ||
398 | lineEdit()->deselect(); | ||
399 | cpos = 0; | ||
400 | lineEdit()->setCursorPosition(cpos); | ||
401 | setSelect(cpos , 1); | ||
402 | } | ||
403 | |||
404 | if ( cpos == 2 ) { | ||
405 | lineEdit()->setCursorPosition(++cpos); | ||
406 | } | ||
407 | |||
408 | // num keys when cursorPos preEnd | ||
409 | if ( cpos < 5 ) { | ||
410 | // switch another keys | ||
411 | switch(e->key()) { | ||
412 | case Key_Delete: | ||
413 | text.at( cpos ) = '0'; | ||
414 | lineEdit()->setText( text ); | ||
415 | lineEdit()->setCursorPosition(cpos); | ||
416 | setSelect ( cpos , 1 ); | ||
417 | changedText(); | ||
418 | break; | ||
419 | case Key_9: | ||
420 | case Key_8: | ||
421 | case Key_7: | ||
422 | case Key_6: | ||
423 | if ( !(cpos == 1 || cpos == 4) ) | ||
424 | return; | ||
425 | if ( cpos == 1 && text.at( 0 ) > '1') | ||
426 | text.at( 0 ) = '1'; | ||
427 | case Key_5: | ||
428 | case Key_4: | ||
429 | case Key_3: | ||
430 | if ( cpos < 1 ) | ||
431 | return; | ||
432 | if ( hour12Format && cpos == 1 ) | ||
433 | return; | ||
434 | case Key_2: | ||
435 | if ( hour12Format && cpos == 0 ) | ||
436 | return; | ||
437 | if ( cpos == 0 && text.at( 1 ) > '3') | ||
438 | text.at( 1 ) = '3'; | ||
439 | case Key_1: | ||
440 | case Key_0: | ||
441 | if ( hour12Format ) { | ||
442 | if ( e->key() == Key_0 && cpos == 1 && text.at( 0 ) == '0' ) | ||
443 | return; | ||
444 | if ( e->key() == Key_0 && cpos == 0 && text.at( 1 ) == '0' ) | ||
445 | text.at( 1 ) = '1'; | ||
446 | } | ||
447 | text.at( cpos ) = QChar ( e->key() ); | ||
448 | lineEdit()->setText( text ); | ||
449 | if ( cpos == 1 ) | ||
450 | ++cpos; | ||
451 | if ( cpos < 5) | ||
452 | lineEdit()->setCursorPosition(++cpos); | ||
453 | setSelect( cpos , 1 ); | ||
454 | changedText(); | ||
455 | break; | ||
456 | case Key_Home: | ||
457 | lineEdit()->setCursorPosition(0); | ||
458 | setSelect( cpos , 1 ); | ||
459 | break; | ||
460 | case Key_End: | ||
461 | lineEdit()->setCursorPosition(5); | ||
462 | lineEdit()->deselect(); | ||
463 | break; | ||
464 | default: | ||
465 | // QComboBox::keyPressEvent(e); | ||
466 | break; | ||
467 | } // switch num keys | ||
468 | } else if ( cpos == 5 ) {// if cpos < 5 | ||
469 | if ( hour12Format ) { | ||
470 | if ( e->key() == Key_A ) { | ||
471 | text.at( 5 ) = 'a'; | ||
472 | lineEdit()->setText( text ); | ||
473 | lineEdit()->setCursorPosition(5); | ||
474 | |||
475 | } else if ( e->key() == Key_P ) { | ||
476 | text.at( 5 ) = 'p'; | ||
477 | lineEdit()->setText( text ); | ||
478 | lineEdit()->setCursorPosition(5); | ||
479 | |||
480 | } | ||
481 | } | ||
482 | } | ||
483 | |||
484 | |||
485 | } | ||
486 | |||
487 | void KOTimeEdit::updateText() | ||
488 | { | ||
489 | // kdDebug(5850) << "KOTimeEdit::updateText() " << endl | ||
490 | QString s = KGlobal::locale()->formatTime(mTime); | ||
491 | // Set the text but without emitting signals, nor losing the cursor position | ||
492 | QLineEdit *line = lineEdit(); | ||
493 | line->blockSignals(true); | ||
494 | int pos = line->cursorPosition(); | ||
495 | // qDebug(" settext *%s* ", s.latin1()); | ||
496 | line->setText(s); | ||
497 | // line->setCursorPosition(pos); | ||
498 | // line->blockSignals(false); | ||
499 | |||
500 | // kdDebug(5850) << "KOTimeEdit::updateText(): " << s << endl; | ||
501 | |||
502 | if (!mTime.minute() % 15) { | ||
503 | setCurrentItem((mTime.hour()*4)+(mTime.minute()/15)); | ||
504 | } | ||
505 | line->setCursorPosition(pos); | ||
506 | line->blockSignals(false); | ||
507 | |||
508 | } | ||
509 | |||
510 | bool KOTimeEdit::inputIsValid() const | ||
511 | { | ||
512 | int cursorPos = lineEdit()->cursorPosition(); | ||
513 | QString str = currentText(); | ||
514 | return validator()->validate( str, cursorPos ) == QValidator::Acceptable; | ||
515 | } | ||
516 | |||
517 | void KOTimeEdit::changedText() | ||
518 | { | ||
519 | //kdDebug(5850) << "KOTimeEdit::changedText()" << endl; | ||
520 | if ( inputIsValid() ) | ||
521 | { | ||
522 | int pos = lineEdit()->cursorPosition(); | ||
523 | mTime = getTime(); | ||
524 | // updateText(); | ||
525 | emit timeChanged(mTime); | ||
526 | lineEdit()->setCursorPosition(pos); | ||
527 | } | ||
528 | } | ||