| # kdeui Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# kdatepicker.cpp

    00001 /*  -*- C++ -*-
    00002     This file is part of the KDE libraries
    00003     Copyright (C) 1997 Tim D. Gilman (tdgilman@best.org)
    00004               (C) 1998-2001 Mirko Boehm (mirko@kde.org)
    00005     This library is free software; you can redistribute it and/or
    00006     modify it under the terms of the GNU Library General Public
    00007     License as published by the Free Software Foundation; either
    00008     version 2 of the License, or (at your option) any later version.
    00009
    00010     This library is distributed in the hope that it will be useful,
    00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00013     Library General Public License for more details.
    00014
    00015     You should have received a copy of the GNU Library General Public License
    00016     along with this library; see the file COPYING.LIB.  If not, write to
    00017     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00018     Boston, MA 02111-1307, USA.
    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); // set button texts
    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; // eat event
    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     // ----- calculate button row height:
    00157     for(count=0; count<NoOfButtons; ++count) {
    00158         if ( buttons[count] ) { // closeButton may be 0L
    00159             sizes[count]=buttons[count]->sizeHint();
    00160             buttonHeight=QMAX(buttonHeight, sizes[count].height());
    00161         }
    00162         else
    00163             sizes[count] = QSize(0,0); // closeButton
    00164     }
    00165
    00166     // ----- calculate size of the month button:
    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     // ----- place the buttons:
    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     // ----- place the line edit for direct input:
    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     // ----- adjust the table:
    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       // ----- find the first selectable day in this week (hacky solution :)
    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       // ----- set this date
    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       // ----- construct a valid date in this month:
    00323       date.setYMD(date.year(), month, 1);
    00324       date.setYMD(date.year(), month, QMIN(day, date.daysInMonth()));
    00325       // ----- set this month
    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       // ----- construct a valid date in this month:
    00353       date.setYMD(year, date.month(), 1);
    00354       date.setYMD(year, date.month(), QMIN(day, date.daysInMonth()));
    00355       // ----- set this month
    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   // ----- store the size hints:
    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   // ----- calculate width hint:
    00429   cx=QMAX(cx, tableSize.width()); // line edit ignored
    00430   // ----- calculate height hint:
    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     // yearBackward,
    00440     // monthBackward,
    00441     selectMonth,
    00442     selectYear,
    00443     // monthForward,
    00444     // yearForward
    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     { // maxMonthRect is used by sizeHint()
    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     // Calculate ISO 8601 week number (taken from glibc/Gnumeric)
    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     /* Does date belong to last week of previous year? */
    00509     if ((week == 0) && (jan1wday > 4 /*THURSDAY*/)) {
    00510         QDate tmpdate=QDate(year-1,12,31);
    00511         return weekOfYear(tmpdate);
    00512     }
    00513
    00514     if ((jan1wday <= 4 /*THURSDAY*/) && (jan1wday > 1 /*MONDAY*/))
    00515         week++;
    00516
    00517     if (week == 53) {
    00518         nextjan1date=QDate(year+1, 1, 1);
    00519         nextjan1wday = nextjan1date.dayOfWeek();
    00520         if (nextjan1wday <= 4 /*THURSDAY*/)
    00521             week = 1;
    00522     }
    00523
    00524     return week;
    00525 }
    00526
    00527 void KDatePicker::virtual_hook( int /*id*/, void* /*data*/ )
    00528 { /*BASE::virtual_hook( id, data );*/ }
    00529

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:56:25 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001