summaryrefslogtreecommitdiffabout
path: root/libkdepim/kdateedit.cpp
Unidiff
Diffstat (limited to 'libkdepim/kdateedit.cpp') (more/less context) (show whitespace changes)
-rw-r--r--libkdepim/kdateedit.cpp486
1 files changed, 486 insertions, 0 deletions
diff --git a/libkdepim/kdateedit.cpp b/libkdepim/kdateedit.cpp
new file mode 100644
index 0000000..60bd2cf
--- a/dev/null
+++ b/libkdepim/kdateedit.cpp
@@ -0,0 +1,486 @@
1/*
2 This file is part of libkdepim.
3
4 Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 As a special exception, permission is given to link this program
21 with any edition of Qt, and distribute the resulting executable,
22 without including the source code for Qt in the source distribution.
23*/
24
25#include <qapplication.h>
26#include <qevent.h>
27#include <qlineedit.h>
28#include <qpixmap.h>
29#include <qpushbutton.h>
30
31#include <kdatepicker.h>
32#include <kdebug.h>
33#include <kglobal.h>
34#include <kiconloader.h>
35#include <klocale.h>
36#include <kmessagebox.h>
37#include <knotifyclient.h>
38#include <qpalette.h>
39
40#include "kdateedit.h"
41#include "kdateedit.moc"
42
43KDateEdit::KDateEdit(QWidget *parent, const char *name, bool withoutDP )
44 : QHBox(parent, name)
45{
46 dateFormShort = true;
47 withoutDp = withoutDP;
48 mDateEdit = new QLineEdit(this);
49 mDateEdit->setText(KGlobal::locale()->formatDate(QDate::currentDate(),dateFormShort));
50 setFocusProxy(mDateEdit);
51 mDateEdit->installEventFilter(this);
52
53 // Highlight Background and Textcolor
54 QPalette palette = QWidget::palette();
55 unsigned char red, green, blue;
56 red = palette.color( QPalette::Normal , QColorGroup::Background ).red() - 10;
57 green = palette.color( QPalette::Normal , QColorGroup::Background ).green() - 10;
58 blue = palette.color( QPalette::Normal , QColorGroup::Background ).blue() - 10;
59 palette.setColor( QColorGroup::Highlight, QColor(red,green,blue) );
60 palette.setColor( QColorGroup::HighlightedText, palette.color( QPalette::Normal , QColorGroup::Foreground ) );
61 mDateEdit->setPalette( palette );
62
63 if ( withoutDP ) {
64 mDateFrame = 0;
65 mDateButton = 0;
66 mDatePicker = 0;
67 } else {
68 QPixmap pixmap = SmallIcon("smallcal");
69 mDateButton = new QPushButton(this);
70 mDateButton->setPixmap(pixmap);
71
72 mDateFrame = new QVBox(0,0,WType_Popup);
73 // mDateFrame->setFrameStyle(QFrame::PopupPanel | QFrame::Raised);
74 mDateFrame->setFrameStyle( QFrame::WinPanel |QFrame::Raised );
75 mDateFrame->setLineWidth(3);
76 mDateFrame->hide();
77
78 mDatePicker = new KDatePicker(mDateFrame,QDate::currentDate());
79 connect(mDatePicker,SIGNAL(dateEntered(QDate)),SLOT(setDate(QDate)));
80 connect(mDatePicker,SIGNAL(dateEntered(QDate)),SIGNAL(dateChanged(QDate)));
81 connect(mDatePicker,SIGNAL(dateSelected(QDate)),SLOT(setDate(QDate)));
82 connect(mDatePicker,SIGNAL(dateSelected(QDate)),SIGNAL(dateChanged(QDate)));
83 connect(mDatePicker,SIGNAL(dateSelected(QDate)),mDateFrame,SLOT(hide()));
84 connect(mDateButton,SIGNAL(clicked()),SLOT(toggleDatePicker()));
85
86 //mDateFrame->resize( 400, 300 );
87
88 }
89 connect(mDateEdit,SIGNAL(returnPressed()),SLOT(lineEnterPressed()));
90 connect(mDateEdit,SIGNAL(textChanged(const QString &)),
91 SLOT(textChanged(const QString &)));
92
93 // Create the keyword list. This will be used to match against when the user
94 // enters information.
95 mKeywordMap[i18n("tomorrow")] = 1;
96 mKeywordMap[i18n("today")] = 0;
97 mKeywordMap[i18n("yesterday")] = -1;
98
99 /*
100 * This loop uses some math tricks to figure out the offset in days
101 * to the next date the given day of the week occurs. There
102 * are two cases, that the new day is >= the current day, which means
103 * the new day has not occured yet or that the new day < the current day,
104 * which means the new day is already passed (so we need to find the
105 * day in the next week).
106 */
107 QString dayName;
108 int currentDay = QDate::currentDate().dayOfWeek();
109 for (int i = 1; i <= 7; ++i)
110 {
111 dayName = KGlobal::locale()->weekDayName(i).lower();
112 if (i >= currentDay)
113 mKeywordMap[dayName] = i - currentDay;
114 else
115 mKeywordMap[dayName] = 7 - currentDay + i;
116 }
117
118 mTextChanged = false;
119 mHandleInvalid = false;
120 QWidget::setTabOrder( mDateEdit, mDateButton );
121}
122
123KDateEdit::~KDateEdit()
124{
125 delete mDateFrame;
126}
127
128void KDateEdit::setDate(QDate newDate)
129{
130 if (!newDate.isValid() && !mHandleInvalid)
131 return;
132 if ( readDate() == newDate )
133 return;
134 QString dateString = "";
135 if(newDate.isValid())
136 dateString = KGlobal::locale()->formatDate( newDate, dateFormShort );
137
138 mTextChanged = false;
139
140 // We do not want to generate a signal here, since we explicity setting
141 // the date
142 bool b = mDateEdit->signalsBlocked();
143 mDateEdit->blockSignals(true);
144 mDateEdit->setText(dateString);
145 mDateEdit->blockSignals(b);
146}
147
148void KDateEdit::setDate( QDate date,int *cpos,const int key ,const bool dateFormShort)
149{
150 QString dateForm = dateFormShort ?
151 KGlobal::locale()->dateFormatShort() :
152 KGlobal::locale()->dateFormat();
153
154 int begin = dateForm.find("%");
155 int space = 0;
156 int allStrLength = 0;
157 int strLength = 0;
158 int repeat = 0;
159
160 // witch? Day, Month or Year switch?
161 while(1){
162 switch ( dateForm.at(begin + 1).latin1() )
163 {
164 case 'd':// 16 (month day)
165 strLength = 2; //Ok
166 break;
167 case 'm':// 01 (month)
168 strLength = 2; //Ok
169 break;
170 case 'a':// Mon (Weekday)
171 strLength = KGlobal::locale()->weekDayName(date.dayOfWeek(), true).length();
172 break;
173 case 'A':// Monday (Weekday)
174 strLength = KGlobal::locale()->weekDayName(date.dayOfWeek(), false).length();
175 break;
176 case 'b':// Jan (monthName)
177 strLength = KGlobal::locale()->monthName(date.month(), true).length();
178 break;
179 case 'B':// January (monthName)
180 strLength = KGlobal::locale()->monthName(date.month(), false).length();
181 break;
182 case 'y':// 04 (year short)
183 strLength = 2; //Ok
184 break;
185 case 'Y':// 2004 (year)
186 strLength = 4; //Ok
187 break;
188 default:
189 break;
190 }
191 space = begin - (repeat++ * 2);
192 // all select? then dayswitch
193 if( (mDateEdit->text().length() == mDateEdit->markedText().length() ) &&
194 ( (dateForm.at(begin + 1).latin1() == 'd') ||
195 (dateForm.at(begin + 1).latin1() == 'a') ||
196 (dateForm.at(begin + 1).latin1() == 'A') ) ) {
197 break;
198 }
199 // mDateEdit-StringPos == CursorPosition(cpos) then break and set date
200 if( ( (space + allStrLength) <= *cpos && *cpos <= (space + allStrLength + strLength) ) || *cpos < begin ) {
201 break;
202 }
203 allStrLength += strLength;
204 begin = dateForm.find("%", begin +1);
205 }
206
207 // set date
208 switch ( dateForm.at(begin + 1).latin1() ) {
209 case 'd':
210 case 'a':
211 case 'A':
212 if(key == Key_Up) {
213 setDate( date.addDays( 1 ) );
214 }
215 else if(key == Key_Down) {
216 setDate( date.addDays( -1 ) );
217 }
218 maxDay = readDate().day();
219 break;
220 case 'm':
221 case 'b':
222 case 'B':
223 if(key == Key_Up) {
224 int year = ((date.month()+1)>12)?date.year()+1:date.year();
225 int month = ((date.month()+1)>12)?1:date.month()+1;
226 int day = (QDate(year,month,1).daysInMonth()<maxDay)?QDate(year,month,1).daysInMonth():maxDay;
227 setDate( QDate( year, month, day ) );
228 } else if(key == Key_Down) {
229 int year = ((date.month()-1)<1)?date.year()-1:date.year();
230 int month = ((date.month()-1)<1)?12:date.month()-1;
231 int day = (QDate(year,month,1).daysInMonth()<maxDay)?QDate(year,month,1).daysInMonth():maxDay;
232 setDate( QDate( year, month, day ) );
233 }
234 break;
235 case 'y':
236 case 'Y':
237 if(key == Key_Up) {
238 setDate( QDate( date.year() + 1, date.month() , date.day()) );
239 }
240 else if(key == Key_Down) {
241 setDate( QDate( date.year() - 1, date.month() , date.day()) );
242 }
243 break;
244/* default:
245 if(key == Key_Up) {
246 setDate( date.addDays( 1 ) );
247 } else if(key == Key_Down) {
248 setDate( date.addDays( -1 ) );
249 }
250 break;*/
251 }
252
253 date = readDate();
254 begin = dateForm.find("%");
255 int allSelectStrLength = 0;
256 int selectStrLength = 0;
257
258 // set selection do new date an set cursor at end of selection
259 for(int i = 0; i < repeat; i++){
260 switch ( dateForm.at(begin + 1).latin1() )
261 {
262 case 'd':// 16 (month day)
263 selectStrLength = 2; //Ok
264 break;
265 case 'm':// 01 (month)
266 selectStrLength = 2; //Ok
267 break;
268 case 'a':// Mon (Weekday short)
269 selectStrLength = KGlobal::locale()->weekDayName(date.dayOfWeek(), true).length();
270 break;
271 case 'A':// Monday (Weekday)
272 selectStrLength = KGlobal::locale()->weekDayName(date.dayOfWeek(), false).length();
273 break;
274 case 'b':// Jan (monthName short)
275 selectStrLength = KGlobal::locale()->monthName(date.month(), true).length();
276 break;
277 case 'B':// January (monthName)
278 selectStrLength = KGlobal::locale()->monthName(date.month(), false).length();
279 break;
280 case 'y':// 04 (year short)
281 selectStrLength = 2; //Ok
282 break;
283 case 'Y':// 2004 (year)
284 selectStrLength = 4; //Ok
285 break;
286 default:
287 break;
288 }
289 space = begin - (i * 2);
290 allSelectStrLength += selectStrLength;
291 begin = dateForm.find("%", begin +1);
292 }
293 // set selection from begin of date
294 setSelect( space + allSelectStrLength - selectStrLength , selectStrLength);
295 *cpos = space + allSelectStrLength;
296 emit(dateChanged(date));
297
298 return;
299}
300
301void KDateEdit::setHandleInvalid(bool handleInvalid)
302{
303 mHandleInvalid = handleInvalid;
304}
305
306void KDateEdit::setEnabled(bool on)
307{
308 mDateEdit->setEnabled(on);
309 mDateButton->setEnabled(on);
310}
311
312QDate KDateEdit::date() const
313{
314 QDate date = readDate();
315
316 if (date.isValid() || mHandleInvalid) {
317 return date;
318 } else {
319 KNotifyClient::beep();
320 return QDate::currentDate();
321 }
322}
323
324void KDateEdit::keyPressEvent(QKeyEvent *e)
325{
326 QDate date = readDate();
327 int cpos = mDateEdit->cursorPosition();
328
329 switch(e->key())
330 {
331 case Key_Escape:
332 mDateEdit->deselect();
333 case Key_Tab:
334 QHBox::keyPressEvent(e);
335 break;
336 case Key_Up:
337 // when date invalid then set to currend and return
338 if(!date.isValid()) {
339 date = QDate::currentDate();
340 setDate(date);
341 mDateEdit->setCursorPosition(cpos);
342 emit(dateChanged(date));
343 QString text = i18n( "You entered an invalid date!\n Date changed to current date." );
344 KMessageBox::information( 0, text );
345 return;
346 }
347 setDate(date, &cpos, Key_Up, dateFormShort);
348 break;
349 case Key_Down:
350 // when date invalid then set to current and return
351 if(!date.isValid()) {
352 date = QDate::currentDate();
353 setDate(date);
354 mDateEdit->setCursorPosition(cpos);
355 emit(dateChanged(date));
356 QString text = i18n( "You entered an invalid date!\n Date changed to current date." );
357 KMessageBox::information( 0, text );
358 return;
359 }
360 setDate(date, &cpos, Key_Down, dateFormShort);
361 break;
362 default:
363 QHBox::keyPressEvent(e);
364 break;
365 } // switch
366 mDateEdit->setCursorPosition(cpos);
367}
368
369void KDateEdit::setSelect( int from, int to )
370{
371// return;
372 mDateEdit->setSelection( from , to );
373}
374
375void KDateEdit::toggleDatePicker()
376{
377 if( mDateFrame->isVisible() ) {
378 mDateFrame->hide();
379 } else {
380 QPoint tmpPoint = mapToGlobal(mDateButton->geometry().bottomRight());
381 QSize datepickersize = mDatePicker->sizeHint();
382
383 if ( tmpPoint.x() < 7+datepickersize.width() ) tmpPoint.setX( 7+datepickersize.width() );
384
385 int h = QApplication::desktop()->height();
386
387 if ( tmpPoint.y() + datepickersize.height() > h ) tmpPoint.setY( h - datepickersize.height() );
388
389 mDateFrame->setGeometry(tmpPoint.x()-datepickersize.width()-7, tmpPoint.y(),
390 datepickersize.width()+2*mDateFrame->lineWidth(), datepickersize.height()+2*mDateFrame->lineWidth());
391
392 QDate date = readDate();
393 if(date.isValid()) {
394 mDatePicker->setDate(date);
395 } else {
396 mDatePicker->setDate(QDate::currentDate());
397 }
398 mDateFrame->show();
399 }
400}
401
402
403void KDateEdit::lineEnterPressed()
404{
405 QDate date = readDate();
406
407 if(date.isValid())
408 {
409 // Update the edit. This is needed if the user has entered a
410 // word rather than the actual date.
411 setDate(date);
412 emit(dateChanged(date));
413 emit returnPressed();
414 }
415 else
416 {
417 if ( withoutDp ) {
418 KNotifyClient::beep();
419 } else {
420 if ( !mDateEdit->text().isEmpty() ) {
421 mTextChanged = false;
422 QString text = i18n( "You entered an invalid date!\n Will use current date instead." );
423 if ( KMessageBox::warningContinueCancel( 0, text ) == KMessageBox::Continue ) {
424 setDate( QDate::currentDate() );
425 emit dateChanged( QDate::currentDate() );
426 }
427 }
428 }
429 }
430}
431
432bool KDateEdit::inputIsValid()
433{
434 return readDate().isValid();
435}
436
437QDate KDateEdit::readDate() const
438{
439 QString text = mDateEdit->text();
440 QDate date;
441
442 if (mKeywordMap.contains(text.lower()))
443 {
444 date = QDate::currentDate().addDays(mKeywordMap[text.lower()]);
445 }
446 else
447 {
448 date = KGlobal::locale()->readDate(text);
449 }
450
451 return date;
452}
453
454bool KDateEdit::eventFilter(QObject *, QEvent *e)
455{
456 // We only process the focus out event if the text has changed
457 // since we got focus
458 if ((e->type() == QEvent::FocusOut) && mTextChanged)
459 {
460 lineEnterPressed();
461 mTextChanged = false;
462 }
463 // switch dateFormShort by double klick with mouse
464 else if (e->type() == QEvent::MouseButtonDblClick)
465 {
466 dateFormShort = dateFormShort?false:true;
467 mDateEdit->setText(KGlobal::locale()->formatDate(readDate(),dateFormShort));
468 }
469 else if (e->type() == QEvent::FocusIn)
470 {
471 maxDay = readDate().day();
472 }
473
474 return false;
475}
476
477void KDateEdit::textChanged(const QString &)
478{
479 if(mHandleInvalid && mDateEdit->text().stripWhiteSpace().isEmpty()) {
480 QDate date; //invalid date
481 emit(dateChanged(date));
482 } else {
483 mTextChanged = true;
484 }
485 maxDay = readDate().day();
486}