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 <qlayout.h>
00022 #include <qframe.h>
00023 #include <qpainter.h>
00024 #include <qdialog.h>
00025 #include <qstyle.h>
00026 #include <qtoolbutton.h>
00027 #include <qcombobox.h>
00028 #include <qtooltip.h>
00029 #include <qfont.h>
00030 #include <qvalidator.h>
00031 #include <qpopupmenu.h>
00032 
00033 #include "kdatepicker.h"
00034 #include <kglobal.h>
00035 #include <kapplication.h>
00036 #include <kdialog.h>
00037 #include <klocale.h>
00038 #include <kiconloader.h>
00039 #include <ktoolbar.h>
00040 #include <klineedit.h>
00041 #include <kdebug.h>
00042 #include <knotifyclient.h>
00043 #include <kcalendarsystem.h>
00044 
00045 #include "kdatetbl.h"
00046 #include "kdatepicker.moc"
00047 
00048 // Week numbers are defined by ISO 8601
00049 // See http://www.merlyn.demon.co.uk/weekinfo.htm for details
00050 
00051 class KDatePicker::KDatePickerPrivate
00052 {
00053 public:
00054     KDatePickerPrivate() : closeButton(0L), selectWeek(0L), todayButton(0), navigationLayout(0) {}
00055 
00056     void fillWeeksCombo(const QDate &date);
00057 
00058     QToolButton *closeButton;
00059     QComboBox *selectWeek;
00060     QToolButton *todayButton;
00061     QBoxLayout *navigationLayout;
00062 };
00063 
00064 void KDatePicker::fillWeeksCombo(const QDate &date)
00065 {
00066   // every year can have a different number of weeks
00067   const KCalendarSystem * calendar = KGlobal::locale()->calendar();
00068 
00069   // it could be that we had 53,1..52 and now 1..53 which is the same number but different
00070   // so always fill with new values
00071 
00072   d->selectWeek->clear();
00073 
00074   // We show all week numbers for all weeks between first day of year to last day of year
00075   // This of course can be a list like 53,1,2..52
00076 
00077   QDate day(date.year(), 1, 1);
00078   int lastMonth = calendar->monthsInYear(day);
00079   QDate lastDay(date.year(), lastMonth, calendar->daysInMonth(QDate(date.year(), lastMonth, 1)));
00080 
00081   for (; day <= lastDay; day = calendar->addDays(day, 7 /*calendar->daysOfWeek()*/) )
00082   {
00083     int year = 0;
00084     QString week = i18n("Week %1").arg(calendar->weekNumber(day, &year));
00085     if ( year != date.year() ) week += "*";  // show that this is a week from a different year
00086     d->selectWeek->insertItem(week);
00087   }
00088 }
00089 
00090 KDatePicker::KDatePicker(QWidget *parent, QDate dt, const char *name)
00091   : QFrame(parent,name)
00092 {
00093   init( dt );
00094 }
00095 
00096 KDatePicker::KDatePicker(QWidget *parent, QDate dt, const char *name, WFlags f)
00097   : QFrame(parent,name, f)
00098 {
00099   init( dt );
00100 }
00101 
00102 KDatePicker::KDatePicker( QWidget *parent, const char *name )
00103   : QFrame(parent,name)
00104 {
00105   init( QDate::currentDate() );
00106 }
00107 
00108 void KDatePicker::init( const QDate &dt )
00109 {
00110   d = new KDatePickerPrivate();
00111 
00112   QBoxLayout * topLayout = new QVBoxLayout(this);
00113 
00114   d->navigationLayout = new QHBoxLayout(topLayout);
00115   d->navigationLayout->addStretch();
00116   yearBackward = new QToolButton(this);
00117   yearBackward->setAutoRaise(true);
00118   d->navigationLayout->addWidget(yearBackward);
00119   monthBackward = new QToolButton(this);
00120   monthBackward ->setAutoRaise(true);
00121   d->navigationLayout->addWidget(monthBackward);
00122   d->navigationLayout->addSpacing(KDialog::spacingHint());
00123 
00124   selectMonth = new QToolButton(this);
00125   selectMonth ->setAutoRaise(true);
00126   d->navigationLayout->addWidget(selectMonth);
00127   selectYear = new QToolButton(this);
00128   selectYear->setToggleButton(true);
00129   selectYear->setAutoRaise(true);
00130   d->navigationLayout->addWidget(selectYear);
00131   d->navigationLayout->addSpacing(KDialog::spacingHint());
00132 
00133   monthForward = new QToolButton(this);
00134   monthForward ->setAutoRaise(true);
00135   d->navigationLayout->addWidget(monthForward);
00136   yearForward = new QToolButton(this);
00137   yearForward ->setAutoRaise(true);
00138   d->navigationLayout->addWidget(yearForward);
00139   d->navigationLayout->addStretch();
00140 
00141   line = new KLineEdit(this);
00142   val = new KDateValidator(this);
00143   table = new KDateTable(this);
00144   fontsize = KGlobalSettings::generalFont().pointSize();
00145   if (fontsize == -1)
00146      fontsize = QFontInfo(KGlobalSettings::generalFont()).pointSize();
00147 
00148   fontsize++; // Make a little bigger
00149 
00150   d->selectWeek = new QComboBox(false, this);  // read only week selection
00151   d->todayButton = new QToolButton(this);
00152   d->todayButton->setIconSet(SmallIconSet("today"));
00153 
00154   QToolTip::add(yearForward, i18n("Next year"));
00155   QToolTip::add(yearBackward, i18n("Previous year"));
00156   QToolTip::add(monthForward, i18n("Next month"));
00157   QToolTip::add(monthBackward, i18n("Previous month"));
00158   QToolTip::add(d->selectWeek, i18n("Select a week"));
00159   QToolTip::add(selectMonth, i18n("Select a month"));
00160   QToolTip::add(selectYear, i18n("Select a year"));
00161   QToolTip::add(d->todayButton, i18n("Select the current day"));
00162 
00163   // -----
00164   setFontSize(fontsize);
00165   line->setValidator(val);
00166   line->installEventFilter( this );
00167   if (  QApplication::reverseLayout() )
00168   {
00169       yearForward->setIconSet(BarIconSet(QString::fromLatin1("2leftarrow")));
00170       yearBackward->setIconSet(BarIconSet(QString::fromLatin1("2rightarrow")));
00171       monthForward->setIconSet(BarIconSet(QString::fromLatin1("1leftarrow")));
00172       monthBackward->setIconSet(BarIconSet(QString::fromLatin1("1rightarrow")));
00173   }
00174   else
00175   {
00176       yearForward->setIconSet(BarIconSet(QString::fromLatin1("2rightarrow")));
00177       yearBackward->setIconSet(BarIconSet(QString::fromLatin1("2leftarrow")));
00178       monthForward->setIconSet(BarIconSet(QString::fromLatin1("1rightarrow")));
00179       monthBackward->setIconSet(BarIconSet(QString::fromLatin1("1leftarrow")));
00180   }
00181   connect(table, SIGNAL(dateChanged(QDate)), SLOT(dateChangedSlot(QDate)));
00182   connect(table, SIGNAL(tableClicked()), SLOT(tableClickedSlot()));
00183   connect(monthForward, SIGNAL(clicked()), SLOT(monthForwardClicked()));
00184   connect(monthBackward, SIGNAL(clicked()), SLOT(monthBackwardClicked()));
00185   connect(yearForward, SIGNAL(clicked()), SLOT(yearForwardClicked()));
00186   connect(yearBackward, SIGNAL(clicked()), SLOT(yearBackwardClicked()));
00187   connect(d->selectWeek, SIGNAL(activated(int)), SLOT(weekSelected(int)));
00188   connect(d->todayButton, SIGNAL(clicked()), SLOT(todayButtonClicked()));
00189   connect(selectMonth, SIGNAL(clicked()), SLOT(selectMonthClicked()));
00190   connect(selectYear, SIGNAL(toggled(bool)), SLOT(selectYearClicked()));
00191   connect(line, SIGNAL(returnPressed()), SLOT(lineEnterPressed()));
00192   table->setFocus();
00193 
00194 
00195   topLayout->addWidget(table);
00196 
00197   QBoxLayout * bottomLayout = new QHBoxLayout(topLayout);
00198   bottomLayout->addWidget(d->todayButton);
00199   bottomLayout->addWidget(line);
00200   bottomLayout->addWidget(d->selectWeek);
00201 
00202   table->setDate(dt);
00203   dateChangedSlot(dt);  // needed because table emits changed only when newDate != oldDate
00204 }
00205 
00206 KDatePicker::~KDatePicker()
00207 {
00208   delete d;
00209 }
00210 
00211 bool
00212 KDatePicker::eventFilter(QObject *o, QEvent *e )
00213 {
00214    if ( e->type() == QEvent::KeyPress ) {
00215       QKeyEvent *k = (QKeyEvent *)e;
00216 
00217       if ( (k->key() == Qt::Key_Prior) ||
00218            (k->key() == Qt::Key_Next)  ||
00219            (k->key() == Qt::Key_Up)    ||
00220            (k->key() == Qt::Key_Down) )
00221        {
00222           QApplication::sendEvent( table, e );
00223           table->setFocus();
00224           return true; // eat event
00225        }
00226    }
00227    return QFrame::eventFilter( o, e );
00228 }
00229 
00230 void
00231 KDatePicker::resizeEvent(QResizeEvent* e)
00232 {
00233   QWidget::resizeEvent(e);
00234 }
00235 
00236 void
00237 KDatePicker::dateChangedSlot(QDate date)
00238 {
00239     kdDebug(298) << "KDatePicker::dateChangedSlot: date changed (" << date.year() << "/" << date.month() << "/" << date.day() << ")." << endl;
00240 
00241     const KCalendarSystem * calendar = KGlobal::locale()->calendar();
00242 
00243     line->setText(KGlobal::locale()->formatDate(date, true));
00244     selectMonth->setText(calendar->monthName(date, false));
00245     fillWeeksCombo(date);
00246 
00247     // calculate the item num in the week combo box; normalize selected day so as if 1.1. is the first day of the week
00248     QDate firstDay(date.year(), 1, 1);
00249     d->selectWeek->setCurrentItem((calendar->dayOfYear(date) + calendar->dayOfWeek(firstDay) - 2) / 7/*calendar->daysInWeek()*/);
00250 
00251     selectYear->setText(calendar->yearString(date, false));
00252 
00253     emit(dateChanged(date));
00254 }
00255 
00256 void
00257 KDatePicker::tableClickedSlot()
00258 {
00259   kdDebug(298) << "KDatePicker::tableClickedSlot: table clicked." << endl;
00260   emit(dateSelected(table->getDate()));
00261   emit(tableClicked());
00262 }
00263 
00264 const QDate&
00265 KDatePicker::getDate() const
00266 {
00267   return table->getDate();
00268 }
00269 
00270 const QDate &
00271 KDatePicker::date() const
00272 {
00273     return table->getDate();
00274 }
00275 
00276 bool
00277 KDatePicker::setDate(const QDate& date)
00278 {
00279     if(date.isValid())
00280     {
00281         table->setDate(date);  // this also emits dateChanged() which then calls our dateChangedSlot()
00282         return true;
00283     }
00284     else
00285     {
00286         kdDebug(298) << "KDatePicker::setDate: refusing to set invalid date." << endl;
00287         return false;
00288     }
00289 }
00290 
00291 void
00292 KDatePicker::monthForwardClicked()
00293 {
00294     QDate temp;
00295     temp = KGlobal::locale()->calendar()->addMonths( table->getDate(), 1 );
00296 
00297     setDate( temp );
00298 }
00299 
00300 void
00301 KDatePicker::monthBackwardClicked()
00302 {
00303     QDate temp;
00304     temp = KGlobal::locale()->calendar()->addMonths( table->getDate(), -1 );
00305 
00306     setDate( temp );
00307 }
00308 
00309 void
00310 KDatePicker::yearForwardClicked()
00311 {
00312     QDate temp;
00313     temp = KGlobal::locale()->calendar()->addYears( table->getDate(), 1 );
00314 
00315     setDate( temp );
00316 }
00317 
00318 void
00319 KDatePicker::yearBackwardClicked()
00320 {
00321     QDate temp;
00322     temp = KGlobal::locale()->calendar()->addYears( table->getDate(), -1 );
00323 
00324     setDate( temp );
00325 }
00326 
00327 void KDatePicker::selectWeekClicked() {}  // ### in 3.2 obsolete; kept for binary compatibility
00328 
00329 void
00330 KDatePicker::weekSelected(int week)
00331 {
00332   const KCalendarSystem * calendar = KGlobal::locale()->calendar();
00333 
00334   QDate date = table->getDate();
00335   int year = calendar->year(date);
00336 
00337   calendar->setYMD(date, year, 1, 1);  // first day of selected year
00338 
00339   // calculate the first day in the selected week (day 1 is first day of week)
00340   date = calendar->addDays(date, week * 7/*calendar->daysOfWeek()*/ -calendar->dayOfWeek(date) + 1);
00341 
00342   setDate(date);
00343 }
00344 
00345 void
00346 KDatePicker::selectMonthClicked()
00347 {
00348   // every year can have different month names (in some calendar systems)
00349   const KCalendarSystem * calendar = KGlobal::locale()->calendar();
00350   QDate date = table->getDate();
00351   int i, month, months = calendar->monthsInYear(date);
00352 
00353   QPopupMenu popup(selectMonth);
00354 
00355   for (i = 1; i <= months; i++)
00356     popup.insertItem(calendar->monthName(i, calendar->year(date)), i);
00357 
00358   popup.setActiveItem(calendar->month(date) - 1);
00359 
00360   if ( (month = popup.exec(selectMonth->mapToGlobal(QPoint(0, 0)), calendar->month(date) - 1)) == -1 ) return;  // canceled
00361 
00362   int day = calendar->day(date);
00363   // ----- construct a valid date in this month:
00364   //date.setYMD(date.year(), month, 1);
00365   //date.setYMD(date.year(), month, QMIN(day, date.daysInMonth()));
00366   calendar->setYMD(date, calendar->year(date), month,
00367                    QMIN(day, calendar->daysInMonth(date)));
00368   // ----- set this month
00369   setDate(date);
00370 }
00371 
00372 void
00373 KDatePicker::selectYearClicked()
00374 {
00375   const KCalendarSystem * calendar = KGlobal::locale()->calendar();
00376 
00377   if (selectYear->state() == QButton::Off)
00378   {
00379     return;
00380   }
00381 
00382   int year;
00383   KPopupFrame* popup = new KPopupFrame(this);
00384   KDateInternalYearSelector* picker = new KDateInternalYearSelector(popup);
00385   // -----
00386   picker->resize(picker->sizeHint());
00387   popup->setMainWidget(picker);
00388   connect(picker, SIGNAL(closeMe(int)), popup, SLOT(close(int)));
00389   picker->setFocus();
00390   if(popup->exec(selectYear->mapToGlobal(QPoint(0, selectMonth->height()))))
00391     {
00392       QDate date;
00393       int day;
00394       // -----
00395       year=picker->getYear();
00396       date=table->getDate();
00397       day=calendar->day(date);
00398       // ----- construct a valid date in this month:
00399       //date.setYMD(year, date.month(), 1);
00400       //date.setYMD(year, date.month(), QMIN(day, date.daysInMonth()));
00401       calendar->setYMD(date, year, calendar->month(date),
00402                        QMIN(day, calendar->daysInMonth(date)));
00403       // ----- set this month
00404       setDate(date);
00405     } else {
00406       KNotifyClient::beep();
00407     }
00408   delete popup;
00409 }
00410 
00411 void
00412 KDatePicker::setEnabled(bool enable)
00413 {
00414   QWidget *widgets[]= {
00415     yearForward, yearBackward, monthForward, monthBackward,
00416     selectMonth, selectYear,
00417     line, table, d->selectWeek, d->todayButton };
00418   const int Size=sizeof(widgets)/sizeof(widgets[0]);
00419   int count;
00420   // -----
00421   for(count=0; count<Size; ++count)
00422     {
00423       widgets[count]->setEnabled(enable);
00424     }
00425 }
00426 
00427 void
00428 KDatePicker::lineEnterPressed()
00429 {
00430   QDate temp;
00431   // -----
00432   if(val->date(line->text(), temp)==QValidator::Acceptable)
00433     {
00434         kdDebug(298) << "KDatePicker::lineEnterPressed: valid date entered." << endl;
00435         emit(dateEntered(temp));
00436         setDate(temp);
00437     } else {
00438       KNotifyClient::beep();
00439       kdDebug(298) << "KDatePicker::lineEnterPressed: invalid date entered." << endl;
00440     }
00441 }
00442 
00443 void
00444 KDatePicker::todayButtonClicked()
00445 {
00446   setDate(QDate::currentDate());
00447 }
00448 
00449 QSize
00450 KDatePicker::sizeHint() const
00451 {
00452   return QWidget::sizeHint();
00453 }
00454 
00455 void
00456 KDatePicker::setFontSize(int s)
00457 {
00458   QWidget *buttons[]= {
00459     // yearBackward,
00460     // monthBackward,
00461     selectMonth,
00462     selectYear,
00463     // monthForward,
00464     // yearForward
00465   };
00466   const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]);
00467   int count;
00468   QFont font;
00469   QRect r;
00470   // -----
00471   fontsize=s;
00472   for(count=0; count<NoOfButtons; ++count)
00473     {
00474       font=buttons[count]->font();
00475       font.setPointSize(s);
00476       buttons[count]->setFont(font);
00477     }
00478   QFontMetrics metrics(selectMonth->fontMetrics());
00479 
00480   for (int i = 1; ; ++i)
00481     {
00482       QString str = KGlobal::locale()->calendar()->monthName(i,
00483          KGlobal::locale()->calendar()->year(table->getDate()), false);
00484       if (str.isNull()) break;
00485       r=metrics.boundingRect(str);
00486       maxMonthRect.setWidth(QMAX(r.width(), maxMonthRect.width()));
00487       maxMonthRect.setHeight(QMAX(r.height(),  maxMonthRect.height()));
00488     }
00489 
00490   QSize metricBound = style().sizeFromContents(QStyle::CT_ToolButton,
00491                                                selectMonth,
00492                                                maxMonthRect);
00493   selectMonth->setMinimumSize(metricBound);
00494 
00495   table->setFontSize(s);
00496 }
00497 
00498 void
00499 KDatePicker::setCloseButton( bool enable )
00500 {
00501     if ( enable == (d->closeButton != 0L) )
00502         return;
00503 
00504     if ( enable ) {
00505         d->closeButton = new QToolButton( this );
00506         d->closeButton->setAutoRaise(true);
00507         d->navigationLayout->addSpacing(KDialog::spacingHint());
00508         d->navigationLayout->addWidget(d->closeButton);
00509         QToolTip::add(d->closeButton, i18n("Close"));
00510         d->closeButton->setPixmap( SmallIcon("remove") );
00511         connect( d->closeButton, SIGNAL( clicked() ),
00512                  topLevelWidget(), SLOT( close() ) );
00513     }
00514     else {
00515         delete d->closeButton;
00516         d->closeButton = 0L;
00517     }
00518 
00519     updateGeometry();
00520 }
00521 
00522 bool KDatePicker::hasCloseButton() const
00523 {
00524     return (d->closeButton != 0L);
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 kdeui Library Version 3.3.90.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 30 10:11:59 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003