F:/KPlato/koffice/kplato/kptcalendarpanel.cc

Aller à la documentation de ce fichier.
00001 /* This file is part of the KDE project
00002     Copyright (C) 1997 Tim D. Gilman (tdgilman@best.org)
00003               (C) 1998-2001 Mirko Boehm (mirko@kde.org)
00004               (C) 2004 Dag Andersen <danders@get2net.dk>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020 */
00021 
00022 /* This is based on KDatePicker. */
00023 
00024 #include "kptcalendarpanel.h"
00025 #include "kptdatetable.h"
00026 #include "kptcalendar.h"
00027 
00028 
00029 #include <kglobal.h>
00030 #include <kapplication.h>
00031 #include <klocale.h>
00032 #include <kcalendarsystem.h>
00033 #include <kiconloader.h>
00034 #include <q3frame.h>
00035 #include <qpainter.h>
00036 #include <qdialog.h>
00037 #include <qstyle.h>
00038 #include <qtoolbutton.h>
00039 #include <QToolTip>
00040 #include <QFont>
00041 //Added by qt3to4:
00042 #include <QKeyEvent>
00043 #include <QEvent>
00044 #include <QResizeEvent>
00045 #include <klineedit.h>
00046 #include <qvalidator.h>
00047 #include <kdebug.h>
00048 #include <knotification.h>
00049 
00050 namespace KPlato
00051 {
00052 
00053 class CalendarPanel::CalendarPanelPrivate
00054 {
00055 public:
00056     CalendarPanelPrivate() : closeButton(0L), selectWeek(0L) {}
00057 
00058     QToolButton *closeButton;
00059     QToolButton *selectWeek;
00060 };
00061 
00062 
00063 CalendarPanel::CalendarPanel(QWidget *parent, QDate dt, const char *name, Qt::WFlags f)
00064   : Q3Frame(parent,name, f)
00065 {
00066   init( dt );
00067 }
00068 
00069 CalendarPanel::CalendarPanel( QWidget *parent, const char *name )
00070   : Q3Frame(parent,name)
00071 {
00072     init( QDate::currentDate() );
00073 }
00074 
00075 void CalendarPanel::init( const QDate &dt )
00076 {
00077   yearForward = new QToolButton(this);
00078   yearBackward = new QToolButton(this);
00079   monthForward = new QToolButton(this);
00080   monthBackward = new QToolButton(this);
00081   selectMonth = new QToolButton(this);
00082   selectYear = new QToolButton(this);
00083   line = new KLineEdit(this);
00084   val = new DateValidator(this);
00085   table = new DateTable(this, dt, "Calendar table", 0);
00086   fontsize = 10;
00087 
00088   d = new CalendarPanelPrivate();
00089   d->selectWeek = new QToolButton( this );
00090 
00091   yearForward->setToolTip( i18n("Next year"));
00092   yearBackward->setToolTip( i18n("Previous year"));
00093   monthForward->setToolTip( i18n("Next month"));
00094   monthBackward->setToolTip( i18n("Previous month"));
00095   d->selectWeek->setToolTip( i18n("Select a week"));
00096   selectMonth->setToolTip( i18n("Select a month"));
00097   selectYear->setToolTip( i18n("Select a year"));
00098 
00099   // -----
00100   setFontSize(10);
00101   line->setValidator(val);
00102   line->installEventFilter( this );
00103   yearForward->setPixmap(BarIcon(QString::fromLatin1("2rightarrow")));
00104   yearBackward->setPixmap(BarIcon(QString::fromLatin1("2leftarrow")));
00105   monthForward->setPixmap(BarIcon(QString::fromLatin1("1rightarrow")));
00106   monthBackward->setPixmap(BarIcon(QString::fromLatin1("1leftarrow")));
00107   setDate(dt); // set button texts
00108   connect(table, SIGNAL(dateChanged(QDate)), SLOT(dateChangedSlot(QDate)));
00109   connect(table, SIGNAL(tableClicked()), SLOT(tableClickedSlot()));
00110   connect(monthForward, SIGNAL(clicked()), SLOT(monthForwardClicked()));
00111   connect(monthBackward, SIGNAL(clicked()), SLOT(monthBackwardClicked()));
00112   connect(yearForward, SIGNAL(clicked()), SLOT(yearForwardClicked()));
00113   connect(yearBackward, SIGNAL(clicked()), SLOT(yearBackwardClicked()));
00114   connect(d->selectWeek, SIGNAL(clicked()), SLOT(selectWeekClicked()));
00115   connect(selectMonth, SIGNAL(clicked()), SLOT(selectMonthClicked()));
00116   connect(selectYear, SIGNAL(clicked()), SLOT(selectYearClicked()));
00117   connect(line, SIGNAL(returnPressed()), SLOT(lineEnterPressed()));
00118 
00119   connect(table, SIGNAL(weekdaySelected(int)), SLOT(slotWeekdaySelected(int)));
00120   connect(table, SIGNAL(weekSelected(int, int)), SLOT(slotWeekSelected(int, int)));
00121   connect(table, SIGNAL(selectionCleared()), SLOT(slotSelectionCleared()));
00122 
00123   table->setFocus();
00124 }
00125 
00126 CalendarPanel::~CalendarPanel()
00127 {
00128   delete d;
00129 }
00130 
00131 bool
00132 CalendarPanel::eventFilter(QObject *o, QEvent *e )
00133 {
00134    if ( e->type() == QEvent::KeyPress ) {
00135       QKeyEvent *k = (QKeyEvent *)e;
00136 
00137       if ( (k->key() == Qt::Key_PageUp) ||
00138            (k->key() == Qt::Key_PageDown)  ||
00139            (k->key() == Qt::Key_Up)    ||
00140            (k->key() == Qt::Key_Down) )
00141        {
00142           QApplication::sendEvent( table, e );
00143           table->setFocus();
00144           return TRUE; // eat event
00145        }
00146    }
00147    return Q3Frame::eventFilter( o, e );
00148 }
00149 
00150 void
00151 CalendarPanel::resizeEvent(QResizeEvent*)
00152 {
00153     QWidget *buttons[] = {
00154         yearBackward,
00155             monthBackward,
00156             selectMonth,
00157             selectYear,
00158             monthForward,
00159             yearForward,
00160             d->closeButton
00161     };
00162     const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]);
00163     QSize sizes[NoOfButtons];
00164     int buttonHeight=0;
00165     int count;
00166     int w=0;
00167     int x=0;
00168     // ----- calculate button row height:
00169     for(count=0; count<NoOfButtons; ++count) {
00170         if ( buttons[count] ) { // closeButton may be 0L
00171             sizes[count]=buttons[count]->sizeHint();
00172             buttonHeight=qMax(buttonHeight, sizes[count].height());
00173         }
00174         else
00175             sizes[count] = QSize(0,0); // closeButton
00176     }
00177 
00178     // ----- calculate size of the month button:
00179     for(count=0; count<NoOfButtons; ++count) {
00180         if(buttons[count]==selectMonth) {
00181             //QSize metricBound = style()->sizeFromContents(QStyle::CT_ToolButton, selectMonth, maxMonthRect);
00182             //sizes[count].setWidth(qMax(metricBound.width(), maxMonthRect.width()+2*QApplication::style()->pixelMetric(QStyle::PM_ButtonMargin)));
00183             sizes[count].setWidth( selectMonth->sizeHint().width() );
00184         }
00185     }
00186     // ----- center buttons
00187     w=0;
00188     for(count=0; count<NoOfButtons; ++count)
00189     {
00190         w +=sizes[count].width();
00191     }
00192     x = (qMax(w, width())-w)/2;
00193 
00194     // ----- place the buttons:
00195     for(count=0; count<NoOfButtons; ++count)
00196     {
00197         w=sizes[count].width();
00198         if ( buttons[count] )
00199             buttons[count]->setGeometry(x, 0, w, buttonHeight);
00200         x+=w;
00201     }
00202     // ----- place the line edit for direct input:
00203     sizes[0]=line->sizeHint();
00204     int week_width=d->selectWeek->fontMetrics().width(i18n("Week XX"))+((d->closeButton != 0L) ? 50 : 20);
00205     line->setGeometry(0, height()-sizes[0].height(), width()-week_width, sizes[0].height());
00206     d->selectWeek->setGeometry(width()-week_width, height()-sizes[0].height(), week_width, sizes[0].height());
00207     // ----- adjust the table:
00208     table->setGeometry(0, buttonHeight, width(),
00209                        height()-buttonHeight-sizes[0].height());
00210 }
00211 
00212 void
00213 CalendarPanel::dateChangedSlot(QDate date)
00214 {
00215     //kDebug() << "CalendarPanel::dateChangedSlot: date changed (" << date.year() << "/" << date.month() << "/" << date.day() << ")." << endl;
00216     line->setText(KGlobal::locale()->formatDate(date, true));
00217     d->selectWeek->setText(i18n("Week %1", weekOfYear(date)));
00218     selectMonth->setText(KGlobal::locale()->calendar()->monthName(date.month(), false));
00219     selectYear->setText(date.toString("yyyy"));
00220     emit(dateChanged(date));
00221 }
00222 
00223 void
00224 CalendarPanel::tableClickedSlot()
00225 {
00226   //kDebug() << "CalendarPanel::tableClickedSlot: table clicked." << endl;
00227   emit(dateSelected(table->getDate()));
00228   emit(tableClicked());
00229 }
00230 
00231 const QDate&
00232 CalendarPanel::getDate() const
00233 {
00234   return table->getDate();
00235 }
00236 
00237 const QDate &
00238 CalendarPanel::date() const
00239 {
00240     return table->getDate();
00241 }
00242 
00243 bool
00244 CalendarPanel::setDate(const QDate& date)
00245 {
00246     if(date.isValid()) {
00247         QString temp;
00248         // -----
00249         table->setDate(date);
00250         d->selectWeek->setText(i18n("Week %1", weekOfYear(date)));
00251         selectMonth->setText(KGlobal::locale()->calendar()->monthName(date.month(), false));
00252         temp.setNum(date.year());
00253         selectYear->setText(temp);
00254         line->setText(KGlobal::locale()->formatDate(date, true));
00255         return true;
00256     } else {
00257         kDebug() << "CalendarPanel::setDate: refusing to set invalid date." << endl;
00258         return false;
00259     }
00260 }
00261 
00262 void
00263 CalendarPanel::monthForwardClicked()
00264 {
00265     setDate( table->getDate().addMonths(1) );
00266 }
00267 
00268 void
00269 CalendarPanel::monthBackwardClicked()
00270 {
00271     setDate( table->getDate().addMonths(-1) );
00272 }
00273 
00274 void
00275 CalendarPanel::yearForwardClicked()
00276 {
00277     setDate( table->getDate().addYears(1) );
00278 }
00279 
00280 void
00281 CalendarPanel::yearBackwardClicked()
00282 {
00283     setDate( table->getDate().addYears(-1) );
00284 }
00285 
00286 void
00287 CalendarPanel::selectWeekClicked()
00288 {
00289   int week;
00290   PopupFrame* popup = new PopupFrame(this);
00291   DateInternalWeekSelector* picker = new DateInternalWeekSelector(fontsize, popup);
00292   // -----
00293   picker->resize(picker->sizeHint());
00294   popup->setMainWidget(picker);
00295   connect(picker, SIGNAL(closeMe(int)), popup, SLOT(close(int)));
00296   picker->setFocus();
00297   if(popup->exec(d->selectWeek->mapToGlobal(QPoint(0, d->selectWeek->height()))))
00298     {
00299       QDate date;
00300       int year;
00301       // -----
00302       week=picker->getWeek();
00303       date=table->getDate();
00304       year=date.year();
00305       // ----- find the first selectable day in this week (hacky solution :)
00306       date.setYMD(year, 1, 1);
00307       while (weekOfYear(date)>50)
00308           date=date.addDays(1);
00309       while (weekOfYear(date)<week && (week!=53 || (week==53 &&
00310             (weekOfYear(date)!=52 || weekOfYear(date.addDays(1))!=1))))
00311           date=date.addDays(1);
00312       if (week==53 && weekOfYear(date)==52)
00313           while (weekOfYear(date.addDays(-1))==52)
00314               date=date.addDays(-1);
00315       // ----- set this date
00316       setDate(date);
00317     } else {
00318          KNotification::beep();
00319     }
00320   delete popup;
00321 }
00322 
00323 void
00324 CalendarPanel::selectMonthClicked()
00325 {
00326   int month;
00327   PopupFrame* popup = new PopupFrame(this);
00328   DateInternalMonthPicker* picker = new DateInternalMonthPicker(fontsize, popup);
00329   // -----
00330   picker->resize(picker->sizeHint());
00331   popup->setMainWidget(picker);
00332   picker->setFocus();
00333   connect(picker, SIGNAL(closeMe(int)), popup, SLOT(close(int)));
00334   if(popup->exec(selectMonth->mapToGlobal(QPoint(0, selectMonth->height()))))
00335     {
00336       QDate date;
00337       int day;
00338       // -----
00339       month=picker->getResult();
00340       date=table->getDate();
00341       day=date.day();
00342       // ----- construct a valid date in this month:
00343       date.setYMD(date.year(), month, 1);
00344       date.setYMD(date.year(), month, qMin(day, date.daysInMonth()));
00345       // ----- set this month
00346       setDate(date);
00347     } else {
00348       KNotification::beep();
00349     }
00350   delete popup;
00351 }
00352 
00353 void
00354 CalendarPanel::selectYearClicked()
00355 {
00356   int year;
00357   PopupFrame* popup = new PopupFrame(this);
00358   DateInternalYearSelector* picker = new DateInternalYearSelector(fontsize, popup);
00359   // -----
00360   picker->resize(picker->sizeHint());
00361   popup->setMainWidget(picker);
00362   connect(picker, SIGNAL(closeMe(int)), popup, SLOT(close(int)));
00363   picker->setFocus();
00364   if(popup->exec(selectYear->mapToGlobal(QPoint(0, selectMonth->height()))))
00365     {
00366       QDate date;
00367       int day;
00368       // -----
00369       year=picker->getYear();
00370       date=table->getDate();
00371       day=date.day();
00372       // ----- construct a valid date in this month:
00373       date.setYMD(year, date.month(), 1);
00374       date.setYMD(year, date.month(), qMin(day, date.daysInMonth()));
00375       // ----- set this month
00376       setDate(date);
00377     } else {
00378       KNotification::beep();
00379     }
00380   delete popup;
00381 }
00382 
00383 void
00384 CalendarPanel::setEnabled(bool enable)
00385 {
00386   QWidget *widgets[]= {
00387     yearForward, yearBackward, monthForward, monthBackward,
00388     selectMonth, selectYear,
00389     line, table, d->selectWeek };
00390   const int Size=sizeof(widgets)/sizeof(widgets[0]);
00391   int count;
00392   // -----
00393   for(count=0; count<Size; ++count)
00394     {
00395       widgets[count]->setEnabled(enable);
00396     }
00397     table->setEnabled(enable);
00398 }
00399 
00400 void
00401 CalendarPanel::lineEnterPressed()
00402 {
00403   QDate temp;
00404   // -----
00405   if(val->date(line->text(), temp)==QValidator::Acceptable)
00406     {
00407         //kDebug() << "CalendarPanel::lineEnterPressed: valid date entered." << endl;
00408         emit(dateEntered(temp));
00409         setDate(temp);
00410     } else {
00411       KNotification::beep();
00412       //kDebug() << "CalendarPanel::lineEnterPressed: invalid date entered." << endl;
00413     }
00414 }
00415 
00416 QSize
00417 CalendarPanel::sizeHint() const
00418 {
00419   QSize tableSize=table->sizeHint();
00420   QWidget *buttons[]={
00421     yearBackward,
00422     monthBackward,
00423     selectMonth,
00424     selectYear,
00425     monthForward,
00426     yearForward,
00427     d->closeButton
00428   };
00429   const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]);
00430   QSize sizes[NoOfButtons];
00431   int cx=0, cy=0, count;
00432   // ----- store the size hints:
00433     for(count=0; count<NoOfButtons; ++count) {
00434         if ( buttons[count] )
00435             sizes[count]=buttons[count]->sizeHint();
00436         else
00437             sizes[count] = QSize(0,0);
00438 
00439         if(buttons[count]==selectMonth) {
00440             // what's this doing differently from sizeHint?
00441             //QSize metricBound = style()->sizeFromContents(QStyle::CT_ToolButton, selectMonth, maxMonthRect);
00442             //cx+=qMax(metricBound.width(), maxMonthRect.width()+2*QApplication::style()->pixelMetric(QStyle::PM_ButtonMargin));
00443             cx += qMax( selectMonth->sizeHint().width(), maxMonthRect.width()+2*QApplication::style()->pixelMetric(QStyle::PM_ButtonMargin) );
00444         } else {
00445                 cx+=sizes[count].width();
00446             }
00447         cy=qMax(sizes[count].height(), cy);
00448     }
00449     // ----- calculate width hint:
00450     cx=qMax(cx, tableSize.width()); // line edit ignored
00451     // ----- calculate height hint:
00452     cy+=tableSize.height()+line->sizeHint().height();
00453     return QSize(cx, cy);
00454 }
00455 
00456 void
00457 CalendarPanel::setFontSize(int s)
00458 {
00459   QWidget *buttons[]= {
00460     // yearBackward,
00461     // monthBackward,
00462     selectMonth,
00463     selectYear,
00464     // monthForward,
00465     // yearForward
00466   };
00467   const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]);
00468   int count;
00469   QFont font;
00470   QRect r;
00471   // -----
00472   fontsize=s;
00473   for(count=0; count<NoOfButtons; ++count)
00474     {
00475       font=buttons[count]->font();
00476       font.setPointSize(s);
00477       buttons[count]->setFont(font);
00478     }
00479   QFontMetrics metrics(selectMonth->fontMetrics());
00480   for(int i=1; i <= 12; ++i)
00481     { // maxMonthRect is used by sizeHint()
00482       r=metrics.boundingRect(KGlobal::locale()->calendar()->monthName(i, false));
00483       maxMonthRect.setWidth(qMax(r.width(), maxMonthRect.width()));
00484       maxMonthRect.setHeight(qMax(r.height(),  maxMonthRect.height()));
00485     }
00486   table->setFontSize(s);
00487 }
00488 
00489 void
00490 CalendarPanel::setCloseButton( bool enable )
00491 {
00492     if ( enable == (d->closeButton != 0L) )
00493         return;
00494 
00495     if ( enable ) {
00496         d->closeButton = new QToolButton( this );
00497         d->closeButton->setToolTip( i18n("Close"));
00498         d->closeButton->setPixmap( SmallIcon("remove") );
00499         connect( d->closeButton, SIGNAL( clicked() ),
00500                  topLevelWidget(), SLOT( close() ) );
00501     }
00502     else {
00503         delete d->closeButton;
00504         d->closeButton = 0L;
00505     }
00506 
00507     updateGeometry();
00508 }
00509 
00510 bool CalendarPanel::hasCloseButton() const
00511 {
00512     return (d->closeButton != 0L);
00513 }
00514 
00515 int CalendarPanel::weekOfYear(QDate date)
00516 {
00517     // Calculate ISO 8601 week number (taken from glibc/Gnumeric)
00518     int year, week, wday, jan1wday, nextjan1wday;
00519     QDate jan1date, nextjan1date;
00520 
00521     year=date.year();
00522     wday=date.dayOfWeek();
00523 
00524     jan1date=QDate(year,1,1);
00525     jan1wday=jan1date.dayOfWeek();
00526 
00527     week = (date.dayOfYear()-1 + jan1wday-1)/7 + ((jan1wday-1) == 0 ? 1 : 0);
00528 
00529     /* Does date belong to last week of previous year? */
00530     if ((week == 0) && (jan1wday > 4 /*THURSDAY*/)) {
00531         QDate tmpdate=QDate(year-1,12,31);
00532         return weekOfYear(tmpdate);
00533     }
00534 
00535     if ((jan1wday <= 4 /*THURSDAY*/) && (jan1wday > 1 /*MONDAY*/))
00536         week++;
00537 
00538     if (week == 53) {
00539         nextjan1date=QDate(year+1, 1, 1);
00540         nextjan1wday = nextjan1date.dayOfWeek();
00541         if (nextjan1wday <= 4 /*THURSDAY*/)
00542             week = 1;
00543     }
00544 
00545     return week;
00546 }
00547 
00548 void CalendarPanel::slotWeekdaySelected(int day) {
00549     //kDebug()<<k_funcinfo<<endl;
00550     emit weekdaySelected(day);
00551 }
00552 
00553 void CalendarPanel::slotWeekSelected(int week, int year) {
00554     //kDebug()<<k_funcinfo<<endl;
00555     emit weekSelected(week, year);
00556 }
00557 
00558 void CalendarPanel::setCalendar(Calendar *cal) {
00559     //kDebug()<<k_funcinfo<<endl;
00560     table->clear();
00561     if (cal) {
00562         table->setMarkedWeekdays(cal->weekdaysMap());
00563         //kDebug()<<k_funcinfo<<"Days="<<it.count()<<endl;
00564         foreach (CalendarDay *d, cal->days()) {
00565             if (d->state() != Map::None) {
00566                 table->addMarkedDate(d->date(), d->state());
00567             //kDebug()<<k_funcinfo<<"Added day: "<<d->date().toString()<<"="<<d->state()<<endl;
00568             }
00569         }
00570         setEnabled(true);
00571         table->setFocus();
00572     }
00573 }
00574 
00575 DateMap  CalendarPanel::selectedDates() {
00576     return table->selectedDates();
00577 }
00578 
00579 IntMap  CalendarPanel::selectedWeekdays() {
00580     return table->selectedWeekdays();
00581 }
00582 
00583 DateMap  CalendarPanel::markedDates() {
00584     return table->markedDates();
00585 }
00586 
00587 IntMap  CalendarPanel::markedWeekdays() {
00588     return table->markedWeekdays();
00589 }
00590 
00591 void CalendarPanel::clear() {
00592     table->clear();
00593     setEnabled(false);
00594 }
00595 
00596 void CalendarPanel::markSelected(int state) {
00597     table->markSelected(state);
00598  }
00599 
00600 void CalendarPanel::slotSelectionCleared() {
00601     emit selectionCleared();
00602  }
00603 
00604 void CalendarPanel::virtual_hook( int /*id*/, void* /*data*/ )
00605 { /*BASE::virtual_hook( id, data );*/ }
00606 
00607 }  //KPlato namespace
00608 
00609 #include "kptcalendarpanel.moc"

Généré le Wed Nov 22 23:40:55 2006 pour KPlato par  doxygen 1.5.1-p1