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