00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kdatepicker.h"
00022 #include <kglobal.h>
00023 #include <kapplication.h>
00024 #include <klocale.h>
00025 #include <kiconloader.h>
00026 #include <qframe.h>
00027 #include <qpainter.h>
00028 #include <qdialog.h>
00029 #include <qstyle.h>
00030 #include <qtoolbutton.h>
00031 #include <qtooltip.h>
00032 #include <qfont.h>
00033 #include <klineedit.h>
00034 #include <qvalidator.h>
00035 #include <kdebug.h>
00036 #include <knotifyclient.h>
00037 #include "kdatetbl.h"
00038 #include "kdatepicker.moc"
00039
00040 class KDatePicker::KDatePickerPrivate
00041 {
00042 public:
00043 KDatePickerPrivate() : closeButton(0L), selectWeek(0L) {}
00044
00045 QToolButton *closeButton;
00046 QToolButton *selectWeek;
00047 };
00048
00049
00050 KDatePicker::KDatePicker(QWidget *parent, QDate dt, const char *name)
00051 : QFrame(parent,name)
00052 {
00053 init( dt );
00054 }
00055
00056 KDatePicker::KDatePicker(QWidget *parent, QDate dt, const char *name, WFlags f)
00057 : QFrame(parent,name, f)
00058 {
00059 init( dt );
00060 }
00061
00062 KDatePicker::KDatePicker( QWidget *parent, const char *name )
00063 : QFrame(parent,name)
00064 {
00065 init( QDate::currentDate() );
00066 }
00067
00068 void KDatePicker::init( const QDate &dt )
00069 {
00070 yearForward = new QToolButton(this);
00071 yearBackward = new QToolButton(this);
00072 monthForward = new QToolButton(this);
00073 monthBackward = new QToolButton(this);
00074 selectMonth = new QToolButton(this);
00075 selectYear = new QToolButton(this);
00076 line = new KLineEdit(this);
00077 val = new KDateValidator(this);
00078 table = new KDateTable(this);
00079 fontsize = 10;
00080
00081 d = new KDatePickerPrivate();
00082 d->selectWeek = new QToolButton( this );
00083
00084 QToolTip::add(yearForward, i18n("Next year"));
00085 QToolTip::add(yearBackward, i18n("Previous year"));
00086 QToolTip::add(monthForward, i18n("Next month"));
00087 QToolTip::add(monthBackward, i18n("Previous month"));
00088 QToolTip::add(d->selectWeek, i18n("Select a week"));
00089 QToolTip::add(selectMonth, i18n("Select a month"));
00090 QToolTip::add(selectYear, i18n("Select a year"));
00091
00092
00093 setFontSize(10);
00094 line->setValidator(val);
00095 line->installEventFilter( this );
00096 yearForward->setPixmap(BarIcon(QString::fromLatin1("2rightarrow")));
00097 yearBackward->setPixmap(BarIcon(QString::fromLatin1("2leftarrow")));
00098 monthForward->setPixmap(BarIcon(QString::fromLatin1("1rightarrow")));
00099 monthBackward->setPixmap(BarIcon(QString::fromLatin1("1leftarrow")));
00100 setDate(dt);
00101 connect(table, SIGNAL(dateChanged(QDate)), SLOT(dateChangedSlot(QDate)));
00102 connect(table, SIGNAL(tableClicked()), SLOT(tableClickedSlot()));
00103 connect(monthForward, SIGNAL(clicked()), SLOT(monthForwardClicked()));
00104 connect(monthBackward, SIGNAL(clicked()), SLOT(monthBackwardClicked()));
00105 connect(yearForward, SIGNAL(clicked()), SLOT(yearForwardClicked()));
00106 connect(yearBackward, SIGNAL(clicked()), SLOT(yearBackwardClicked()));
00107 connect(d->selectWeek, SIGNAL(clicked()), SLOT(selectWeekClicked()));
00108 connect(selectMonth, SIGNAL(clicked()), SLOT(selectMonthClicked()));
00109 connect(selectYear, SIGNAL(clicked()), SLOT(selectYearClicked()));
00110 connect(line, SIGNAL(returnPressed()), SLOT(lineEnterPressed()));
00111 table->setFocus();
00112 }
00113
00114 KDatePicker::~KDatePicker()
00115 {
00116 delete d;
00117 }
00118
00119 bool
00120 KDatePicker::eventFilter(QObject *o, QEvent *e )
00121 {
00122 if ( e->type() == QEvent::KeyPress ) {
00123 QKeyEvent *k = (QKeyEvent *)e;
00124
00125 if ( (k->key() == Qt::Key_Prior) ||
00126 (k->key() == Qt::Key_Next) ||
00127 (k->key() == Qt::Key_Up) ||
00128 (k->key() == Qt::Key_Down) )
00129 {
00130 QApplication::sendEvent( table, e );
00131 table->setFocus();
00132 return TRUE;
00133 }
00134 }
00135 return QFrame::eventFilter( o, e );
00136 }
00137
00138 void
00139 KDatePicker::resizeEvent(QResizeEvent*)
00140 {
00141 QWidget *buttons[] = {
00142 yearBackward,
00143 monthBackward,
00144 selectMonth,
00145 selectYear,
00146 monthForward,
00147 yearForward,
00148 d->closeButton
00149 };
00150 const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]);
00151 QSize sizes[NoOfButtons];
00152 int buttonHeight=0;
00153 int count;
00154 int w;
00155 int x=0;
00156
00157 for(count=0; count<NoOfButtons; ++count) {
00158 if ( buttons[count] ) {
00159 sizes[count]=buttons[count]->sizeHint();
00160 buttonHeight=QMAX(buttonHeight, sizes[count].height());
00161 }
00162 else
00163 sizes[count] = QSize(0,0);
00164 }
00165
00166
00167 for(count=0; count<NoOfButtons; ++count) {
00168 if(buttons[count]==selectMonth) {
00169 QSize metricBound = style().sizeFromContents(QStyle::CT_ToolButton, selectMonth, maxMonthRect);
00170 sizes[count].setWidth(QMAX(metricBound.width(), maxMonthRect.width()+2*QApplication::style().pixelMetric(QStyle::PM_ButtonMargin)));
00171 }
00172 }
00173
00174 x=0;
00175 for(count=0; count<NoOfButtons; ++count)
00176 {
00177 w=sizes[count].width();
00178 if ( buttons[count] )
00179 buttons[count]->setGeometry(x, 0, w, buttonHeight);
00180 x+=w;
00181 }
00182
00183 sizes[0]=line->sizeHint();
00184 int week_width=d->selectWeek->fontMetrics().width(i18n("Week XX"))+((d->closeButton != 0L) ? 50 : 20);
00185 line->setGeometry(0, height()-sizes[0].height(), width()-week_width, sizes[0].height());
00186 d->selectWeek->setGeometry(width()-week_width, height()-sizes[0].height(), week_width, sizes[0].height());
00187
00188 table->setGeometry(0, buttonHeight, width(),
00189 height()-buttonHeight-sizes[0].height());
00190 }
00191
00192 void
00193 KDatePicker::dateChangedSlot(QDate date)
00194 {
00195 kdDebug() << "KDatePicker::dateChangedSlot: date changed (" << date.year() << "/" << date.month() << "/" << date.day() << ")." << endl;
00196 line->setText(KGlobal::locale()->formatDate(date, true));
00197 d->selectWeek->setText(i18n("Week %1").arg(weekOfYear(date)));
00198 selectMonth->setText(KGlobal::locale()->monthName(date.month(), false));
00199 selectYear->setText(date.toString("yyyy"));
00200 emit(dateChanged(date));
00201 }
00202
00203 void
00204 KDatePicker::tableClickedSlot()
00205 {
00206 kdDebug() << "KDatePicker::tableClickedSlot: table clicked." << endl;
00207 emit(dateSelected(table->getDate()));
00208 emit(tableClicked());
00209 }
00210
00211 const QDate&
00212 KDatePicker::getDate() const
00213 {
00214 return table->getDate();
00215 }
00216
00217 const QDate &
00218 KDatePicker::date() const
00219 {
00220 return table->getDate();
00221 }
00222
00223 bool
00224 KDatePicker::setDate(const QDate& date)
00225 {
00226 if(date.isValid()) {
00227 QString temp;
00228
00229 table->setDate(date);
00230 d->selectWeek->setText(i18n("Week %1").arg(weekOfYear(date)));
00231 selectMonth->setText(KGlobal::locale()->monthName(date.month(), false));
00232 temp.setNum(date.year());
00233 selectYear->setText(temp);
00234 line->setText(KGlobal::locale()->formatDate(date, true));
00235 return true;
00236 } else {
00237 kdDebug() << "KDatePicker::setDate: refusing to set invalid date." << endl;
00238 return false;
00239 }
00240 }
00241
00242 void
00243 KDatePicker::monthForwardClicked()
00244 {
00245 setDate( table->getDate().addMonths(1) );
00246 }
00247
00248 void
00249 KDatePicker::monthBackwardClicked()
00250 {
00251 setDate( table->getDate().addMonths(-1) );
00252 }
00253
00254 void
00255 KDatePicker::yearForwardClicked()
00256 {
00257 setDate( table->getDate().addYears(1) );
00258 }
00259
00260 void
00261 KDatePicker::yearBackwardClicked()
00262 {
00263 setDate( table->getDate().addYears(-1) );
00264 }
00265
00266 void
00267 KDatePicker::selectWeekClicked()
00268 {
00269 int week;
00270 KPopupFrame* popup = new KPopupFrame(this);
00271 KDateInternalWeekSelector* picker = new KDateInternalWeekSelector(fontsize, popup);
00272
00273 picker->resize(picker->sizeHint());
00274 popup->setMainWidget(picker);
00275 connect(picker, SIGNAL(closeMe(int)), popup, SLOT(close(int)));
00276 picker->setFocus();
00277 if(popup->exec(d->selectWeek->mapToGlobal(QPoint(0, d->selectWeek->height()))))
00278 {
00279 QDate date;
00280 int year;
00281
00282 week=picker->getWeek();
00283 date=table->getDate();
00284 year=date.year();
00285
00286 date.setYMD(year, 1, 1);
00287 while (weekOfYear(date)>50)
00288 date=date.addDays(1);
00289 while (weekOfYear(date)<week && (week!=53 || (week==53 &&
00290 (weekOfYear(date)!=52 || weekOfYear(date.addDays(1))!=1))))
00291 date=date.addDays(1);
00292 if (week==53 && weekOfYear(date)==52)
00293 while (weekOfYear(date.addDays(-1))==52)
00294 date=date.addDays(-1);
00295
00296 setDate(date);
00297 } else {
00298 KNotifyClient::beep();
00299 }
00300 delete popup;
00301 }
00302
00303 void
00304 KDatePicker::selectMonthClicked()
00305 {
00306 int month;
00307 KPopupFrame* popup = new KPopupFrame(this);
00308 KDateInternalMonthPicker* picker = new KDateInternalMonthPicker(fontsize, popup);
00309
00310 picker->resize(picker->sizeHint());
00311 popup->setMainWidget(picker);
00312 picker->setFocus();
00313 connect(picker, SIGNAL(closeMe(int)), popup, SLOT(close(int)));
00314 if(popup->exec(selectMonth->mapToGlobal(QPoint(0, selectMonth->height()))))
00315 {
00316 QDate date;
00317 int day;
00318
00319 month=picker->getResult();
00320 date=table->getDate();
00321 day=date.day();
00322
00323 date.setYMD(date.year(), month, 1);
00324 date.setYMD(date.year(), month, QMIN(day, date.daysInMonth()));
00325
00326 setDate(date);
00327 } else {
00328 KNotifyClient::beep();
00329 }
00330 delete popup;
00331 }
00332
00333 void
00334 KDatePicker::selectYearClicked()
00335 {
00336 int year;
00337 KPopupFrame* popup = new KPopupFrame(this);
00338 KDateInternalYearSelector* picker = new KDateInternalYearSelector(fontsize, popup);
00339
00340 picker->resize(picker->sizeHint());
00341 popup->setMainWidget(picker);
00342 connect(picker, SIGNAL(closeMe(int)), popup, SLOT(close(int)));
00343 picker->setFocus();
00344 if(popup->exec(selectYear->mapToGlobal(QPoint(0, selectMonth->height()))))
00345 {
00346 QDate date;
00347 int day;
00348
00349 year=picker->getYear();
00350 date=table->getDate();
00351 day=date.day();
00352
00353 date.setYMD(year, date.month(), 1);
00354 date.setYMD(year, date.month(), QMIN(day, date.daysInMonth()));
00355
00356 setDate(date);
00357 } else {
00358 KNotifyClient::beep();
00359 }
00360 delete popup;
00361 }
00362
00363 void
00364 KDatePicker::setEnabled(bool enable)
00365 {
00366 QWidget *widgets[]= {
00367 yearForward, yearBackward, monthForward, monthBackward,
00368 selectMonth, selectYear,
00369 line, table, d->selectWeek };
00370 const int Size=sizeof(widgets)/sizeof(widgets[0]);
00371 int count;
00372
00373 for(count=0; count<Size; ++count)
00374 {
00375 widgets[count]->setEnabled(enable);
00376 }
00377 }
00378
00379 void
00380 KDatePicker::lineEnterPressed()
00381 {
00382 QDate temp;
00383
00384 if(val->date(line->text(), temp)==QValidator::Acceptable)
00385 {
00386 kdDebug() << "KDatePicker::lineEnterPressed: valid date entered." << endl;
00387 emit(dateEntered(temp));
00388 setDate(temp);
00389 } else {
00390 KNotifyClient::beep();
00391 kdDebug() << "KDatePicker::lineEnterPressed: invalid date entered." << endl;
00392 }
00393 }
00394
00395 QSize
00396 KDatePicker::sizeHint() const
00397 {
00398 QSize tableSize=table->sizeHint();
00399 QWidget *buttons[]={
00400 yearBackward,
00401 monthBackward,
00402 selectMonth,
00403 selectYear,
00404 monthForward,
00405 yearForward,
00406 d->closeButton
00407 };
00408 const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]);
00409 QSize sizes[NoOfButtons];
00410 int cx=0, cy=0, count;
00411
00412 for(count=0; count<NoOfButtons; ++count)
00413 {
00414 if ( buttons[count] )
00415 sizes[count]=buttons[count]->sizeHint();
00416 else
00417 sizes[count] = QSize(0,0);
00418
00419 if(buttons[count]==selectMonth)
00420 {
00421 QSize metricBound = style().sizeFromContents(QStyle::CT_ToolButton, selectMonth, maxMonthRect);
00422 cx+=QMAX(metricBound.width(), maxMonthRect.width()+2*QApplication::style().pixelMetric(QStyle::PM_ButtonMargin));
00423 } else {
00424 cx+=sizes[count].width();
00425 }
00426 cy=QMAX(sizes[count].height(), cy);
00427 }
00428
00429 cx=QMAX(cx, tableSize.width());
00430
00431 cy+=tableSize.height()+line->sizeHint().height();
00432 return QSize(cx, cy);
00433 }
00434
00435 void
00436 KDatePicker::setFontSize(int s)
00437 {
00438 QWidget *buttons[]= {
00439
00440
00441 selectMonth,
00442 selectYear,
00443
00444
00445 };
00446 const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]);
00447 int count;
00448 QFont font;
00449 QRect r;
00450
00451 fontsize=s;
00452 for(count=0; count<NoOfButtons; ++count)
00453 {
00454 font=buttons[count]->font();
00455 font.setPointSize(s);
00456 buttons[count]->setFont(font);
00457 }
00458 QFontMetrics metrics(selectMonth->fontMetrics());
00459 for(int i=1; i <= 12; ++i)
00460 {
00461 r=metrics.boundingRect(KGlobal::locale()->monthName(i, false));
00462 maxMonthRect.setWidth(QMAX(r.width(), maxMonthRect.width()));
00463 maxMonthRect.setHeight(QMAX(r.height(), maxMonthRect.height()));
00464 }
00465 table->setFontSize(s);
00466 }
00467
00468 void
00469 KDatePicker::setCloseButton( bool enable )
00470 {
00471 if ( enable == (d->closeButton != 0L) )
00472 return;
00473
00474 if ( enable ) {
00475 d->closeButton = new QToolButton( this );
00476 QToolTip::add(d->closeButton, i18n("Close"));
00477 d->closeButton->setPixmap( SmallIcon("remove") );
00478 connect( d->closeButton, SIGNAL( clicked() ),
00479 topLevelWidget(), SLOT( close() ) );
00480 }
00481 else {
00482 delete d->closeButton;
00483 d->closeButton = 0L;
00484 }
00485
00486 updateGeometry();
00487 }
00488
00489 bool KDatePicker::hasCloseButton() const
00490 {
00491 return (d->closeButton != 0L);
00492 }
00493
00494 int KDatePicker::weekOfYear(QDate date)
00495 {
00496
00497 int year, week, wday, jan1wday, nextjan1wday;
00498 QDate jan1date, nextjan1date;
00499
00500 year=date.year();
00501 wday=date.dayOfWeek();
00502
00503 jan1date=QDate(year,1,1);
00504 jan1wday=jan1date.dayOfWeek();
00505
00506 week = (date.dayOfYear()-1 + jan1wday-1)/7 + ((jan1wday-1) == 0 ? 1 : 0);
00507
00508
00509 if ((week == 0) && (jan1wday > 4 )) {
00510 QDate tmpdate=QDate(year-1,12,31);
00511 return weekOfYear(tmpdate);
00512 }
00513
00514 if ((jan1wday <= 4 ) && (jan1wday > 1 ))
00515 week++;
00516
00517 if (week == 53) {
00518 nextjan1date=QDate(year+1, 1, 1);
00519 nextjan1wday = nextjan1date.dayOfWeek();
00520 if (nextjan1wday <= 4 )
00521 week = 1;
00522 }
00523
00524 return week;
00525 }
00526
00527 void KDatePicker::virtual_hook( int , void* )
00528 { }
00529