moved kdeaccessibility kdeaddons kdeadmin kdeartwork kdebindings kdeedu kdegames...
[kdeedu.git] / libkdeedu / extdate / extdatepicker.cpp
blob78e5f0d24ff32817e44ad9cfb41ae148ae3617b4
1 /* -*- C++ -*-
2 This file is part of the KDE libraries
3 Copyright (C) 1997 Tim D. Gilman (tdgilman@best.org)
4 (C) 1998-2001 Mirko Boehm (mirko@kde.org)
5 (C) 2004 Jason Harris (jharris@30doradus.org)
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
23 #include <qlayout.h>
24 #include <qstyle.h>
25 #include <qtoolbutton.h>
26 #include <qtooltip.h>
27 #include <qpopupmenu.h>
29 #include <kdialog.h>
30 #include <klocale.h>
31 #include <kiconloader.h>
32 #include <ktoolbar.h>
33 #include <kdebug.h>
34 #include <knotifyclient.h>
36 #include "extdatepicker.h"
37 #include "extdatetbl.h"
38 #include "extdatepicker.moc"
40 // Week numbers are defined by ISO 8601
41 // See http://www.merlyn.demon.co.uk/weekinfo.htm for details
43 class ExtDatePicker::ExtDatePickerPrivate
45 public:
46 ExtDatePickerPrivate() : closeButton(0L), selectWeek(0L), todayButton(0),
47 navigationLayout(0), calendar(0) {}
49 void fillWeeksCombo(const ExtDate &date);
51 QToolButton *closeButton;
52 QComboBox *selectWeek;
53 QToolButton *todayButton;
54 QBoxLayout *navigationLayout;
55 ExtCalendarSystem *calendar;
58 void ExtDatePicker::fillWeeksCombo(const ExtDate &date)
60 // every year can have a different number of weeks
62 //must remain commented unless ExtDate stuff gets added to kdelibs
63 // const ExtCalendarSystem * calendar = KGlobal::locale()->calendar();
65 // it could be that we had 53,1..52 and now 1..53 which is the same number but different
66 // so always fill with new values
68 d->selectWeek->clear();
70 // We show all week numbers for all weeks between first day of year to last day of year
71 // This of course can be a list like 53,1,2..52
73 ExtDate day(date.year(), 1, 1);
74 int lastMonth = d->calendar->monthsInYear(day);
75 ExtDate lastDay(date.year(), lastMonth, d->calendar->daysInMonth(ExtDate(date.year(), lastMonth, 1)));
77 for (; day <= lastDay; day = d->calendar->addDays(day, 7 /*calendar->daysOfWeek()*/) )
79 int year = 0;
80 QString week = i18n("Week %1").arg(d->calendar->weekNumber(day, &year));
81 if ( year != date.year() ) week += "*"; // show that this is a week from a different year
82 d->selectWeek->insertItem(week);
86 ExtDatePicker::ExtDatePicker(QWidget *parent, ExtDate dt, const char *name)
87 : QFrame(parent,name)
89 init( dt );
92 ExtDatePicker::ExtDatePicker(QWidget *parent, ExtDate dt, const char *name, WFlags f)
93 : QFrame(parent,name, f)
95 init( dt );
98 ExtDatePicker::ExtDatePicker( QWidget *parent, const char *name )
99 : QFrame(parent,name)
101 init( ExtDate::currentDate() );
104 void ExtDatePicker::init( const ExtDate &dt )
106 d = new ExtDatePickerPrivate();
108 d->calendar = new ExtCalendarSystemGregorian();
110 QBoxLayout * topLayout = new QVBoxLayout(this);
112 d->navigationLayout = new QHBoxLayout(topLayout);
113 d->navigationLayout->addStretch();
114 yearBackward = new QToolButton(this);
115 yearBackward->setAutoRaise(true);
116 d->navigationLayout->addWidget(yearBackward);
117 monthBackward = new QToolButton(this);
118 monthBackward ->setAutoRaise(true);
119 d->navigationLayout->addWidget(monthBackward);
120 d->navigationLayout->addSpacing(KDialog::spacingHint());
122 selectMonth = new QToolButton(this);
123 selectMonth ->setAutoRaise(true);
124 d->navigationLayout->addWidget(selectMonth);
125 selectYear = new QToolButton(this);
126 selectYear->setToggleButton(true);
127 selectYear->setAutoRaise(true);
128 d->navigationLayout->addWidget(selectYear);
129 d->navigationLayout->addSpacing(KDialog::spacingHint());
131 monthForward = new QToolButton(this);
132 monthForward ->setAutoRaise(true);
133 d->navigationLayout->addWidget(monthForward);
134 yearForward = new QToolButton(this);
135 yearForward ->setAutoRaise(true);
136 d->navigationLayout->addWidget(yearForward);
137 d->navigationLayout->addStretch();
139 line = new KLineEdit(this);
140 val = new ExtDateValidator(this);
141 table = new ExtDateTable(this);
142 fontsize = KGlobalSettings::generalFont().pointSize();
143 if (fontsize == -1)
144 fontsize = QFontInfo(KGlobalSettings::generalFont()).pointSize();
146 fontsize++; // Make a little bigger
148 d->selectWeek = new QComboBox(false, this); // read only week selection
149 d->todayButton = new QToolButton(this);
150 d->todayButton->setIconSet(SmallIconSet("today"));
152 QToolTip::add(yearForward, i18n("Next year"));
153 QToolTip::add(yearBackward, i18n("Previous year"));
154 QToolTip::add(monthForward, i18n("Next month"));
155 QToolTip::add(monthBackward, i18n("Previous month"));
156 QToolTip::add(d->selectWeek, i18n("Select a week"));
157 QToolTip::add(selectMonth, i18n("Select a month"));
158 QToolTip::add(selectYear, i18n("Select a year"));
159 QToolTip::add(d->todayButton, i18n("Select the current day"));
161 // -----
162 setFontSize(fontsize);
163 line->setValidator(val);
164 line->installEventFilter( this );
165 if ( QApplication::reverseLayout() )
167 yearForward->setIconSet(BarIconSet(QString::fromLatin1("2leftarrow")));
168 yearBackward->setIconSet(BarIconSet(QString::fromLatin1("2rightarrow")));
169 monthForward->setIconSet(BarIconSet(QString::fromLatin1("1leftarrow")));
170 monthBackward->setIconSet(BarIconSet(QString::fromLatin1("1rightarrow")));
172 else
174 yearForward->setIconSet(BarIconSet(QString::fromLatin1("2rightarrow")));
175 yearBackward->setIconSet(BarIconSet(QString::fromLatin1("2leftarrow")));
176 monthForward->setIconSet(BarIconSet(QString::fromLatin1("1rightarrow")));
177 monthBackward->setIconSet(BarIconSet(QString::fromLatin1("1leftarrow")));
179 connect(table, SIGNAL(dateChanged(const ExtDate&)), SLOT(dateChangedSlot(const ExtDate&)));
180 connect(table, SIGNAL(tableClicked()), SLOT(tableClickedSlot()));
181 connect(monthForward, SIGNAL(clicked()), SLOT(monthForwardClicked()));
182 connect(monthBackward, SIGNAL(clicked()), SLOT(monthBackwardClicked()));
183 connect(yearForward, SIGNAL(clicked()), SLOT(yearForwardClicked()));
184 connect(yearBackward, SIGNAL(clicked()), SLOT(yearBackwardClicked()));
185 connect(d->selectWeek, SIGNAL(activated(int)), SLOT(weekSelected(int)));
186 connect(d->todayButton, SIGNAL(clicked()), SLOT(todayButtonClicked()));
187 connect(selectMonth, SIGNAL(clicked()), SLOT(selectMonthClicked()));
188 connect(selectYear, SIGNAL(toggled(bool)), SLOT(selectYearClicked()));
189 connect(line, SIGNAL(returnPressed()), SLOT(lineEnterPressed()));
190 table->setFocus();
193 topLayout->addWidget(table);
195 QBoxLayout * bottomLayout = new QHBoxLayout(topLayout);
196 bottomLayout->addWidget(d->todayButton);
197 bottomLayout->addWidget(line);
198 bottomLayout->addWidget(d->selectWeek);
200 table->setDate(dt);
201 dateChangedSlot(dt); // needed because table emits changed only when newDate != oldDate
204 ExtDatePicker::~ExtDatePicker()
206 delete d;
209 bool
210 ExtDatePicker::eventFilter(QObject *o, QEvent *e )
212 if ( e->type() == QEvent::KeyPress ) {
213 QKeyEvent *k = (QKeyEvent *)e;
215 if ( (k->key() == Qt::Key_Prior) ||
216 (k->key() == Qt::Key_Next) ||
217 (k->key() == Qt::Key_Up) ||
218 (k->key() == Qt::Key_Down) )
220 QApplication::sendEvent( table, e );
221 table->setFocus();
222 return true; // eat event
225 return QFrame::eventFilter( o, e );
228 void
229 ExtDatePicker::resizeEvent(QResizeEvent* e)
231 QWidget::resizeEvent(e);
234 void
235 ExtDatePicker::dateChangedSlot(const ExtDate &date)
237 kdDebug(298) << "ExtDatePicker::dateChangedSlot: date changed (" << date.year() << "/" << date.month() << "/" << date.day() << ")." << endl;
240 //must remain commented unless ExtDate gets added to kdelibs
241 // const ExtCalendarSystem * calendar = KGlobal::locale()->calendar();
243 // line->setText(KGlobal::locale()->formatDate(date, true));
244 line->setText( date.toString( KGlobal::locale()->dateFormatShort() ) );
245 selectMonth->setText(d->calendar->monthName(date, false));
246 fillWeeksCombo(date);
248 // calculate the item num in the week combo box; normalize selected day so as if 1.1. is the first day of the week
249 ExtDate firstDay(date.year(), 1, 1);
250 d->selectWeek->setCurrentItem((d->calendar->dayOfYear(date) + d->calendar->dayOfWeek(firstDay) - 2) / 7/*calendar->daysInWeek()*/);
252 selectYear->setText(d->calendar->yearString(date, false));
254 emit(dateChanged(date));
257 void
258 ExtDatePicker::tableClickedSlot()
260 kdDebug(298) << "ExtDatePicker::tableClickedSlot: table clicked." << endl;
261 emit(dateSelected(table->getDate()));
262 emit(tableClicked());
265 const ExtDate&
266 ExtDatePicker::getDate() const
268 return table->getDate();
271 const ExtDate &
272 ExtDatePicker::date() const
274 return table->getDate();
277 bool
278 ExtDatePicker::setDate(const ExtDate& date)
280 if(date.isValid())
282 table->setDate(date); // this also emits dateChanged() which then calls our dateChangedSlot()
283 return true;
285 else
287 kdDebug(298) << "ExtDatePicker::setDate: refusing to set invalid date." << endl;
288 return false;
292 void
293 ExtDatePicker::monthForwardClicked()
295 ExtDate temp;
296 // temp = KGlobal::locale()->calendar()->addMonths( table->getDate(), 1 );
297 temp = d->calendar->addMonths( table->getDate(), 1 );
298 setDate( temp );
301 void
302 ExtDatePicker::monthBackwardClicked()
304 ExtDate temp;
305 // temp = KGlobal::locale()->calendar()->addMonths( table->getDate(), -1 );
306 temp = d->calendar->addMonths( table->getDate(), -1 );
307 setDate( temp );
310 void
311 ExtDatePicker::yearForwardClicked()
313 ExtDate temp;
314 // temp = KGlobal::locale()->calendar()->addYears( table->getDate(), 1 );
315 temp = d->calendar->addYears( table->getDate(), 1 );
316 setDate( temp );
319 void
320 ExtDatePicker::yearBackwardClicked()
322 ExtDate temp;
323 // temp = KGlobal::locale()->calendar()->addYears( table->getDate(), -1 );
324 temp = d->calendar->addYears( table->getDate(), -1 );
325 setDate( temp );
328 void ExtDatePicker::selectWeekClicked() {} // ### in 3.2 obsolete; kept for binary compatibility
330 void
331 ExtDatePicker::weekSelected(int week)
333 // const ExtCalendarSystem * calendar = KGlobal::locale()->calendar();
335 ExtDate date = table->getDate();
336 int year = d->calendar->year(date);
338 d->calendar->setYMD(date, year, 1, 1); // first day of selected year
340 // calculate the first day in the selected week (day 1 is first day of week)
341 date = d->calendar->addDays(date, week * 7/*calendar->daysOfWeek()*/ -d->calendar->dayOfWeek(date) + 1);
343 setDate(date);
346 void
347 ExtDatePicker::selectMonthClicked()
349 // every year can have different month names (in some calendar systems)
350 // const ExtCalendarSystem * calendar = KGlobal::locale()->calendar();
351 ExtDate date = table->getDate();
352 int i, month, months = d->calendar->monthsInYear(date);
354 QPopupMenu popup(selectMonth);
356 for (i = 1; i <= months; i++)
357 popup.insertItem(d->calendar->monthName(i, d->calendar->year(date)), i);
359 popup.setActiveItem(d->calendar->month(date) - 1);
361 if ( (month = popup.exec(selectMonth->mapToGlobal(QPoint(0, 0)), d->calendar->month(date) - 1)) == -1 ) return; // canceled
363 int day = d->calendar->day(date);
364 // ----- construct a valid date in this month:
365 //date.setYMD(date.year(), month, 1);
366 //date.setYMD(date.year(), month, QMIN(day, date.daysInMonth()));
367 d->calendar->setYMD(date, d->calendar->year(date), month,
368 QMIN(day, d->calendar->daysInMonth(date)));
369 // ----- set this month
370 setDate(date);
373 void
374 ExtDatePicker::selectYearClicked()
376 // const ExtCalendarSystem * calendar = KGlobal::locale()->calendar();
378 if (selectYear->state() == QButton::Off)
380 return;
383 int year;
384 KPopupFrame* popup = new KPopupFrame(this);
385 ExtDateInternalYearSelector* picker = new ExtDateInternalYearSelector(popup);
386 // -----
387 picker->resize(picker->sizeHint());
388 popup->setMainWidget(picker);
389 connect(picker, SIGNAL(closeMe(int)), popup, SLOT(close(int)));
390 picker->setFocus();
391 if(popup->exec(selectYear->mapToGlobal(QPoint(0, selectMonth->height()))))
393 ExtDate date;
394 int day;
395 // -----
396 year=picker->getYear();
397 date=table->getDate();
398 day=d->calendar->day(date);
399 // ----- construct a valid date in this month:
400 //date.setYMD(year, date.month(), 1);
401 //date.setYMD(year, date.month(), QMIN(day, date.daysInMonth()));
402 d->calendar->setYMD(date, year, d->calendar->month(date),
403 QMIN(day, d->calendar->daysInMonth(date)));
404 // ----- set this month
405 setDate(date);
406 } else {
407 KNotifyClient::beep();
409 delete popup;
412 void
413 ExtDatePicker::setEnabled(bool enable)
415 QWidget *widgets[]= {
416 yearForward, yearBackward, monthForward, monthBackward,
417 selectMonth, selectYear,
418 line, table, d->selectWeek, d->todayButton };
419 const int Size=sizeof(widgets)/sizeof(widgets[0]);
420 int count;
421 // -----
422 for(count=0; count<Size; ++count)
424 widgets[count]->setEnabled(enable);
428 void
429 ExtDatePicker::lineEnterPressed()
431 ExtDate temp;
432 // -----
433 if(val->date(line->text(), temp)==QValidator::Acceptable)
435 kdDebug(298) << "ExtDatePicker::lineEnterPressed: valid date entered." << endl;
436 emit(dateEntered(temp));
437 setDate(temp);
438 } else {
439 KNotifyClient::beep();
440 kdDebug(298) << "ExtDatePicker::lineEnterPressed: invalid date entered." << endl;
444 void
445 ExtDatePicker::todayButtonClicked()
447 setDate(ExtDate::currentDate());
450 QSize
451 ExtDatePicker::sizeHint() const
453 return QWidget::sizeHint();
456 void
457 ExtDatePicker::setFontSize(int s)
459 QWidget *buttons[]= {
460 // yearBackward,
461 // monthBackward,
462 selectMonth,
463 selectYear,
464 // monthForward,
465 // yearForward
467 const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]);
468 int count;
469 QFont font;
470 QRect r;
471 // -----
472 fontsize=s;
473 for(count=0; count<NoOfButtons; ++count)
475 font=buttons[count]->font();
476 font.setPointSize(s);
477 buttons[count]->setFont(font);
479 QFontMetrics metrics(selectMonth->fontMetrics());
481 for (int i = 1; ; ++i)
483 QString str = d->calendar->monthName(i,
484 d->calendar->year(table->getDate()), false);
485 if (str.isNull()) break;
486 r=metrics.boundingRect(str);
487 maxMonthRect.setWidth(QMAX(r.width(), maxMonthRect.width()));
488 maxMonthRect.setHeight(QMAX(r.height(), maxMonthRect.height()));
491 QSize metricBound = style().sizeFromContents(QStyle::CT_ToolButton,
492 selectMonth,
493 maxMonthRect);
494 selectMonth->setMinimumSize(metricBound);
496 table->setFontSize(s);
499 void
500 ExtDatePicker::setCloseButton( bool enable )
502 if ( enable == (d->closeButton != 0L) )
503 return;
505 if ( enable ) {
506 d->closeButton = new QToolButton( this );
507 d->closeButton->setAutoRaise(true);
508 d->navigationLayout->addSpacing(KDialog::spacingHint());
509 d->navigationLayout->addWidget(d->closeButton);
510 QToolTip::add(d->closeButton, i18n("Close"));
511 d->closeButton->setPixmap( SmallIcon("remove") );
512 connect( d->closeButton, SIGNAL( clicked() ),
513 topLevelWidget(), SLOT( close() ) );
515 else {
516 delete d->closeButton;
517 d->closeButton = 0L;
520 updateGeometry();
523 bool ExtDatePicker::hasCloseButton() const
525 return (d->closeButton != 0L);
528 void ExtDatePicker::virtual_hook( int /*id*/, void* /*data*/ )
529 { /*BASE::virtual_hook( id, data );*/ }