• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDEUI

kdatetable.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               (C) 2007 John Layt <john@layt.net>
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 #include "kdatetable.h"
00023 
00024 #include <kconfig.h>
00025 #include <kcolorscheme.h>
00026 #include <kglobal.h>
00027 #include <kglobalsettings.h>
00028 #include <klocale.h>
00029 #include <kdebug.h>
00030 #include <knotification.h>
00031 #include <kcalendarsystem.h>
00032 #include <kshortcut.h>
00033 #include <kstandardshortcut.h>
00034 #include "kdatepicker.h"
00035 #include "kmenu.h"
00036 #include "kactioncollection.h"
00037 #include "kaction.h"
00038 #include <kdeversion.h>
00039 
00040 #include <QtCore/QDate>
00041 #include <QtCore/QCharRef>
00042 #include <QtGui/QPen>
00043 #include <QtGui/QPainter>
00044 #include <QtGui/QDialog>
00045 #include <QtGui/QActionEvent>
00046 #include <QtCore/QHash>
00047 #include <QtGui/QApplication>
00048 #include <assert.h>
00049 
00050 #include <cmath>
00051 
00052 class KDateTable::KDateTablePrivate
00053 {
00054 public:
00055     KDateTablePrivate( KDateTable *q ): q( q )
00056     {
00057         popupMenuEnabled = false;
00058         useCustomColors = false;
00059         m_calendar = 0;
00060     }
00061 
00062     ~KDateTablePrivate()
00063     {
00064     }
00065 
00066     void nextMonth();
00067     void previousMonth();
00068     void beginningOfMonth();
00069     void endOfMonth();
00070     void beginningOfWeek();
00071     void endOfWeek();
00072 
00073     KDateTable *q;
00074 
00078     int fontsize;
00079 
00083     QDate mDate;
00084 
00088     int weekDayFirstOfMonth;
00089 
00093     int numDaysThisMonth;
00094 
00098     QRectF maxCell;
00099 
00103     int numWeekRows;
00104 
00108     int numDayColumns;
00109 
00110     bool popupMenuEnabled : 1;
00111     bool useCustomColors : 1;
00112 
00113     struct DatePaintingMode
00114     {
00115         QColor fgColor;
00116         QColor bgColor;
00117         BackgroundMode bgMode;
00118     };
00119     QHash <int, DatePaintingMode*> customPaintingModes;
00120 
00121     KCalendarSystem *m_calendar;
00122 
00123 };
00124 
00125 
00126 class KPopupFrame::KPopupFramePrivate
00127 {
00128 public:
00129     KPopupFramePrivate( KPopupFrame *q ):
00130             q( q ),
00131             result( 0 ), // rejected
00132             main( 0 )
00133     {
00134     }
00135 
00136     KPopupFrame *q;
00137 
00141     int result;
00142 
00146     QWidget *main;
00147 };
00148 
00149 
00150 class KDateValidator::KDateValidatorPrivate
00151 {
00152 public:
00153     KDateValidatorPrivate( KDateValidator *q ): q( q )
00154     {
00155     }
00156 
00157     ~KDateValidatorPrivate()
00158     {
00159     }
00160 
00161     KDateValidator *q;
00162 };
00163 
00164 KDateValidator::KDateValidator( QWidget *parent ) : QValidator( parent ), d( 0 )
00165 {
00166 }
00167 
00168 QValidator::State KDateValidator::validate( QString &text, int &unused ) const
00169 {
00170     Q_UNUSED( unused );
00171 
00172     QDate temp;
00173     // ----- everything is tested in date():
00174     return date( text, temp );
00175 }
00176 
00177 QValidator::State KDateValidator::date( const QString &text, QDate &d ) const
00178 {
00179     QDate tmp = KGlobal::locale()->readDate( text );
00180     if ( !tmp.isNull() ) {
00181         d = tmp;
00182         return Acceptable;
00183     } else {
00184         return QValidator::Intermediate;
00185     }
00186 }
00187 
00188 void KDateValidator::fixup( QString& ) const
00189 {
00190 }
00191 
00192 KDateTable::KDateTable( const QDate& date_, QWidget* parent )
00193            : QWidget( parent ), d( new KDateTablePrivate( this ) )
00194 {
00195     d->numWeekRows = 7;
00196     d->numDayColumns = calendar()->daysInWeek( date_ );
00197     setFontSize( 10 );
00198     setFocusPolicy( Qt::StrongFocus );
00199     QPalette palette;
00200     palette.setColor( backgroundRole(), KColorScheme(QPalette::Active, KColorScheme::View).background().color() );
00201     setPalette( palette );
00202 
00203     if( !setDate( date_ ) ) {
00204         // this initializes weekDayFirstOfMonth, numDaysThisMonth
00205         setDate( QDate::currentDate() );
00206     }
00207     initAccels();
00208 }
00209 
00210 KDateTable::KDateTable( QWidget *parent )
00211            : QWidget( parent ), d( new KDateTablePrivate( this ) )
00212 {
00213     // JPL should we just call KDateTable( QDate::currentDate(), parent ) here to save duplication?
00214     // Or if that is a problem with base class instantiation move all to a private init()
00215     d->numWeekRows = 7;
00216     d->numDayColumns = calendar()->daysInWeek( QDate::currentDate() );
00217     setFontSize( 10 );
00218     setFocusPolicy( Qt::StrongFocus );
00219     QPalette palette;
00220     palette.setColor( backgroundRole(), KColorScheme(QPalette::Active, KColorScheme::View).background().color() );
00221     setPalette( palette );
00222     // this initializes weekDayFirstOfMonth, numDaysThisMonth
00223     setDate( QDate::currentDate() );
00224     initAccels();
00225 }
00226 
00227 KDateTable::~KDateTable()
00228 {
00229     delete d;
00230 }
00231 
00232 void KDateTable::initAccels()
00233 {
00234     KActionCollection * localCollection = new KActionCollection( this );
00235 
00236     KAction* next = localCollection->addAction( QLatin1String( "next" ) );
00237     next->setShortcuts( KStandardShortcut::next() );
00238     connect( next, SIGNAL( triggered( bool ) ), SLOT( nextMonth() ) );
00239 
00240     KAction* prior = localCollection->addAction( QLatin1String( "prior" ) );
00241     prior->setShortcuts( KStandardShortcut::prior() );
00242     connect( prior, SIGNAL( triggered( bool ) ), SLOT( previousMonth() ) );
00243 
00244     KAction* beginMonth = localCollection->addAction( QLatin1String( "beginMonth" ) );
00245     beginMonth->setShortcuts( KStandardShortcut::begin() );
00246     connect( beginMonth, SIGNAL( triggered( bool ) ), SLOT( beginningOfMonth() ) );
00247 
00248     KAction* endMonth = localCollection->addAction( QLatin1String( "endMonth" ) );
00249     endMonth->setShortcuts( KStandardShortcut::end() );
00250     connect( endMonth, SIGNAL( triggered( bool ) ), SLOT( endOfMonth() ) );
00251 
00252     KAction* beginWeek = localCollection->addAction( QLatin1String( "beginWeek" ) );
00253     beginWeek->setShortcuts( KStandardShortcut::beginningOfLine() );
00254     connect( beginWeek, SIGNAL( triggered( bool ) ), SLOT( beginningOfWeek() ) );
00255 
00256     KAction* endWeek = localCollection->addAction( "endWeek" );
00257     endWeek->setShortcuts( KStandardShortcut::endOfLine() );
00258     connect( endWeek, SIGNAL( triggered( bool ) ), SLOT( endOfWeek() ) );
00259 
00260     localCollection->readSettings();
00261     localCollection->addAssociatedWidget( this );
00262     foreach (QAction* action, localCollection->actions())
00263         action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
00264 }
00265 
00266 int KDateTable::posFromDate( const QDate &date_ )
00267 {
00268     int initialPosition = calendar()->day( date_ );
00269     int offset = ( d->weekDayFirstOfMonth - calendar()->weekStartDay() + d->numDayColumns ) % d->numDayColumns;
00270 
00271     // make sure at least one day of the previous month is visible.
00272     // adjust this < 1 if more days should be forced visible:
00273     if ( offset < 1 ) {
00274         offset += d->numDayColumns;
00275     }
00276 
00277     return initialPosition + offset;
00278 }
00279 
00280 QDate KDateTable::dateFromPos( int position )
00281 {
00282     QDate cellDate;
00283 
00284     int offset = ( d->weekDayFirstOfMonth - calendar()->weekStartDay() + d->numDayColumns ) % d->numDayColumns;
00285 
00286     // make sure at least one day of the previous month is visible.
00287     // adjust this < 1 if more days should be forced visible:
00288     if ( offset < 1 ) {
00289         offset += d->numDayColumns;
00290     }
00291 
00292     if ( calendar()->setYMD( cellDate, calendar()->year( d->mDate ), calendar()->month( d->mDate ), 1 ) ) {
00293         cellDate = calendar()->addDays( cellDate, position - offset );
00294     } else {
00295         //If first of month is not valid, then that must be before earliestValid Date, so safe to assume next month ok
00296         if ( calendar()->setYMD( cellDate, calendar()->year( d->mDate ), calendar()->month( d->mDate ) + 1, 1 ) ) {
00297             cellDate = calendar()->addDays( cellDate, position - offset - calendar()->daysInMonth( d->mDate ) );
00298         }
00299     }
00300     return cellDate;
00301 }
00302 
00303 void KDateTable::paintEvent( QPaintEvent *e )
00304 {
00305     QPainter p( this );
00306     const QRect &rectToUpdate = e->rect();
00307     double cellWidth = width() / ( double ) d->numDayColumns;
00308     double cellHeight = height() / ( double ) d->numWeekRows;
00309     int leftCol = ( int )std::floor( rectToUpdate.left() / cellWidth );
00310     int topRow = ( int )std::floor( rectToUpdate.top() / cellHeight );
00311     int rightCol = ( int )std::ceil( rectToUpdate.right() / cellWidth );
00312     int bottomRow = ( int )std::ceil( rectToUpdate.bottom() / cellHeight );
00313     bottomRow = qMin( bottomRow, d->numWeekRows - 1 );
00314     rightCol = qMin( rightCol, d->numDayColumns - 1 );
00315     p.translate( leftCol * cellWidth, topRow * cellHeight );
00316     for ( int i = leftCol; i <= rightCol; ++i ) {
00317         for ( int j = topRow; j <= bottomRow; ++j ) {
00318             paintCell( &p, j, i );
00319             p.translate( 0, cellHeight );
00320         }
00321         p.translate( cellWidth, 0 );
00322         p.translate( 0, -cellHeight * ( bottomRow - topRow + 1 ) );
00323     }
00324 }
00325 
00326 void KDateTable::paintCell( QPainter *painter, int row, int col )
00327 {
00328     double w = ( width() / ( double ) d->numDayColumns ) - 1;
00329     double h = ( height() / ( double ) d->numWeekRows ) - 1;
00330     QRectF cell = QRectF( 0, 0, w, h );
00331     QString cellText;
00332     QPen pen;
00333     QColor cellBorderColor, cellBaseLineColor, cellBackgroundColor, cellTextColor;
00334     QFont cellFont = KGlobalSettings::generalFont();
00335     bool workingDay = false;
00336     bool drawCellBorder = false;
00337     bool drawBaseLine = false;
00338     int cellWeekDay, pos;
00339     BackgroundMode cellBackgroundMode = RectangleMode;
00340 
00341     //Calculate the position of the cell in the grid
00342     pos = d->numDayColumns * ( row - 1 ) + col;
00343 
00344     //Calculate what day of the week the cell is
00345     if ( col + calendar()->weekStartDay() <= d->numDayColumns ) {
00346         cellWeekDay = col + calendar()->weekStartDay();
00347     } else {
00348         cellWeekDay = col + calendar()->weekStartDay() - d->numDayColumns;
00349     }
00350 
00351     //See if cell day is normally a working day
00352     if ( KGlobal::locale()->workingWeekStartDay() <= KGlobal::locale()->workingWeekEndDay() ) {
00353         if ( cellWeekDay >= KGlobal::locale()->workingWeekStartDay() &&
00354              cellWeekDay <= KGlobal::locale()->workingWeekEndDay() ) {
00355                 workingDay = true;
00356         }
00357     } else {
00358         if ( cellWeekDay >= KGlobal::locale()->workingWeekStartDay() ||
00359              cellWeekDay <= KGlobal::locale()->workingWeekEndDay() ) {
00360                 workingDay = true;
00361         }
00362     }
00363 
00364     if( row == 0 ) {
00365 
00366         //We are drawing a header cell
00367 
00368         QColor titleColor, textColor;
00369 
00370         if ( isEnabled() ) {
00371             titleColor = KGlobalSettings::activeTitleColor();
00372             textColor = KGlobalSettings::activeTextColor();
00373         } else {
00374             titleColor = KGlobalSettings::inactiveTitleColor();
00375             textColor = KGlobalSettings::inactiveTextColor();
00376         }
00377 
00378         //If not a normal working day, then invert title/text colours
00379         if ( workingDay ) {
00380             cellBackgroundColor = titleColor;
00381             cellTextColor = textColor;
00382         } else {
00383             cellBackgroundColor = textColor;
00384             cellTextColor = titleColor;
00385         }
00386 
00387         //Set the text to the short day name and bold it
00388         cellFont.setBold( true );
00389         cellText = calendar()->weekDayName( cellWeekDay, KCalendarSystem::ShortDayName );
00390 
00391         //Draw a baseline under the cell
00392         drawBaseLine = true;
00393         cellBaseLineColor = palette().color( QPalette::Text );
00394 
00395     } else {
00396 
00397         //We are drawing a day cell
00398 
00399         //Calculate the date the cell represents
00400         QDate cellDate = dateFromPos( pos );
00401 
00402         bool validDay = calendar()->isValid( cellDate );
00403 
00404         // Draw the day number in the cell, if the date is not valid then we don't want to show it
00405         if ( validDay ) {
00406             cellText = calendar()->dayString( cellDate, KCalendarSystem::ShortFormat );
00407         } else {
00408             cellText = "";
00409         }
00410 
00411         if( ! validDay || calendar()->month( cellDate ) != calendar()->month( d->mDate ) ) {
00412             // we are either
00413             // ° painting an invalid day
00414             // ° painting a day of the previous month or
00415             // ° painting a day of the following month or
00416             cellBackgroundColor = palette().color( QPalette::Background );
00417             cellTextColor = palette().color( QPalette::Mid );
00418         } else {
00419             //Paint a day of the current month
00420 
00421             // Background Colour priorities will be (high-to-low):
00422             // * Selected Day Background Colour
00423             // * Customised Day Background Colour
00424             // * Normal Day Background Colour
00425 
00426             // Background Shape priorities will be (high-to-low):
00427             // * Customised Day Shape
00428             // * Normal Day Shape
00429 
00430             // Text Colour priorities will be (high-to-low):
00431             // * Customised Day Colour
00432             // * Day of Pray Colour (Red letter)
00433             // * Selected Day Colour
00434             // * Normal Day Colour
00435 
00436             //Determine various characteristics of the cell date
00437             bool selectedDay = ( cellDate == d->mDate );
00438             bool currentDay = ( cellDate == QDate::currentDate() );
00439             bool dayOfPray = ( calendar()->dayOfWeek( cellDate ) == KGlobal::locale()->weekDayOfPray() );
00440             bool customDay = ( d->useCustomColors && d->customPaintingModes.contains(cellDate.toJulianDay()) );
00441 
00442             //Default values for a normal cell
00443             cellBackgroundColor = palette().color( QPalette::Background );
00444             cellTextColor = palette().color( QPalette::Text );
00445 
00446             // If we are drawing the current date, then draw a border
00447             if ( currentDay ) {
00448                 drawCellBorder = true;
00449                 cellBorderColor = palette().color( QPalette::Text );
00450             }
00451 
00452             // if we are drawing the day cell currently selected in the table
00453             if ( selectedDay ) {
00454                 // set the background to highlighted
00455                 if ( isEnabled() ) {
00456                     cellBackgroundColor = palette().color( QPalette::Highlight );
00457                 } else {
00458                     cellBackgroundColor = palette().color( QPalette::Text );
00459                 }
00460                 cellTextColor = palette().color( QPalette::HighlightedText );
00461             }
00462 
00463             //If custom colors or shape are required for this date
00464             if ( customDay ) {
00465                 KDateTablePrivate::DatePaintingMode * mode = d->customPaintingModes[cellDate.toJulianDay()];
00466                 if ( mode->bgMode != NoBgMode ) {
00467                         cellBackgroundMode = mode->bgMode;
00468                         if (!selectedDay) cellBackgroundColor = mode->bgColor;
00469                 }
00470                 cellTextColor = mode->fgColor;
00471             }
00472 
00473             //If the cell day is the day of religious observance, then always color text red unless Custom overrides
00474             if ( ! customDay && dayOfPray ) {
00475                 cellTextColor = Qt::red;  //should use some user-configurable palette or scheme colour?
00476             }
00477 
00478         }
00479     }
00480 
00481     //Draw the background
00482     painter->setPen( cellBackgroundColor );
00483     painter->setBrush( cellBackgroundColor );
00484     if ( cellBackgroundMode == CircleMode ) {
00485         painter->drawEllipse( cell );
00486     } else {
00487         painter->drawRect( cell );
00488     }
00489 
00490     //Draw the border
00491     if ( drawCellBorder ) {
00492         painter->setPen( cellBorderColor );
00493         if ( cellBackgroundMode == CircleMode ) {
00494             painter->drawEllipse( cell );
00495         } else {
00496             painter->drawRect( cell );
00497         }
00498     }
00499 
00500     //Draw the text
00501     painter->setPen( cellTextColor );
00502     painter->setFont( cellFont );
00503     painter->drawText( cell, Qt::AlignCenter, cellText, &cell );
00504 
00505     //Draw the base line
00506     if (drawBaseLine) {
00507         painter->setPen( cellBaseLineColor );
00508         painter->drawLine( QPointF( 0, h ), QPointF( w, h ) );
00509     }
00510 
00511     // If the day cell we just drew is bigger than the current max cell sizes,
00512     // then adjust the max to the current cell
00513     if ( cell.width() > d->maxCell.width() ) d->maxCell.setWidth( cell.width() );
00514     if ( cell.height() > d->maxCell.height() ) d->maxCell.setHeight( cell.height() );
00515 }
00516 
00517 void KDateTable::KDateTablePrivate::nextMonth()
00518 {
00519     // setDate does validity checking for us
00520     q->setDate( q->calendar()->addMonths( mDate, 1 ) );
00521 }
00522 
00523 void KDateTable::KDateTablePrivate::previousMonth()
00524 {
00525     // setDate does validity checking for us
00526     q->setDate( q->calendar()->addMonths( mDate, -1 ) );
00527 }
00528 
00529 void KDateTable::KDateTablePrivate::beginningOfMonth()
00530 {
00531     // setDate does validity checking for us
00532     q->setDate( q->calendar()->addDays( mDate, 1 - q->calendar()->day( mDate ) ) );
00533 }
00534 
00535 void KDateTable::KDateTablePrivate::endOfMonth()
00536 {
00537     // setDate does validity checking for us
00538     q->setDate( q->calendar()->addDays( mDate,
00539                 q->calendar()->daysInMonth( mDate ) - q->calendar()->day( mDate ) ) );
00540 }
00541 
00542 // JPL Do these make the assumption that first day of week is weekday 1? As it may not be.
00543 void KDateTable::KDateTablePrivate::beginningOfWeek()
00544 {
00545     // setDate does validity checking for us
00546     q->setDate( q->calendar()->addDays( mDate, 1 - q->calendar()->dayOfWeek( mDate ) ) );
00547 }
00548 
00549 // JPL Do these make the assumption that first day of week is weekday 1? As it may not be.
00550 void KDateTable::KDateTablePrivate::endOfWeek()
00551 {
00552     // setDate does validity checking for us
00553     q->setDate( q->calendar()->addDays( mDate,
00554                 q->calendar()->daysInWeek( mDate ) - q->calendar()->dayOfWeek( mDate ) ) );
00555 }
00556 
00557 void KDateTable::keyPressEvent( QKeyEvent *e )
00558 {
00559     switch( e->key() ) {
00560     case Qt::Key_Up:
00561         // setDate does validity checking for us
00562         setDate( calendar()->addDays( d->mDate, - d->numDayColumns ) );
00563         break;
00564     case Qt::Key_Down:
00565         // setDate does validity checking for us
00566         setDate( calendar()->addDays( d->mDate, d->numDayColumns ) );
00567         break;
00568     case Qt::Key_Left:
00569         // setDate does validity checking for us
00570         setDate( calendar()->addDays( d->mDate, -1 ) );
00571         break;
00572     case Qt::Key_Right:
00573         // setDate does validity checking for us
00574         setDate( calendar()->addDays( d->mDate, 1 ) );
00575         break;
00576     case Qt::Key_Minus:
00577         // setDate does validity checking for us
00578         setDate( calendar()->addDays( d->mDate, -1 ) );
00579         break;
00580     case Qt::Key_Plus:
00581         // setDate does validity checking for us
00582         setDate( calendar()->addDays( d->mDate, 1 ) );
00583         break;
00584     case Qt::Key_N:
00585         // setDate does validity checking for us
00586         setDate( QDate::currentDate() );
00587         break;
00588     case Qt::Key_Return:
00589     case Qt::Key_Enter:
00590         emit tableClicked();
00591         break;
00592     case Qt::Key_Control:
00593     case Qt::Key_Alt:
00594     case Qt::Key_Meta:
00595     case Qt::Key_Shift:
00596         // Don't beep for modifiers
00597         break;
00598     default:
00599         if ( !e->modifiers() ) { // hm
00600             KNotification::beep();
00601         }
00602     }
00603 }
00604 
00605 void KDateTable::setFontSize( int size )
00606 {
00607     int count;
00608     QFontMetricsF metrics( fontMetrics() );
00609     QRectF rect;
00610     // ----- store rectangles:
00611     d->fontsize = size;
00612     // ----- find largest day name:
00613     d->maxCell.setWidth( 0 );
00614     d->maxCell.setHeight( 0 );
00615     for( count = 0; count < calendar()->daysInWeek( d->mDate ); ++count ) {
00616         rect = metrics.boundingRect( calendar()->weekDayName( count + 1, KCalendarSystem::ShortDayName ) );
00617         d->maxCell.setWidth( qMax( d->maxCell.width(), rect.width() ) );
00618         d->maxCell.setHeight( qMax( d->maxCell.height(), rect.height() ) );
00619     }
00620     // ----- compare with a real wide number and add some space:
00621     rect = metrics.boundingRect( QLatin1String( "88" ) );
00622     d->maxCell.setWidth( qMax( d->maxCell.width() + 2, rect.width() ) );
00623     d->maxCell.setHeight( qMax( d->maxCell.height() + 4, rect.height() ) );
00624 }
00625 
00626 void KDateTable::wheelEvent ( QWheelEvent * e )
00627 {
00628     setDate( calendar()->addMonths( d->mDate, -( int )( e->delta() / 120 ) ) );
00629     e->accept();
00630 }
00631 
00632 void KDateTable::mousePressEvent( QMouseEvent *e )
00633 {
00634     if( e->type() != QEvent::MouseButtonPress ) { // the KDatePicker only reacts on mouse press events:
00635         return;
00636     }
00637 
00638     if( !isEnabled() ) {
00639         KNotification::beep();
00640         return;
00641     }
00642 
00643     int row, col, pos, temp;
00644 
00645     QPoint mouseCoord = e->pos();
00646     row = mouseCoord.y() / ( height() / d->numWeekRows );
00647     col = mouseCoord.x() / ( width() / d->numDayColumns );
00648 
00649     if( row < 1 || col < 0 ) { // the user clicked on the frame of the table
00650         return;
00651     }
00652 
00653     // Rows and columns are zero indexed.  The (row - 1) below is to avoid counting
00654     // the row with the days of the week in the calculation.
00655 
00656     // old selected date:
00657     temp = posFromDate( d->mDate );
00658 
00659     // new position and date
00660     pos = ( d->numDayColumns * ( row - 1 ) ) + col;
00661     QDate clickedDate = dateFromPos( pos );
00662 
00663     // set the new date. If it is in the previous or next month, the month will
00664     // automatically be changed, no need to do that manually...
00665     // validity checking done inside setDate
00666     setDate( clickedDate );
00667 
00668     // This could be optimized to only call update over the regions
00669     // of old and new cell, but 99% of times there is also a call to
00670     // setDate that already calls update() so no need to optimize that
00671     // much here
00672     update();
00673 
00674     emit tableClicked();
00675 
00676     if (  e->button() == Qt::RightButton && d->popupMenuEnabled ) {
00677         KMenu * menu = new KMenu();
00678         menu->addTitle( calendar()->formatDate( clickedDate ) );
00679         emit aboutToShowContextMenu( menu, clickedDate );
00680         menu->popup( e->globalPos() );
00681     }
00682 }
00683 
00684 bool KDateTable::setDate( const QDate& date_ )
00685 {
00686     if( date_.isNull() || ! calendar()->isValid( date_ ) ) {
00687         return false;
00688     }
00689 
00690     bool changed = false;
00691 
00692     if( d->mDate != date_ ) {
00693         emit( dateChanged( d->mDate, date_ ) );
00694         d->mDate = date_;
00695         emit( dateChanged( d->mDate ) );
00696         changed = true;
00697     }
00698 
00699     // set weekday number of first day of this month, but this may not be a valid date so fake
00700     // it if needed e.g. in QDate Mon 1 Jan -4713 is not valid when it should be, so fake as day 1
00701     QDate firstDayOfMonth;
00702     if ( calendar()->setYMD( firstDayOfMonth,
00703                              calendar()->year( d->mDate ), calendar()->month( d->mDate ), 1 ) ) {
00704         d->weekDayFirstOfMonth = calendar()->dayOfWeek( firstDayOfMonth );
00705     } else {
00706         d->weekDayFirstOfMonth = calendar()->dayOfWeek( d->mDate ) -
00707                                  ( ( calendar()->day( d->mDate ) - 1 ) % d->numDayColumns );
00708         if ( d->weekDayFirstOfMonth <= 0 ) {
00709             d->weekDayFirstOfMonth = d->weekDayFirstOfMonth + d->numDayColumns;
00710         }
00711     }
00712 
00713     d->numDaysThisMonth = calendar()->daysInMonth( d->mDate );
00714 
00715     if( changed ) {
00716         update();
00717     }
00718 
00719     return true;
00720 }
00721 
00722 const QDate &KDateTable::date() const
00723 {
00724     return d->mDate;
00725 }
00726 
00727 const KCalendarSystem *KDateTable::calendar() const
00728 {
00729     if ( d->m_calendar ) {
00730         return d->m_calendar;
00731     }
00732 
00733     return  KGlobal::locale()->calendar();
00734 }
00735 
00736 bool KDateTable::setCalendar( KCalendarSystem *calendar_ )
00737 {
00738     // Delete the old calendar first, provided it's not the global (better to be safe...)
00739     if ( d->m_calendar && d->m_calendar != KGlobal::locale()->calendar() ) {
00740         delete d->m_calendar;
00741     }
00742 
00743     d->m_calendar = 0;
00744 
00745     // Don't actually set calendar if it's the global, setting to 0 will cause global to be returned
00746     if ( calendar_ != KGlobal::locale()->calendar() ) {
00747         d->m_calendar = calendar_;
00748 
00749         // Need to redraw to display correct calendar
00750         d->numDayColumns = calendar()->daysInWeek( d->mDate );
00751         setDate( d->mDate );
00752         // JPL not 100% sure we need to emit
00753         emit( dateChanged( d->mDate, d->mDate ) );
00754         emit( dateChanged( d->mDate ) );
00755         update();
00756     }
00757 
00758     return true;
00759 }
00760 
00761 bool KDateTable::setCalendar( const QString &calendarType )
00762 {
00763     // If type passed in is the same as the global, then use the global instead
00764     if ( calendarType != KGlobal::locale()->calendarType() ) {
00765         return( setCalendar( KCalendarSystem::create( calendarType ) ) );
00766     } else {
00767         // Delete the old calendar first, provided it's not the global (better to be safe...)
00768         if ( d->m_calendar && d->m_calendar != KGlobal::locale()->calendar() ) {
00769             delete d->m_calendar;
00770         }
00771         d->m_calendar = 0;
00772         return true;
00773     }
00774 }
00775 
00776 void KDateTable::focusInEvent( QFocusEvent *e )
00777 {
00778     QWidget::focusInEvent( e );
00779 }
00780 
00781 void KDateTable::focusOutEvent( QFocusEvent *e )
00782 {
00783     QWidget::focusOutEvent( e );
00784 }
00785 
00786 QSize KDateTable::sizeHint() const
00787 {
00788     if( d->maxCell.height() > 0 && d->maxCell.width() > 0 ) {
00789         return QSize( qRound( d->maxCell.width() * d->numDayColumns ),
00790                       ( qRound( d->maxCell.height() + 2 ) * d->numWeekRows ) );
00791     } else {
00792         kDebug() << "KDateTable::sizeHint: obscure failure - " << endl;
00793         return QSize( -1, -1 );
00794     }
00795 }
00796 
00797 void KDateTable::setPopupMenuEnabled( bool enable )
00798 {
00799     d->popupMenuEnabled = enable;
00800 }
00801 
00802 bool KDateTable::popupMenuEnabled() const
00803 {
00804     return d->popupMenuEnabled;
00805 }
00806 
00807 void KDateTable::setCustomDatePainting( const QDate &date, const QColor &fgColor, BackgroundMode bgMode, const QColor &bgColor )
00808 {
00809     if ( !fgColor.isValid() ) {
00810         unsetCustomDatePainting( date );
00811         return;
00812     }
00813 
00814     KDateTablePrivate::DatePaintingMode *mode = new KDateTablePrivate::DatePaintingMode;
00815     mode->bgMode = bgMode;
00816     mode->fgColor = fgColor;
00817     mode->bgColor = bgColor;
00818 
00819     d->customPaintingModes.insert( date.toJulianDay(), mode );
00820     d->useCustomColors = true;
00821     update();
00822 }
00823 
00824 void KDateTable::unsetCustomDatePainting( const QDate &date )
00825 {
00826     d->customPaintingModes.remove( date.toJulianDay() );
00827     if ( d->customPaintingModes.isEmpty() ) d->useCustomColors = false;
00828     update();
00829 }
00830 
00831 
00832 // JPL Shouldn't this be in own file as is used in a couple of places?  Or moved to private in KDE5?
00833 
00834 KPopupFrame::KPopupFrame( QWidget* parent )
00835             : QFrame( parent, Qt::Popup ), d( new KPopupFramePrivate( this ) )
00836 {
00837     setFrameStyle( QFrame::Box | QFrame::Raised );
00838     setMidLineWidth( 2 );
00839 }
00840 
00841 KPopupFrame::~KPopupFrame()
00842 {
00843     delete d;
00844 }
00845 
00846 void KPopupFrame::keyPressEvent( QKeyEvent* e )
00847 {
00848     if( e->key() == Qt::Key_Escape ) {
00849         d->result = 0; // rejected
00850         emit leaveModality();
00851         //qApp->exit_loop();
00852     }
00853 }
00854 
00855 void KPopupFrame::close( int r )
00856 {
00857     d->result = r;
00858     emit leaveModality();
00859     //qApp->exit_loop();
00860 }
00861 
00862 void KPopupFrame::setMainWidget( QWidget *m )
00863 {
00864     d->main = m;
00865     if( d->main ) {
00866         resize( d->main->width() + 2 * frameWidth(), d->main->height() + 2 * frameWidth() );
00867     }
00868 }
00869 
00870 void KPopupFrame::resizeEvent( QResizeEvent *e )
00871 {
00872     Q_UNUSED( e );
00873 
00874     if( d->main ) {
00875         d->main->setGeometry( frameWidth(), frameWidth(),
00876                               width() - 2 * frameWidth(), height() - 2 * frameWidth() );
00877     }
00878 }
00879 
00880 void KPopupFrame::popup( const QPoint &pos )
00881 {
00882     // Make sure the whole popup is visible.
00883     QRect desktopGeometry = KGlobalSettings::desktopGeometry( pos );
00884 
00885     int x = pos.x();
00886     int y = pos.y();
00887     int w = width();
00888     int h = height();
00889     if ( x + w > desktopGeometry.x() + desktopGeometry.width() ) {
00890         x = desktopGeometry.width() - w;
00891     }
00892     if ( y + h > desktopGeometry.y() + desktopGeometry.height() ) {
00893         y = desktopGeometry.height() - h;
00894     }
00895     if ( x < desktopGeometry.x() ) {
00896         x = 0;
00897     }
00898     if ( y < desktopGeometry.y() ) {
00899         y = 0;
00900     }
00901 
00902     // Pop the thingy up.
00903     move( x, y );
00904     show();
00905     d->main->setFocus();
00906 }
00907 
00908 int KPopupFrame::exec( const QPoint &pos )
00909 {
00910     popup( pos );
00911     repaint();
00912     QEventLoop eventLoop;
00913     connect( this, SIGNAL( leaveModality() ),
00914              &eventLoop, SLOT( quit() ) );
00915     eventLoop.exec();
00916 
00917     hide();
00918     return d->result;
00919 }
00920 
00921 int KPopupFrame::exec( int x, int y )
00922 {
00923     return exec( QPoint( x, y ) );
00924 }
00925 
00926 #include "kdatetable.moc"

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal