kdeui Library API Documentation

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 
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:20:58 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001