Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

kdatetbl.cpp

Go to the documentation of this file.
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 
00022 //
00023 // Copyright (C) 1997 Tim D. Gilman
00024 //           (C) 1998-2001 Mirko Boehm
00025 // Written using Qt (http://www.troll.no) for the
00026 // KDE project (http://www.kde.org)
00027 //
00028 // This is a support class for the KDatePicker class.  It just
00029 // draws the calender table without titles, but could theoretically
00030 // be used as a standalone.
00031 //
00032 // When a date is selected by the user, it emits a signal:
00033 //      dateSelected(QDate)
00034 
00035 #include <kglobal.h>
00036 #include <kglobalsettings.h>
00037 #include <kapplication.h>
00038 #include <klocale.h>
00039 #include <kdebug.h>
00040 #include <knotifyclient.h>
00041 #include "kdatetbl.h"
00042 #include <qdatetime.h>
00043 #include <qstring.h>
00044 #include <qpen.h>
00045 #include <qpainter.h>
00046 #include <qdialog.h>
00047 #include <assert.h>
00048 #include <qapplication.h>
00049 
00050 KDateValidator::KDateValidator(QWidget* parent, const char* name)
00051     : QValidator(parent, name)
00052 {
00053 }
00054 
00055 QValidator::State
00056 KDateValidator::validate(QString& text, int&) const
00057 {
00058   QDate temp;
00059   // ----- everything is tested in date():
00060   return date(text, temp);
00061 }
00062 
00063 QValidator::State
00064 KDateValidator::date(const QString& text, QDate& d) const
00065 {
00066   QDate tmp = KGlobal::locale()->readDate(text);
00067   if (!tmp.isNull())
00068     {
00069       d = tmp;
00070       return Acceptable;
00071     } else
00072       return Valid;
00073 }
00074 
00075 void
00076 KDateValidator::fixup( QString& ) const
00077 {
00078 
00079 }
00080 
00081 KDateTable::KDateTable(QWidget *parent, QDate date_, const char* name, WFlags f)
00082   : QGridView(parent, name, f)
00083 {
00084   setFontSize(10);
00085   if(!date_.isValid())
00086     {
00087       kdDebug() << "KDateTable ctor: WARNING: Given date is invalid, using current date." << endl;
00088       date_=QDate::currentDate();
00089     }
00090   setFocusPolicy( QWidget::StrongFocus );
00091   setNumRows(7); // 6 weeks max + headline
00092   setNumCols(7); // 7 days a week
00093   setHScrollBarMode(AlwaysOff);
00094   setVScrollBarMode(AlwaysOff);
00095 #if 0
00096   viewport()->setEraseColor(lightGray);
00097 #endif
00098   setDate(date_); // this initializes firstday, numdays, numDaysPrevMonth
00099 }
00100 
00101 void
00102 KDateTable::paintCell(QPainter *painter, int row, int col)
00103 {
00104   QRect rect;
00105   QString text;
00106   QPen pen;
00107   int w=cellWidth();
00108   int h=cellHeight();
00109   int pos;
00110   QBrush brushBlue(blue);
00111   QBrush brushLightblue(lightGray);
00112   QFont font=KGlobalSettings::generalFont();
00113   // -----
00114   font.setPointSize(fontsize);
00115   if(row==0)
00116     { // we are drawing the headline
00117       font.setBold(true);
00118       painter->setFont(font);
00119       bool normalday = true;
00120       QString daystr;
00121       if (KGlobal::locale()->weekStartsMonday())
00122         {
00123           daystr = KGlobal::locale()->weekDayName(col+1, true);
00124           if (col == 5 || col == 6)
00125               normalday = false;
00126         } else {
00127           daystr = KGlobal::locale()->weekDayName(col==0? 7 : col, true);
00128           if (col == 0 || col == 6)
00129               normalday = false;
00130         }
00131       if (!normalday)
00132         {
00133           painter->setPen(lightGray);
00134           painter->setBrush(brushLightblue);
00135           painter->drawRect(0, 0, w, h);
00136           painter->setPen(blue);
00137         } else {
00138           painter->setPen(blue);
00139           painter->setBrush(brushBlue);
00140           painter->drawRect(0, 0, w, h);
00141           painter->setPen(white);
00142         }
00143       painter->drawText(0, 0, w, h-1, AlignCenter,
00144                         daystr, -1, &rect);
00145       painter->setPen(black);
00146       painter->moveTo(0, h-1);
00147       painter->lineTo(w-1, h-1);
00148       // ----- draw the weekday:
00149     } else {
00150       painter->setFont(font);
00151       pos=7*(row-1)+col;
00152       if (KGlobal::locale()->weekStartsMonday())
00153           pos++;
00154       if(pos<firstday || (firstday+numdays<=pos))
00155         { // we are either
00156           // ° painting a day of the previous month or
00157           // ° painting a day of the following month
00158           if(pos<firstday)
00159             { // previous month
00160               text.setNum(numDaysPrevMonth+pos-firstday+1);
00161             } else { // following month
00162               text.setNum(pos-firstday-numdays+1);
00163             }
00164           painter->setPen(gray);
00165         } else { // paint a day of the current month
00166           text.setNum(pos-firstday+1);
00167           painter->setPen(black);
00168         }
00169 
00170       pen=painter->pen();
00171       if(firstday+date.day()-1==pos)
00172         {
00173           if(hasFocus())
00174             { // draw the currently selected date
00175               painter->setPen(red);
00176               painter->setBrush(darkRed);
00177               pen=white;
00178             } else {
00179               painter->setPen(darkGray);
00180               painter->setBrush(darkGray);
00181               pen=white;
00182             }
00183         } else {
00184           painter->setBrush(lightGray);
00185           painter->setPen(lightGray);
00186         }
00187       painter->drawRect(0, 0, w, h);
00188       painter->setPen(pen);
00189       painter->drawText(0, 0, w, h, AlignCenter, text, -1, &rect);
00190     }
00191   if(rect.width()>maxCell.width()) maxCell.setWidth(rect.width());
00192   if(rect.height()>maxCell.height()) maxCell.setHeight(rect.height());
00193 }
00194 
00195 void
00196 KDateTable::keyPressEvent( QKeyEvent *e )
00197 {
00198     if ( e->key() == Qt::Key_Prior ) {
00199         if ( date.month() == 1 ) {
00200             KNotifyClient::beep();
00201             return;
00202         }
00203         int day = date.day();
00204         if ( day > 27 )
00205             while ( !QDate::isValid( date.year(), date.month()-1, day ) )
00206                 day--;
00207         setDate(QDate(date.year(), date.month()-1, day));
00208         return;
00209     }
00210     if ( e->key() == Qt::Key_Next ) {
00211         if ( date.month() == 12 ) {
00212             KNotifyClient::beep();
00213             return;
00214         }
00215         int day = date.day();
00216         if ( day > 27 )
00217             while ( !QDate::isValid( date.year(), date.month()+1, day ) )
00218                 day--;
00219         setDate(QDate(date.year(), date.month()+1, day));
00220         return;
00221     }
00222 
00223     int dayoff = KGlobal::locale()->weekStartsMonday() ? 1 : 0;
00224 
00225     int temp=firstday+date.day()-dayoff;
00226     int pos = temp;
00227 
00228     if ( e->key() == Qt::Key_Up ) {
00229         pos -= 7;
00230     }
00231     if ( e->key() == Qt::Key_Down ) {
00232         pos += 7;
00233     }
00234     if ( e->key() == Qt::Key_Left ) {
00235         pos--;
00236     }
00237     if ( e->key() == Qt::Key_Right ) {
00238         pos++;
00239     }
00240 
00241     if(pos+dayoff<=firstday)
00242     { // this day is in the previous month
00243         KNotifyClient::beep();
00244         return;
00245     }
00246     if(firstday+numdays<pos+dayoff)
00247     { // this date is in the next month
00248         KNotifyClient::beep(i18n( "Month not long enough" ));
00249         return;
00250     }
00251 
00252     if ( pos == temp )
00253         return;
00254 
00255     setDate(QDate(date.year(), date.month(), pos-firstday+dayoff));
00256     updateCell(temp/7+1, temp%7); // Update the previously selected cell
00257     updateCell(pos/7+1, pos%7); // Update the selected cell
00258     assert(QDate(date.year(), date.month(), pos-firstday+dayoff).isValid());
00259 }
00260 
00261 void
00262 KDateTable::viewportResizeEvent(QResizeEvent * e)
00263 {
00264   QGridView::viewportResizeEvent(e);
00265 
00266   setCellWidth(viewport()->width()/7);
00267   setCellHeight(viewport()->height()/7);
00268 }
00269 
00270 void
00271 KDateTable::setFontSize(int size)
00272 {
00273   int count;
00274   QFontMetrics metrics(fontMetrics());
00275   QRect rect;
00276   // ----- store rectangles:
00277   fontsize=size;
00278   // ----- find largest day name:
00279   maxCell.setWidth(0);
00280   maxCell.setHeight(0);
00281   for(count=0; count<7; ++count)
00282     {
00283       rect=metrics.boundingRect(KGlobal::locale()->weekDayName(count+1, true));
00284       maxCell.setWidth(QMAX(maxCell.width(), rect.width()));
00285       maxCell.setHeight(QMAX(maxCell.height(), rect.height()));
00286     }
00287   // ----- compare with a real wide number and add some space:
00288   rect=metrics.boundingRect(QString::fromLatin1("88"));
00289   maxCell.setWidth(QMAX(maxCell.width()+2, rect.width()));
00290   maxCell.setHeight(QMAX(maxCell.height()+4, rect.height()));
00291 }
00292 
00293 void
00294 KDateTable::contentsMousePressEvent(QMouseEvent *e)
00295 {
00296   if(e->type()!=QEvent::MouseButtonPress)
00297     { // the KDatePicker only reacts on mouse press events:
00298       return;
00299     }
00300   if(!isEnabled())
00301     {
00302       KNotifyClient::beep();
00303       return;
00304     }
00305 
00306   int dayoff = KGlobal::locale()->weekStartsMonday() ? 1 : 0;
00307   // -----
00308   int row, col, pos, temp;
00309   QPoint mouseCoord;
00310   // -----
00311   mouseCoord = e->pos();
00312   row=rowAt(mouseCoord.y());
00313   col=columnAt(mouseCoord.x());
00314   if(row<0 || col<0)
00315     { // the user clicked on the frame of the table
00316       return;
00317     }
00318   pos=7*(row-1)+col+1;
00319   if(pos+dayoff<=firstday)
00320     { // this day is in the previous month
00321       KNotifyClient::beep();
00322       return;
00323     }
00324   if(firstday+numdays<pos+dayoff)
00325     { // this date is in the next month
00326       KNotifyClient::beep();
00327       return;
00328     }
00329   temp=firstday+date.day()-dayoff-1;
00330   setDate(QDate(date.year(), date.month(), pos-firstday+dayoff));
00331   updateCell(temp/7+1, temp%7); // Update the previously selected cell
00332   updateCell(row, col); // Update the selected cell
00333   // assert(QDate(date.year(), date.month(), pos-firstday+dayoff).isValid());
00334   emit(tableClicked());
00335 }
00336 
00337 bool
00338 KDateTable::setDate(const QDate& date_)
00339 {
00340   bool changed=false;
00341   QDate temp;
00342   // -----
00343   if(!date_.isValid())
00344     {
00345       kdDebug() << "KDateTable::setDate: refusing to set invalid date." << endl;
00346       return false;
00347     }
00348   if(date!=date_)
00349     {
00350       date=date_;
00351       changed=true;
00352     }
00353   temp.setYMD(date.year(), date.month(), 1);
00354   firstday=temp.dayOfWeek();
00355   if(firstday==1) firstday=8;
00356   numdays=date.daysInMonth();
00357   if(date.month()==1)
00358     { // set to december of previous year
00359       temp.setYMD(date.year()-1, 12, 1);
00360     } else { // set to previous month
00361       temp.setYMD(date.year(), date.month()-1, 1);
00362     }
00363   numDaysPrevMonth=temp.daysInMonth();
00364   if(changed)
00365     {
00366       repaintContents(false);
00367     }
00368   emit(dateChanged(date));
00369   return true;
00370 }
00371 
00372 const QDate&
00373 KDateTable::getDate() const
00374 {
00375   return date;
00376 }
00377 
00378 void KDateTable::focusInEvent( QFocusEvent *e )
00379 {
00380     repaintContents(false);
00381     QGridView::focusInEvent( e );
00382 }
00383 
00384 void KDateTable::focusOutEvent( QFocusEvent *e )
00385 {
00386     repaintContents(false);
00387     QGridView::focusOutEvent( e );
00388 }
00389 
00390 QSize
00391 KDateTable::sizeHint() const
00392 {
00393   if(maxCell.height()>0 && maxCell.width()>0)
00394     {
00395       return QSize(maxCell.width()*numCols()+2*frameWidth(),
00396              (maxCell.height()+2)*numRows()+2*frameWidth());
00397     } else {
00398       kdDebug() << "KDateTable::sizeHint: obscure failure - " << endl;
00399       return QSize(-1, -1);
00400     }
00401 }
00402 
00403 KDateInternalMonthPicker::KDateInternalMonthPicker
00404 (int fontsize, QWidget* parent, const char* name)
00405   : QGridView(parent, name),
00406     result(0) // invalid
00407 {
00408   QRect rect;
00409   QFont font;
00410   // -----
00411   activeCol = -1;
00412   activeRow = -1;
00413   font=KGlobalSettings::generalFont();
00414   font.setPointSize(fontsize);
00415   setFont(font);
00416   setHScrollBarMode(AlwaysOff);
00417   setVScrollBarMode(AlwaysOff);
00418   setFrameStyle(QFrame::NoFrame);
00419   setNumRows(4);
00420   setNumCols(3);
00421   // enable to find drawing failures:
00422   // setTableFlags(Tbl_clipCellPainting);
00423 #if 0
00424   viewport()->setEraseColor(lightGray); // for consistency with the datepicker
00425 #endif
00426   // ----- find the preferred size
00427   //       (this is slow, possibly, but unfortunatly it is needed here):
00428   QFontMetrics metrics(font);
00429   for(int i=1; i <= 12; ++i)
00430     {
00431       rect=metrics.boundingRect(KGlobal::locale()->monthName(i, false));
00432       if(max.width()<rect.width()) max.setWidth(rect.width());
00433       if(max.height()<rect.height()) max.setHeight(rect.height());
00434     }
00435 
00436 }
00437 
00438 QSize
00439 KDateInternalMonthPicker::sizeHint() const
00440 {
00441   return QSize((max.width()+6)*numCols()+2*frameWidth(),
00442          (max.height()+6)*numRows()+2*frameWidth());
00443 }
00444 
00445 int
00446 KDateInternalMonthPicker::getResult() const
00447 {
00448   return result;
00449 }
00450 
00451 void
00452 KDateInternalMonthPicker::setupPainter(QPainter *p)
00453 {
00454   p->setPen(black);
00455 }
00456 
00457 void
00458 KDateInternalMonthPicker::viewportResizeEvent(QResizeEvent*)
00459 {
00460   setCellWidth(width()/3);
00461   setCellHeight(height()/4);
00462 }
00463 
00464 void
00465 KDateInternalMonthPicker::paintCell(QPainter* painter, int row, int col)
00466 {
00467   int index;
00468   QString text;
00469   // ----- find the number of the cell:
00470   index=3*row+col+1;
00471   text=KGlobal::locale()->monthName(index, false);
00472   painter->drawText(0, 0, cellWidth(), cellHeight(), AlignCenter, text);
00473   if ( activeCol == col && activeRow == row )
00474       painter->drawRect( 0, 0, cellWidth(), cellHeight() );
00475 }
00476 
00477 void
00478 KDateInternalMonthPicker::contentsMousePressEvent(QMouseEvent *e)
00479 {
00480   if(!isEnabled() || e->button() != LeftButton)
00481     {
00482       KNotifyClient::beep();
00483       return;
00484     }
00485   // -----
00486   int row, col;
00487   QPoint mouseCoord;
00488   // -----
00489   mouseCoord = e->pos();
00490   row=rowAt(mouseCoord.y());
00491   col=columnAt(mouseCoord.x());
00492 
00493   if(row<0 || col<0)
00494     { // the user clicked on the frame of the table
00495       activeCol = -1;
00496       activeRow = -1;
00497     } else {
00498       activeCol = col;
00499       activeRow = row;
00500       updateCell( row, col /*, false */ );
00501   }
00502 }
00503 
00504 void
00505 KDateInternalMonthPicker::contentsMouseMoveEvent(QMouseEvent *e)
00506 {
00507   if (e->state() & LeftButton)
00508     {
00509       int row, col;
00510       QPoint mouseCoord;
00511       // -----
00512       mouseCoord = e->pos();
00513       row=rowAt(mouseCoord.y());
00514       col=columnAt(mouseCoord.x());
00515       int tmpRow = -1, tmpCol = -1;
00516       if(row<0 || col<0)
00517         { // the user clicked on the frame of the table
00518           if ( activeCol > -1 )
00519             {
00520               tmpRow = activeRow;
00521               tmpCol = activeCol;
00522             }
00523           activeCol = -1;
00524           activeRow = -1;
00525         } else {
00526           bool differentCell = (activeRow != row || activeCol != col);
00527           if ( activeCol > -1 && differentCell)
00528             {
00529               tmpRow = activeRow;
00530               tmpCol = activeCol;
00531             }
00532           if ( differentCell)
00533             {
00534               activeRow = row;
00535               activeCol = col;
00536               updateCell( row, col /*, false */ ); // mark the new active cell
00537             }
00538         }
00539       if ( tmpRow > -1 ) // repaint the former active cell
00540           updateCell( tmpRow, tmpCol /*, true */ );
00541     }
00542 }
00543 
00544 void
00545 KDateInternalMonthPicker::contentsMouseReleaseEvent(QMouseEvent *e)
00546 {
00547   if(!isEnabled())
00548     {
00549       return;
00550     }
00551   // -----
00552   int row, col, pos;
00553   QPoint mouseCoord;
00554   // -----
00555   mouseCoord = e->pos();
00556   row=rowAt(mouseCoord.y());
00557   col=columnAt(mouseCoord.x());
00558   if(row<0 || col<0)
00559     { // the user clicked on the frame of the table
00560       emit(closeMe(0));
00561     }
00562   pos=3*row+col+1;
00563   result=pos;
00564   emit(closeMe(1));
00565 }
00566 
00567 
00568 
00569 KDateInternalYearSelector::KDateInternalYearSelector
00570 (int fontsize, QWidget* parent, const char* name)
00571   : QLineEdit(parent, name),
00572     val(new QIntValidator(this)),
00573     result(0)
00574 {
00575   QFont font;
00576   // -----
00577   font=KGlobalSettings::generalFont();
00578   font.setPointSize(fontsize);
00579   setFont(font);
00580 #if 0
00581   setFrameStyle(QFrame::NoFrame);
00582 #endif
00583   // we have to respect the limits of QDate here, I fear:
00584   val->setRange(0, 8000);
00585   setValidator(val);
00586   connect(this, SIGNAL(returnPressed()), SLOT(yearEnteredSlot()));
00587 }
00588 
00589 void
00590 KDateInternalYearSelector::yearEnteredSlot()
00591 {
00592   bool ok;
00593   int year;
00594   QDate date;
00595   // ----- check if this is a valid year:
00596   year=text().toInt(&ok);
00597   if(!ok)
00598     {
00599       KNotifyClient::beep();
00600       return;
00601     }
00602   date.setYMD(year, 1, 1);
00603   if(!date.isValid())
00604     {
00605       KNotifyClient::beep();
00606       return;
00607     }
00608   result=year;
00609   emit(closeMe(1));
00610 }
00611 
00612 int
00613 KDateInternalYearSelector::getYear()
00614 {
00615   return result;
00616 }
00617 
00618 void
00619 KDateInternalYearSelector::setYear(int year)
00620 {
00621   QString temp;
00622   // -----
00623   temp.setNum(year);
00624   setText(temp);
00625 }
00626 
00627 KPopupFrame::KPopupFrame(QWidget* parent, const char*  name)
00628   : QFrame(parent, name, WType_Popup),
00629     result(0), // rejected
00630     main(0)
00631 {
00632   setFrameStyle(QFrame::Box|QFrame::Raised);
00633   setMidLineWidth(2);
00634 }
00635 
00636 void
00637 KPopupFrame::keyPressEvent(QKeyEvent* e)
00638 {
00639   if(e->key()==Key_Escape)
00640     {
00641       result=0; // rejected
00642       qApp->exit_loop();
00643     }
00644 }
00645 
00646 void
00647 KPopupFrame::close(int r)
00648 {
00649   result=r;
00650   qApp->exit_loop();
00651 }
00652 
00653 void
00654 KPopupFrame::setMainWidget(QWidget* m)
00655 {
00656   main=m;
00657   if(main!=0)
00658     {
00659       resize(main->width()+2*frameWidth(), main->height()+2*frameWidth());
00660     }
00661 }
00662 
00663 void
00664 KPopupFrame::resizeEvent(QResizeEvent*)
00665 {
00666   if(main!=0)
00667     {
00668       main->setGeometry(frameWidth(), frameWidth(),
00669           width()-2*frameWidth(), height()-2*frameWidth());
00670     }
00671 }
00672 
00673 void
00674 KPopupFrame::popup(const QPoint &pos)
00675 {
00676   // Make sure the whole popup is visible.
00677   QRect d = QApplication::desktop()->frameGeometry();
00678   int x = pos.x();
00679   int y = pos.y();
00680   int w = width();
00681   int h = height();
00682   if (x+w > d.x()+d.width())
00683     x = d.width() - w;
00684   if (y+h > d.y()+d.height())
00685     y = d.height() - h;
00686   if (x < d.x())
00687     x = 0;
00688   if (y < d.y())
00689     y = 0;
00690 
00691   // Pop the thingy up.
00692   move(x, y);
00693   show();
00694 }
00695 
00696 int
00697 KPopupFrame::exec(QPoint pos)
00698 {
00699   popup(pos);
00700   repaint();
00701   qApp->enter_loop();
00702   hide();
00703   return result;
00704 }
00705 
00706 int
00707 KPopupFrame::exec(int x, int y)
00708 {
00709   return exec(QPoint(x, y));
00710 }
00711 
00712 void KPopupFrame::virtual_hook( int, void* )
00713 { /*BASE::virtual_hook( id, data );*/ }
00714 
00715 void KDateTable::virtual_hook( int, void* )
00716 { /*BASE::virtual_hook( id, data );*/ }
00717 
00718 #include "kdatetbl.moc"

Generated on Sat Nov 5 16:17:11 2005 for OPIE by  doxygen 1.4.2