/* -*- C++ -*- This file is part of the KDE libraries Copyright (C) 1997 Tim D. Gilman (tdgilman@best.org) (C) 1998-2001 Mirko Boehm (mirko@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "kdatepicker.h" #include #include #include #include #include #include #include #include #include #include #include "kdatetbl.h" #include "kdatepicker.moc" // Week numbers are defined by ISO 8601 // See http://www.merlyn.demon.co.uk/weekinfo.htm for details class KDatePicker::KDatePickerPrivate { public: KDatePickerPrivate() : closeButton(0L), selectWeek(0L), todayButton(0), navigationLayout(0) {} void fillWeeksCombo(const TQDate &date); TQToolButton *closeButton; TQComboBox *selectWeek; TQToolButton *todayButton; TQBoxLayout *navigationLayout; }; void KDatePicker::fillWeeksCombo(const TQDate &date) { // every year can have a different number of weeks const KCalendarSystem * calendar = TDEGlobal::locale()->calendar(); // it could be that we had 53,1..52 and now 1..53 which is the same number but different // so always fill with new values d->selectWeek->clear(); // We show all week numbers for all weeks between first day of year to last day of year // This of course can be a list like 53,1,2..52 TQDate day; int year = calendar->year(date); calendar->setYMD(day, year, 1, 1); int lastMonth = calendar->monthsInYear(day); TQDate lastDay, firstDayOfLastMonth; calendar->setYMD(firstDayOfLastMonth, year, lastMonth, 1); calendar->setYMD(lastDay, year, lastMonth, calendar->daysInMonth(firstDayOfLastMonth)); for (; day <= lastDay ; day = calendar->addDays(day, 7 /*calendar->daysOfWeek()*/) ) { TQString week = i18n("Week %1").arg(calendar->weekNumber(day, &year)); if ( year != calendar->year(day) ) week += "*"; // show that this is a week from a different year d->selectWeek->insertItem(week); // make sure that the week of the lastDay is always inserted: in Chinese calendar // system, this is not always the case if(day < lastDay && day.daysTo(lastDay) < 7 && calendar->weekNumber(day) != calendar->weekNumber(lastDay)) day = TQT_TQDATE_OBJECT(lastDay.addDays(-7)); } } KDatePicker::KDatePicker(TQWidget *parent, TQDate dt, const char *name) : TQFrame(parent,name) { init( dt ); } KDatePicker::KDatePicker(TQWidget *parent, TQDate dt, const char *name, WFlags f) : TQFrame(parent,name, f) { init( dt ); } KDatePicker::KDatePicker( TQWidget *parent, const char *name ) : TQFrame(parent,name) { init( TQDate::currentDate() ); } void KDatePicker::init( const TQDate &dt ) { d = new KDatePickerPrivate(); TQBoxLayout * topLayout = new TQVBoxLayout(this); d->navigationLayout = new TQHBoxLayout(topLayout); d->navigationLayout->addStretch(); yearBackward = new TQToolButton(this); yearBackward->setAutoRaise(true); d->navigationLayout->addWidget(yearBackward); monthBackward = new TQToolButton(this); monthBackward ->setAutoRaise(true); d->navigationLayout->addWidget(monthBackward); d->navigationLayout->addSpacing(KDialog::spacingHint()); selectMonth = new TQToolButton(this); selectMonth ->setAutoRaise(true); d->navigationLayout->addWidget(selectMonth); selectYear = new TQToolButton(this); selectYear->setToggleButton(true); selectYear->setAutoRaise(true); d->navigationLayout->addWidget(selectYear); d->navigationLayout->addSpacing(KDialog::spacingHint()); monthForward = new TQToolButton(this); monthForward ->setAutoRaise(true); d->navigationLayout->addWidget(monthForward); yearForward = new TQToolButton(this); yearForward ->setAutoRaise(true); d->navigationLayout->addWidget(yearForward); d->navigationLayout->addStretch(); line = new KLineEdit(this); val = new KDateValidator(this); table = new KDateTable(this); fontsize = TDEGlobalSettings::generalFont().pointSize(); if (fontsize == -1) fontsize = TQFontInfo(TDEGlobalSettings::generalFont()).pointSize(); fontsize++; // Make a little bigger d->selectWeek = new TQComboBox(false, this); // read only week selection d->todayButton = new TQToolButton(this); d->todayButton->setIconSet(SmallIconSet("today")); TQToolTip::add(yearForward, i18n("Next year")); TQToolTip::add(yearBackward, i18n("Previous year")); TQToolTip::add(monthForward, i18n("Next month")); TQToolTip::add(monthBackward, i18n("Previous month")); TQToolTip::add(d->selectWeek, i18n("Select a week")); TQToolTip::add(selectMonth, i18n("Select a month")); TQToolTip::add(selectYear, i18n("Select a year")); TQToolTip::add(d->todayButton, i18n("Select the current day")); // ----- setFontSize(fontsize); line->setValidator(val); line->installEventFilter( this ); if ( TQApplication::reverseLayout() ) { yearForward->setIconSet(BarIconSet(TQString::fromLatin1("2leftarrow"))); yearBackward->setIconSet(BarIconSet(TQString::fromLatin1("2rightarrow"))); monthForward->setIconSet(BarIconSet(TQString::fromLatin1("1leftarrow"))); monthBackward->setIconSet(BarIconSet(TQString::fromLatin1("1rightarrow"))); } else { yearForward->setIconSet(BarIconSet(TQString::fromLatin1("2rightarrow"))); yearBackward->setIconSet(BarIconSet(TQString::fromLatin1("2leftarrow"))); monthForward->setIconSet(BarIconSet(TQString::fromLatin1("1rightarrow"))); monthBackward->setIconSet(BarIconSet(TQString::fromLatin1("1leftarrow"))); } connect(table, TQT_SIGNAL(dateChanged(TQDate)), TQT_SLOT(dateChangedSlot(TQDate))); connect(table, TQT_SIGNAL(tableClicked()), TQT_SLOT(tableClickedSlot())); connect(monthForward, TQT_SIGNAL(clicked()), TQT_SLOT(monthForwardClicked())); connect(monthBackward, TQT_SIGNAL(clicked()), TQT_SLOT(monthBackwardClicked())); connect(yearForward, TQT_SIGNAL(clicked()), TQT_SLOT(yearForwardClicked())); connect(yearBackward, TQT_SIGNAL(clicked()), TQT_SLOT(yearBackwardClicked())); connect(d->selectWeek, TQT_SIGNAL(activated(int)), TQT_SLOT(weekSelected(int))); connect(d->todayButton, TQT_SIGNAL(clicked()), TQT_SLOT(todayButtonClicked())); connect(selectMonth, TQT_SIGNAL(clicked()), TQT_SLOT(selectMonthClicked())); connect(selectYear, TQT_SIGNAL(toggled(bool)), TQT_SLOT(selectYearClicked())); connect(line, TQT_SIGNAL(returnPressed()), TQT_SLOT(lineEnterPressed())); table->setFocus(); topLayout->addWidget(table); TQBoxLayout * bottomLayout = new TQHBoxLayout(topLayout); bottomLayout->addWidget(d->todayButton); bottomLayout->addWidget(line); bottomLayout->addWidget(d->selectWeek); table->setDate(dt); dateChangedSlot(dt); // needed because table emits changed only when newDate != oldDate } KDatePicker::~KDatePicker() { delete d; } bool KDatePicker::eventFilter(TQObject *o, TQEvent *e ) { if ( e->type() == TQEvent::KeyPress ) { TQKeyEvent *k = (TQKeyEvent *)e; if ( (k->key() == TQt::Key_Prior) || (k->key() == TQt::Key_Next) || (k->key() == Qt::Key_Up) || (k->key() == Qt::Key_Down) ) { TQApplication::sendEvent( table, e ); table->setFocus(); return true; // eat event } } return TQFrame::eventFilter( o, e ); } void KDatePicker::resizeEvent(TQResizeEvent* e) { TQWidget::resizeEvent(e); } void KDatePicker::dateChangedSlot(TQDate date) { kdDebug(298) << "KDatePicker::dateChangedSlot: date changed (" << date.year() << "/" << date.month() << "/" << date.day() << ")." << endl; const KCalendarSystem * calendar = TDEGlobal::locale()->calendar(); line->setText(TDEGlobal::locale()->formatDate(date, true)); selectMonth->setText(calendar->monthName(date, false)); fillWeeksCombo(date); // calculate the item num in the week combo box; normalize selected day so as if 1.1. is the first day of the week TQDate firstDay; calendar->setYMD(firstDay, calendar->year(date), 1, 1); d->selectWeek->setCurrentItem((calendar->dayOfYear(date) + calendar->dayOfWeek(firstDay) - 2) / 7/*calendar->daysInWeek()*/); selectYear->setText(calendar->yearString(date, false)); emit(dateChanged(date)); } void KDatePicker::tableClickedSlot() { kdDebug(298) << "KDatePicker::tableClickedSlot: table clicked." << endl; emit(dateSelected(table->getDate())); emit(tableClicked()); } const TQDate& KDatePicker::getDate() const { return table->getDate(); } const TQDate & KDatePicker::date() const { return table->getDate(); } bool KDatePicker::setDate(const TQDate& date) { if(date.isValid()) { table->setDate(date); // this also emits dateChanged() which then calls our dateChangedSlot() return true; } else { kdDebug(298) << "KDatePicker::setDate: refusing to set invalid date." << endl; return false; } } void KDatePicker::monthForwardClicked() { TQDate temp; temp = TDEGlobal::locale()->calendar()->addMonths( table->getDate(), 1 ); setDate( temp ); } void KDatePicker::monthBackwardClicked() { TQDate temp; temp = TDEGlobal::locale()->calendar()->addMonths( table->getDate(), -1 ); setDate( temp ); } void KDatePicker::yearForwardClicked() { TQDate temp; temp = TDEGlobal::locale()->calendar()->addYears( table->getDate(), 1 ); setDate( temp ); } void KDatePicker::yearBackwardClicked() { TQDate temp; temp = TDEGlobal::locale()->calendar()->addYears( table->getDate(), -1 ); setDate( temp ); } void KDatePicker::selectWeekClicked() {} // ### in 3.2 obsolete; kept for binary compatibility void KDatePicker::weekSelected(int week) { const KCalendarSystem * calendar = TDEGlobal::locale()->calendar(); TQDate date = table->getDate(); int year = calendar->year(date); calendar->setYMD(date, year, 1, 1); // first day of selected year // calculate the first day in the selected week (day 1 is first day of week) date = calendar->addDays(date, week * 7/*calendar->daysOfWeek()*/ -calendar->dayOfWeek(date) + 1); setDate(date); } void KDatePicker::selectMonthClicked() { // every year can have different month names (in some calendar systems) const KCalendarSystem * calendar = TDEGlobal::locale()->calendar(); TQDate date = table->getDate(); int i, month, months = calendar->monthsInYear(date); TQPopupMenu popup(selectMonth); for (i = 1; i <= months; i++) popup.insertItem(calendar->monthName(i, calendar->year(date)), i); popup.setActiveItem(calendar->month(date) - 1); if ( (month = popup.exec(selectMonth->mapToGlobal(TQPoint(0, 0)), calendar->month(date) - 1)) == -1 ) return; // canceled int day = calendar->day(date); // ----- construct a valid date in this month: calendar->setYMD(date, calendar->year(date), month, 1); date = TQT_TQDATE_OBJECT(date.addDays(TQMIN(day, calendar->daysInMonth(date)) - 1)); // ----- set this month setDate(date); } void KDatePicker::selectYearClicked() { const KCalendarSystem * calendar = TDEGlobal::locale()->calendar(); if (selectYear->state() == TQButton::Off) { return; } int year; TDEPopupFrame* popup = new TDEPopupFrame(this); KDateInternalYearSelector* picker = new KDateInternalYearSelector(popup); // ----- picker->resize(picker->sizeHint()); picker->setYear( table->getDate().year() ); picker->selectAll(); popup->setMainWidget(picker); connect(picker, TQT_SIGNAL(closeMe(int)), popup, TQT_SLOT(close(int))); picker->setFocus(); if(popup->exec(selectYear->mapToGlobal(TQPoint(0, selectMonth->height())))) { TQDate date; int day; // ----- year=picker->getYear(); date=table->getDate(); day=calendar->day(date); // ----- construct a valid date in this month: //date.setYMD(year, date.month(), 1); //date.setYMD(year, date.month(), TQMIN(day, date.daysInMonth())); calendar->setYMD(date, year, calendar->month(date), TQMIN(day, calendar->daysInMonth(date))); // ----- set this month setDate(date); } else { KNotifyClient::beep(); } delete popup; TQTimer::singleShot(0, this, TQT_SLOT(ensureSelectYearIsUp())); } void KDatePicker::ensureSelectYearIsUp() { if (!selectYear->isDown()) { selectYear->setOn( false ); } } void KDatePicker::setEnabled(bool enable) { TQWidget *widgets[]= { yearForward, yearBackward, monthForward, monthBackward, selectMonth, selectYear, line, table, d->selectWeek, d->todayButton }; const int Size=sizeof(widgets)/sizeof(widgets[0]); int count; // ----- for(count=0; countsetEnabled(enable); } } void KDatePicker::lineEnterPressed() { TQDate temp; // ----- if(val->date(line->text(), temp)==TQValidator::Acceptable) { kdDebug(298) << "KDatePicker::lineEnterPressed: valid date entered." << endl; emit(dateEntered(temp)); setDate(temp); } else { KNotifyClient::beep(); kdDebug(298) << "KDatePicker::lineEnterPressed: invalid date entered." << endl; } } void KDatePicker::todayButtonClicked() { setDate(TQDate::currentDate()); } TQSize KDatePicker::sizeHint() const { return TQWidget::sizeHint(); } void KDatePicker::setFontSize(int s) { TQWidget *buttons[]= { // yearBackward, // monthBackward, selectMonth, selectYear, // monthForward, // yearForward }; const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]); int count; TQFont font; TQRect r; // ----- fontsize=s; for(count=0; countfont(); font.setPointSize(s); buttons[count]->setFont(font); } TQFontMetrics metrics(selectMonth->fontMetrics()); for (int i = 1; ; ++i) { TQString str = TDEGlobal::locale()->calendar()->monthName(i, TDEGlobal::locale()->calendar()->year(table->getDate()), false); if (str.isNull()) break; r=metrics.boundingRect(str); maxMonthRect.setWidth(TQMAX(r.width(), maxMonthRect.width())); maxMonthRect.setHeight(TQMAX(r.height(), maxMonthRect.height())); } TQSize metricBound = style().tqsizeFromContents(TQStyle::CT_ToolButton, selectMonth, maxMonthRect); selectMonth->setMinimumSize(metricBound); table->setFontSize(s); } void KDatePicker::setCloseButton( bool enable ) { if ( enable == (d->closeButton != 0L) ) return; if ( enable ) { d->closeButton = new TQToolButton( this ); d->closeButton->setAutoRaise(true); d->navigationLayout->addSpacing(KDialog::spacingHint()); d->navigationLayout->addWidget(d->closeButton); TQToolTip::add(d->closeButton, i18n("Close")); d->closeButton->setPixmap( SmallIcon("remove") ); connect( d->closeButton, TQT_SIGNAL( clicked() ), topLevelWidget(), TQT_SLOT( close() ) ); } else { delete d->closeButton; d->closeButton = 0L; } updateGeometry(); } bool KDatePicker::hasCloseButton() const { return (d->closeButton); } void KDatePicker::virtual_hook( int /*id*/, void* /*data*/ ) { /*BASE::virtual_hook( id, data );*/ }