2 This file is part of the KDE libraries
3 Copyright (C) 1997 Tim D. Gilman (tdgilman@best.org)
4 (C) 1998-2001 Mirko Boehm (mirko@kde.org)
5 (C) 2004 Jason Harris (jharris@30doradus.org)
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
25 #include <qtoolbutton.h>
27 #include <qpopupmenu.h>
31 #include <kiconloader.h>
34 #include <knotifyclient.h>
36 #include "extdatepicker.h"
37 #include "extdatetbl.h"
38 #include "extdatepicker.moc"
40 // Week numbers are defined by ISO 8601
41 // See http://www.merlyn.demon.co.uk/weekinfo.htm for details
43 class ExtDatePicker::ExtDatePickerPrivate
46 ExtDatePickerPrivate() : closeButton(0L), selectWeek(0L), todayButton(0),
47 navigationLayout(0), calendar(0) {}
49 void fillWeeksCombo(const ExtDate
&date
);
51 QToolButton
*closeButton
;
52 QComboBox
*selectWeek
;
53 QToolButton
*todayButton
;
54 QBoxLayout
*navigationLayout
;
55 ExtCalendarSystem
*calendar
;
58 void ExtDatePicker::fillWeeksCombo(const ExtDate
&date
)
60 // every year can have a different number of weeks
62 //must remain commented unless ExtDate stuff gets added to kdelibs
63 // const ExtCalendarSystem * calendar = KGlobal::locale()->calendar();
65 // it could be that we had 53,1..52 and now 1..53 which is the same number but different
66 // so always fill with new values
68 d
->selectWeek
->clear();
70 // We show all week numbers for all weeks between first day of year to last day of year
71 // This of course can be a list like 53,1,2..52
73 ExtDate
day(date
.year(), 1, 1);
74 int lastMonth
= d
->calendar
->monthsInYear(day
);
75 ExtDate
lastDay(date
.year(), lastMonth
, d
->calendar
->daysInMonth(ExtDate(date
.year(), lastMonth
, 1)));
77 for (; day
<= lastDay
; day
= d
->calendar
->addDays(day
, 7 /*calendar->daysOfWeek()*/) )
80 QString week
= i18n("Week %1").arg(d
->calendar
->weekNumber(day
, &year
));
81 if ( year
!= date
.year() ) week
+= "*"; // show that this is a week from a different year
82 d
->selectWeek
->insertItem(week
);
86 ExtDatePicker::ExtDatePicker(QWidget
*parent
, ExtDate dt
, const char *name
)
92 ExtDatePicker::ExtDatePicker(QWidget
*parent
, ExtDate dt
, const char *name
, WFlags f
)
93 : QFrame(parent
,name
, f
)
98 ExtDatePicker::ExtDatePicker( QWidget
*parent
, const char *name
)
101 init( ExtDate::currentDate() );
104 void ExtDatePicker::init( const ExtDate
&dt
)
106 d
= new ExtDatePickerPrivate();
108 d
->calendar
= new ExtCalendarSystemGregorian();
110 QBoxLayout
* topLayout
= new QVBoxLayout(this);
112 d
->navigationLayout
= new QHBoxLayout(topLayout
);
113 d
->navigationLayout
->addStretch();
114 yearBackward
= new QToolButton(this);
115 yearBackward
->setAutoRaise(true);
116 d
->navigationLayout
->addWidget(yearBackward
);
117 monthBackward
= new QToolButton(this);
118 monthBackward
->setAutoRaise(true);
119 d
->navigationLayout
->addWidget(monthBackward
);
120 d
->navigationLayout
->addSpacing(KDialog::spacingHint());
122 selectMonth
= new QToolButton(this);
123 selectMonth
->setAutoRaise(true);
124 d
->navigationLayout
->addWidget(selectMonth
);
125 selectYear
= new QToolButton(this);
126 selectYear
->setToggleButton(true);
127 selectYear
->setAutoRaise(true);
128 d
->navigationLayout
->addWidget(selectYear
);
129 d
->navigationLayout
->addSpacing(KDialog::spacingHint());
131 monthForward
= new QToolButton(this);
132 monthForward
->setAutoRaise(true);
133 d
->navigationLayout
->addWidget(monthForward
);
134 yearForward
= new QToolButton(this);
135 yearForward
->setAutoRaise(true);
136 d
->navigationLayout
->addWidget(yearForward
);
137 d
->navigationLayout
->addStretch();
139 line
= new KLineEdit(this);
140 val
= new ExtDateValidator(this);
141 table
= new ExtDateTable(this);
142 fontsize
= KGlobalSettings::generalFont().pointSize();
144 fontsize
= QFontInfo(KGlobalSettings::generalFont()).pointSize();
146 fontsize
++; // Make a little bigger
148 d
->selectWeek
= new QComboBox(false, this); // read only week selection
149 d
->todayButton
= new QToolButton(this);
150 d
->todayButton
->setIconSet(SmallIconSet("today"));
152 QToolTip::add(yearForward
, i18n("Next year"));
153 QToolTip::add(yearBackward
, i18n("Previous year"));
154 QToolTip::add(monthForward
, i18n("Next month"));
155 QToolTip::add(monthBackward
, i18n("Previous month"));
156 QToolTip::add(d
->selectWeek
, i18n("Select a week"));
157 QToolTip::add(selectMonth
, i18n("Select a month"));
158 QToolTip::add(selectYear
, i18n("Select a year"));
159 QToolTip::add(d
->todayButton
, i18n("Select the current day"));
162 setFontSize(fontsize
);
163 line
->setValidator(val
);
164 line
->installEventFilter( this );
165 if ( QApplication::reverseLayout() )
167 yearForward
->setIconSet(BarIconSet(QString::fromLatin1("2leftarrow")));
168 yearBackward
->setIconSet(BarIconSet(QString::fromLatin1("2rightarrow")));
169 monthForward
->setIconSet(BarIconSet(QString::fromLatin1("1leftarrow")));
170 monthBackward
->setIconSet(BarIconSet(QString::fromLatin1("1rightarrow")));
174 yearForward
->setIconSet(BarIconSet(QString::fromLatin1("2rightarrow")));
175 yearBackward
->setIconSet(BarIconSet(QString::fromLatin1("2leftarrow")));
176 monthForward
->setIconSet(BarIconSet(QString::fromLatin1("1rightarrow")));
177 monthBackward
->setIconSet(BarIconSet(QString::fromLatin1("1leftarrow")));
179 connect(table
, SIGNAL(dateChanged(const ExtDate
&)), SLOT(dateChangedSlot(const ExtDate
&)));
180 connect(table
, SIGNAL(tableClicked()), SLOT(tableClickedSlot()));
181 connect(monthForward
, SIGNAL(clicked()), SLOT(monthForwardClicked()));
182 connect(monthBackward
, SIGNAL(clicked()), SLOT(monthBackwardClicked()));
183 connect(yearForward
, SIGNAL(clicked()), SLOT(yearForwardClicked()));
184 connect(yearBackward
, SIGNAL(clicked()), SLOT(yearBackwardClicked()));
185 connect(d
->selectWeek
, SIGNAL(activated(int)), SLOT(weekSelected(int)));
186 connect(d
->todayButton
, SIGNAL(clicked()), SLOT(todayButtonClicked()));
187 connect(selectMonth
, SIGNAL(clicked()), SLOT(selectMonthClicked()));
188 connect(selectYear
, SIGNAL(toggled(bool)), SLOT(selectYearClicked()));
189 connect(line
, SIGNAL(returnPressed()), SLOT(lineEnterPressed()));
193 topLayout
->addWidget(table
);
195 QBoxLayout
* bottomLayout
= new QHBoxLayout(topLayout
);
196 bottomLayout
->addWidget(d
->todayButton
);
197 bottomLayout
->addWidget(line
);
198 bottomLayout
->addWidget(d
->selectWeek
);
201 dateChangedSlot(dt
); // needed because table emits changed only when newDate != oldDate
204 ExtDatePicker::~ExtDatePicker()
210 ExtDatePicker::eventFilter(QObject
*o
, QEvent
*e
)
212 if ( e
->type() == QEvent::KeyPress
) {
213 QKeyEvent
*k
= (QKeyEvent
*)e
;
215 if ( (k
->key() == Qt::Key_Prior
) ||
216 (k
->key() == Qt::Key_Next
) ||
217 (k
->key() == Qt::Key_Up
) ||
218 (k
->key() == Qt::Key_Down
) )
220 QApplication::sendEvent( table
, e
);
222 return true; // eat event
225 return QFrame::eventFilter( o
, e
);
229 ExtDatePicker::resizeEvent(QResizeEvent
* e
)
231 QWidget::resizeEvent(e
);
235 ExtDatePicker::dateChangedSlot(const ExtDate
&date
)
237 kdDebug(298) << "ExtDatePicker::dateChangedSlot: date changed (" << date
.year() << "/" << date
.month() << "/" << date
.day() << ")." << endl
;
240 //must remain commented unless ExtDate gets added to kdelibs
241 // const ExtCalendarSystem * calendar = KGlobal::locale()->calendar();
243 // line->setText(KGlobal::locale()->formatDate(date, true));
244 line
->setText( date
.toString( KGlobal::locale()->dateFormatShort() ) );
245 selectMonth
->setText(d
->calendar
->monthName(date
, false));
246 fillWeeksCombo(date
);
248 // calculate the item num in the week combo box; normalize selected day so as if 1.1. is the first day of the week
249 ExtDate
firstDay(date
.year(), 1, 1);
250 d
->selectWeek
->setCurrentItem((d
->calendar
->dayOfYear(date
) + d
->calendar
->dayOfWeek(firstDay
) - 2) / 7/*calendar->daysInWeek()*/);
252 selectYear
->setText(d
->calendar
->yearString(date
, false));
254 emit(dateChanged(date
));
258 ExtDatePicker::tableClickedSlot()
260 kdDebug(298) << "ExtDatePicker::tableClickedSlot: table clicked." << endl
;
261 emit(dateSelected(table
->getDate()));
262 emit(tableClicked());
266 ExtDatePicker::getDate() const
268 return table
->getDate();
272 ExtDatePicker::date() const
274 return table
->getDate();
278 ExtDatePicker::setDate(const ExtDate
& date
)
282 table
->setDate(date
); // this also emits dateChanged() which then calls our dateChangedSlot()
287 kdDebug(298) << "ExtDatePicker::setDate: refusing to set invalid date." << endl
;
293 ExtDatePicker::monthForwardClicked()
296 // temp = KGlobal::locale()->calendar()->addMonths( table->getDate(), 1 );
297 temp
= d
->calendar
->addMonths( table
->getDate(), 1 );
302 ExtDatePicker::monthBackwardClicked()
305 // temp = KGlobal::locale()->calendar()->addMonths( table->getDate(), -1 );
306 temp
= d
->calendar
->addMonths( table
->getDate(), -1 );
311 ExtDatePicker::yearForwardClicked()
314 // temp = KGlobal::locale()->calendar()->addYears( table->getDate(), 1 );
315 temp
= d
->calendar
->addYears( table
->getDate(), 1 );
320 ExtDatePicker::yearBackwardClicked()
323 // temp = KGlobal::locale()->calendar()->addYears( table->getDate(), -1 );
324 temp
= d
->calendar
->addYears( table
->getDate(), -1 );
328 void ExtDatePicker::selectWeekClicked() {} // ### in 3.2 obsolete; kept for binary compatibility
331 ExtDatePicker::weekSelected(int week
)
333 // const ExtCalendarSystem * calendar = KGlobal::locale()->calendar();
335 ExtDate date
= table
->getDate();
336 int year
= d
->calendar
->year(date
);
338 d
->calendar
->setYMD(date
, year
, 1, 1); // first day of selected year
340 // calculate the first day in the selected week (day 1 is first day of week)
341 date
= d
->calendar
->addDays(date
, week
* 7/*calendar->daysOfWeek()*/ -d
->calendar
->dayOfWeek(date
) + 1);
347 ExtDatePicker::selectMonthClicked()
349 // every year can have different month names (in some calendar systems)
350 // const ExtCalendarSystem * calendar = KGlobal::locale()->calendar();
351 ExtDate date
= table
->getDate();
352 int i
, month
, months
= d
->calendar
->monthsInYear(date
);
354 QPopupMenu
popup(selectMonth
);
356 for (i
= 1; i
<= months
; i
++)
357 popup
.insertItem(d
->calendar
->monthName(i
, d
->calendar
->year(date
)), i
);
359 popup
.setActiveItem(d
->calendar
->month(date
) - 1);
361 if ( (month
= popup
.exec(selectMonth
->mapToGlobal(QPoint(0, 0)), d
->calendar
->month(date
) - 1)) == -1 ) return; // canceled
363 int day
= d
->calendar
->day(date
);
364 // ----- construct a valid date in this month:
365 //date.setYMD(date.year(), month, 1);
366 //date.setYMD(date.year(), month, QMIN(day, date.daysInMonth()));
367 d
->calendar
->setYMD(date
, d
->calendar
->year(date
), month
,
368 QMIN(day
, d
->calendar
->daysInMonth(date
)));
369 // ----- set this month
374 ExtDatePicker::selectYearClicked()
376 // const ExtCalendarSystem * calendar = KGlobal::locale()->calendar();
378 if (selectYear
->state() == QButton::Off
)
384 KPopupFrame
* popup
= new KPopupFrame(this);
385 ExtDateInternalYearSelector
* picker
= new ExtDateInternalYearSelector(popup
);
387 picker
->resize(picker
->sizeHint());
388 popup
->setMainWidget(picker
);
389 connect(picker
, SIGNAL(closeMe(int)), popup
, SLOT(close(int)));
391 if(popup
->exec(selectYear
->mapToGlobal(QPoint(0, selectMonth
->height()))))
396 year
=picker
->getYear();
397 date
=table
->getDate();
398 day
=d
->calendar
->day(date
);
399 // ----- construct a valid date in this month:
400 //date.setYMD(year, date.month(), 1);
401 //date.setYMD(year, date.month(), QMIN(day, date.daysInMonth()));
402 d
->calendar
->setYMD(date
, year
, d
->calendar
->month(date
),
403 QMIN(day
, d
->calendar
->daysInMonth(date
)));
404 // ----- set this month
407 KNotifyClient::beep();
413 ExtDatePicker::setEnabled(bool enable
)
415 QWidget
*widgets
[]= {
416 yearForward
, yearBackward
, monthForward
, monthBackward
,
417 selectMonth
, selectYear
,
418 line
, table
, d
->selectWeek
, d
->todayButton
};
419 const int Size
=sizeof(widgets
)/sizeof(widgets
[0]);
422 for(count
=0; count
<Size
; ++count
)
424 widgets
[count
]->setEnabled(enable
);
429 ExtDatePicker::lineEnterPressed()
433 if(val
->date(line
->text(), temp
)==QValidator::Acceptable
)
435 kdDebug(298) << "ExtDatePicker::lineEnterPressed: valid date entered." << endl
;
436 emit(dateEntered(temp
));
439 KNotifyClient::beep();
440 kdDebug(298) << "ExtDatePicker::lineEnterPressed: invalid date entered." << endl
;
445 ExtDatePicker::todayButtonClicked()
447 setDate(ExtDate::currentDate());
451 ExtDatePicker::sizeHint() const
453 return QWidget::sizeHint();
457 ExtDatePicker::setFontSize(int s
)
459 QWidget
*buttons
[]= {
467 const int NoOfButtons
=sizeof(buttons
)/sizeof(buttons
[0]);
473 for(count
=0; count
<NoOfButtons
; ++count
)
475 font
=buttons
[count
]->font();
476 font
.setPointSize(s
);
477 buttons
[count
]->setFont(font
);
479 QFontMetrics
metrics(selectMonth
->fontMetrics());
481 for (int i
= 1; ; ++i
)
483 QString str
= d
->calendar
->monthName(i
,
484 d
->calendar
->year(table
->getDate()), false);
485 if (str
.isNull()) break;
486 r
=metrics
.boundingRect(str
);
487 maxMonthRect
.setWidth(QMAX(r
.width(), maxMonthRect
.width()));
488 maxMonthRect
.setHeight(QMAX(r
.height(), maxMonthRect
.height()));
491 QSize metricBound
= style().sizeFromContents(QStyle::CT_ToolButton
,
494 selectMonth
->setMinimumSize(metricBound
);
496 table
->setFontSize(s
);
500 ExtDatePicker::setCloseButton( bool enable
)
502 if ( enable
== (d
->closeButton
!= 0L) )
506 d
->closeButton
= new QToolButton( this );
507 d
->closeButton
->setAutoRaise(true);
508 d
->navigationLayout
->addSpacing(KDialog::spacingHint());
509 d
->navigationLayout
->addWidget(d
->closeButton
);
510 QToolTip::add(d
->closeButton
, i18n("Close"));
511 d
->closeButton
->setPixmap( SmallIcon("remove") );
512 connect( d
->closeButton
, SIGNAL( clicked() ),
513 topLevelWidget(), SLOT( close() ) );
516 delete d
->closeButton
;
523 bool ExtDatePicker::hasCloseButton() const
525 return (d
->closeButton
!= 0L);
528 void ExtDatePicker::virtual_hook( int /*id*/, void* /*data*/ )
529 { /*BASE::virtual_hook( id, data );*/ }