• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • 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 <kdebug.h>
00029 #include <knotification.h>
00030 #include <kcalendarsystem.h>
00031 #include <klocalizeddate.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/QStyle>
00045 #include <QtGui/QStyleOptionViewItem>
00046 #include <QtGui/QDialog>
00047 #include <QtGui/QActionEvent>
00048 #include <QtCore/QHash>
00049 #include <QtGui/QApplication>
00050 #include <assert.h>
00051 
00052 #include <cmath>
00053 
00054 class KDateTable::KDateTablePrivate
00055 {
00056 public:
00057     KDateTablePrivate( KDateTable *q ): q( q )
00058     {
00059         m_popupMenuEnabled = false;
00060         m_useCustomColors = false;
00061         m_hoveredPos = -1;
00062         setDate( QDate::currentDate() );
00063     }
00064 
00065     ~KDateTablePrivate()
00066     {
00067     }
00068 
00069     void setDate( const QDate& date );
00070     void nextMonth();
00071     void previousMonth();
00072     void beginningOfMonth();
00073     void endOfMonth();
00074     void beginningOfWeek();
00075     void endOfWeek();
00076 
00077     KDateTable *q;
00078 
00082     int fontsize;
00083 
00087     KLocalizedDate m_date;
00088     // Need to keep a QDate copy as the "const QDate &date() const;" method returns a reference
00089     // and returning m_date.date() creates a temporary leading to crashes.  Doh!
00090     QDate m_refDate;
00091 
00095     int m_weekDayFirstOfMonth;
00096 
00100     int m_numDaysThisMonth;
00101 
00105     QRectF m_maxCell;
00106 
00110     int m_numWeekRows;
00111 
00115     int m_numDayColumns;
00116 
00117     bool m_popupMenuEnabled;
00118     bool m_useCustomColors;
00119 
00120     struct DatePaintingMode
00121     {
00122         QColor fgColor;
00123         QColor bgColor;
00124         BackgroundMode bgMode;
00125     };
00126     QHash <int, DatePaintingMode*> m_customPaintingModes;
00127 
00128     int m_hoveredPos;
00129 };
00130 
00131 
00132 class KPopupFrame::KPopupFramePrivate
00133 {
00134 public:
00135     KPopupFramePrivate( KPopupFrame *q );
00136     ~KPopupFramePrivate();
00137 
00138     KPopupFrame *q;
00139 
00143     int result;
00144 
00148     QWidget *main;
00149 
00150     // ### KDE 5: Remove this, add a hideEvent() reimplementation instead.
00151     class OutsideClickCatcher;
00152     OutsideClickCatcher *outsideClickCatcher;
00153 };
00154 
00155 
00156 class KPopupFrame::KPopupFramePrivate::OutsideClickCatcher
00157     : public QObject
00158 {
00159 public:
00160     OutsideClickCatcher(QObject *parent = 0)
00161         : QObject(parent), m_popup(0) { }
00162     ~OutsideClickCatcher() { }
00163 
00164     void setPopupFrame(KPopupFrame *popup)
00165     {
00166         m_popup = popup;
00167         popup->installEventFilter(this);
00168     }
00169 
00170     KPopupFrame *m_popup;
00171 
00172     bool eventFilter(QObject *object, QEvent *event)
00173     {
00174         Q_UNUSED(object);
00175 
00176         // To catch outside clicks, it is sufficient to check for
00177         // hide events on Qt::Popup type widgets
00178         if (event->type() == QEvent::Hide && m_popup) {
00179             // do not set d->result here, because the popup
00180             // hides itself after leaving the event loop.
00181             emit m_popup->leaveModality();
00182         }
00183         return false;
00184     }
00185 };
00186 
00187 
00188 KPopupFrame::KPopupFramePrivate::KPopupFramePrivate( KPopupFrame *q ):
00189     q( q ),
00190     result( 0 ), // rejected
00191     main( 0 ),
00192     outsideClickCatcher(new OutsideClickCatcher)
00193 {
00194     outsideClickCatcher->setPopupFrame(q);
00195 }
00196 
00197 KPopupFrame::KPopupFramePrivate::~KPopupFramePrivate()
00198 {
00199     delete outsideClickCatcher;
00200 }
00201 
00202 
00203 class KDateValidator::KDateValidatorPrivate
00204 {
00205 public:
00206     KDateValidatorPrivate( KDateValidator *q ): q( q )
00207     {
00208     }
00209 
00210     ~KDateValidatorPrivate()
00211     {
00212     }
00213 
00214     KDateValidator *q;
00215 };
00216 
00217 KDateValidator::KDateValidator( QWidget *parent ) : QValidator( parent ), d( 0 )
00218 {
00219 }
00220 
00221 QValidator::State KDateValidator::validate( QString &text, int &unused ) const
00222 {
00223     Q_UNUSED( unused );
00224 
00225     QDate temp;
00226     // ----- everything is tested in date():
00227     return date( text, temp );
00228 }
00229 
00230 QValidator::State KDateValidator::date( const QString &text, QDate &d ) const
00231 {
00232     //FIXME This is wrong if the widget is not using the global!
00233     QDate tmp = KGlobal::locale()->readDate( text );
00234     if ( KGlobal::locale()->calendar()->isValid( tmp ) ) {
00235         d = tmp;
00236         return Acceptable;
00237     } else {
00238         return QValidator::Intermediate;
00239     }
00240 }
00241 
00242 void KDateValidator::fixup( QString& ) const
00243 {
00244 }
00245 
00246 KDateTable::KDateTable( const QDate& date, QWidget* parent )
00247            : QWidget( parent ),
00248              d( new KDateTablePrivate( this ) )
00249 {
00250     init( date );
00251 }
00252 
00253 KDateTable::KDateTable( QWidget *parent )
00254            : QWidget( parent ),
00255              d( new KDateTablePrivate( this ) )
00256 {
00257     init( QDate::currentDate() );
00258 }
00259 
00260 KDateTable::~KDateTable()
00261 {
00262     delete d;
00263 }
00264 
00265 void KDateTable::init( const QDate &date )
00266 {
00267     d->m_numWeekRows = 7;
00268 
00269     setFontSize( 10 );
00270     setFocusPolicy( Qt::StrongFocus );
00271     setBackgroundRole(QPalette::Base);
00272     setAutoFillBackground(true);
00273     initAccels();
00274     setAttribute(Qt::WA_Hover, true);
00275 
00276     setDate( date );
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 
00314 int KDateTable::posFromDate( const QDate &date )
00315 {
00316     int initialPosition = calendar()->day( date );
00317     int offset = ( d->m_weekDayFirstOfMonth - calendar()->weekStartDay() + d->m_numDayColumns ) % d->m_numDayColumns;
00318 
00319     // make sure at least one day of the previous month is visible.
00320     // adjust this < 1 if more days should be forced visible:
00321     if ( offset < 1 ) {
00322         offset += d->m_numDayColumns;
00323     }
00324 
00325     return initialPosition + offset;
00326 }
00327 
00328 QDate KDateTable::dateFromPos( int position )
00329 {
00330     int offset = ( d->m_weekDayFirstOfMonth - calendar()->weekStartDay() + d->m_numDayColumns ) % d->m_numDayColumns;
00331 
00332     // make sure at least one day of the previous month is visible.
00333     // adjust this < 1 if more days should be forced visible:
00334     if ( offset < 1 ) {
00335         offset += d->m_numDayColumns;
00336     }
00337 
00338     return d->m_date.firstDayOfMonth().addDays( position - offset ).date();
00339 }
00340 
00341 void KDateTable::paintEvent( QPaintEvent *e )
00342 {
00343     QPainter p( this );
00344     KColorScheme colorScheme(palette().currentColorGroup(), KColorScheme::View);
00345     const QRect &rectToUpdate = e->rect();
00346     double cellWidth = width() / ( double ) d->m_numDayColumns;
00347     double cellHeight = height() / ( double ) d->m_numWeekRows;
00348     int leftCol = ( int )std::floor( rectToUpdate.left() / cellWidth );
00349     int topRow = ( int )std::floor( rectToUpdate.top() / cellHeight );
00350     int rightCol = ( int )std::ceil( rectToUpdate.right() / cellWidth );
00351     int bottomRow = ( int )std::ceil( rectToUpdate.bottom() / cellHeight );
00352     bottomRow = qMin( bottomRow, d->m_numWeekRows - 1 );
00353     rightCol = qMin( rightCol, d->m_numDayColumns - 1 );
00354     if ( layoutDirection() == Qt::RightToLeft ) {
00355         p.translate( ( d->m_numDayColumns - leftCol - 1 ) * cellWidth, topRow * cellHeight );
00356     } else {
00357         p.translate( leftCol * cellWidth, topRow * cellHeight );
00358     }
00359     for ( int i = leftCol; i <= rightCol; ++i ) {
00360         for ( int j = topRow; j <= bottomRow; ++j ) {
00361             paintCell( &p, j, i, colorScheme );
00362             p.translate( 0, cellHeight );
00363         }
00364         if ( layoutDirection() == Qt::RightToLeft ) {
00365             p.translate( -cellWidth, 0 );
00366         } else {
00367             p.translate( cellWidth, 0 );
00368         }
00369         p.translate( 0, -cellHeight * ( bottomRow - topRow + 1 ) );
00370     }
00371 }
00372 
00373 void KDateTable::paintCell( QPainter *painter, int row, int col, const KColorScheme &colorScheme )
00374 {
00375     double w = ( width() / ( double ) d->m_numDayColumns ) - 1;
00376     double h = ( height() / ( double ) d->m_numWeekRows ) - 1;
00377     QRectF cell = QRectF( 0, 0, w, h );
00378     QString cellText;
00379     QPen pen;
00380     QColor cellBackgroundColor, cellTextColor;
00381     QFont cellFont = KGlobalSettings::generalFont();
00382     bool workingDay = false;
00383     int cellWeekDay, pos;
00384     BackgroundMode cellBackgroundMode = RectangleMode;
00385 
00386     //Calculate the position of the cell in the grid
00387     pos = d->m_numDayColumns * ( row - 1 ) + col;
00388 
00389     //Calculate what day of the week the cell is
00390     if ( col + calendar()->weekStartDay() <= d->m_numDayColumns ) {
00391         cellWeekDay = col + calendar()->weekStartDay();
00392     } else {
00393         cellWeekDay = col + calendar()->weekStartDay() - d->m_numDayColumns;
00394     }
00395 
00396     //FIXME This is wrong if the widget is not using the global!
00397     //See if cell day is normally a working day
00398     if ( KGlobal::locale()->workingWeekStartDay() <= KGlobal::locale()->workingWeekEndDay() ) {
00399         if ( cellWeekDay >= KGlobal::locale()->workingWeekStartDay() &&
00400              cellWeekDay <= KGlobal::locale()->workingWeekEndDay() ) {
00401                 workingDay = true;
00402         }
00403     } else {
00404         if ( cellWeekDay >= KGlobal::locale()->workingWeekStartDay() ||
00405              cellWeekDay <= KGlobal::locale()->workingWeekEndDay() ) {
00406                 workingDay = true;
00407         }
00408     }
00409 
00410     if( row == 0 ) {
00411 
00412         //We are drawing a header cell
00413 
00414         //If not a normal working day, then use "do not work today" color
00415         if ( workingDay ) {
00416             cellTextColor = palette().color(QPalette::WindowText);
00417         } else {
00418             KColorScheme colorScheme(palette().currentColorGroup(), KColorScheme::Window);
00419             cellTextColor = colorScheme.foreground(KColorScheme::NegativeText).color();
00420         }
00421         cellBackgroundColor = palette().color(QPalette::Window);
00422 
00423         //Set the text to the short day name and bold it
00424         cellFont.setBold( true );
00425         cellText = calendar()->weekDayName( cellWeekDay, KCalendarSystem::ShortDayName );
00426 
00427     } else {
00428 
00429         //We are drawing a day cell
00430 
00431         //Calculate the date the cell represents
00432         //Copy current date to get same calendar system & locale
00433         KLocalizedDate cellDate = d->m_date;
00434         cellDate = dateFromPos( pos );
00435 
00436         bool validDay = cellDate.isValid();
00437 
00438         // Draw the day number in the cell, if the date is not valid then we don't want to show it
00439         if ( validDay ) {
00440             cellText = cellDate.formatDate( KLocale::Day, KLocale::ShortNumber );
00441         } else {
00442             cellText = "";
00443         }
00444 
00445         if( ! validDay || cellDate.month() != d->m_date.month() ) {
00446             // we are either
00447             // ° painting an invalid day
00448             // ° painting a day of the previous month or
00449             // ° painting a day of the following month or
00450             cellBackgroundColor = palette().color(backgroundRole());
00451             cellTextColor = colorScheme.foreground(KColorScheme::InactiveText).color();
00452         } else {
00453             //Paint a day of the current month
00454 
00455             // Background Colour priorities will be (high-to-low):
00456             // * Selected Day Background Colour
00457             // * Customized Day Background Colour
00458             // * Normal Day Background Colour
00459 
00460             // Background Shape priorities will be (high-to-low):
00461             // * Customized Day Shape
00462             // * Normal Day Shape
00463 
00464             // Text Colour priorities will be (high-to-low):
00465             // * Customized Day Colour
00466             // * Day of Pray Colour (Red letter)
00467             // * Selected Day Colour
00468             // * Normal Day Colour
00469 
00470             //Determine various characteristics of the cell date
00471             bool selectedDay = ( cellDate == date() );
00472             bool currentDay = ( cellDate == QDate::currentDate() );
00473             bool dayOfPray = ( cellDate.dayOfWeek() == calendar()->weekDayOfPray() );
00474             bool customDay = ( d->m_useCustomColors && d->m_customPaintingModes.contains(cellDate.toJulianDay()) );
00475 
00476             //Default values for a normal cell
00477             cellBackgroundColor = palette().color( backgroundRole() );
00478             cellTextColor = palette().color( foregroundRole() );
00479 
00480             // If we are drawing the current date, then draw it bold and active
00481             if ( currentDay ) {
00482                 cellFont.setBold( true );
00483                 cellTextColor = colorScheme.foreground(KColorScheme::ActiveText).color();
00484             }
00485 
00486             // if we are drawing the day cell currently selected in the table
00487             if ( selectedDay ) {
00488                 // set the background to highlighted
00489                 cellBackgroundColor = palette().color( QPalette::Highlight );
00490                 cellTextColor = palette().color( QPalette::HighlightedText );
00491             }
00492 
00493             //If custom colors or shape are required for this date
00494             if ( customDay ) {
00495                 KDateTablePrivate::DatePaintingMode * mode = d->m_customPaintingModes[cellDate.toJulianDay()];
00496                 if ( mode->bgMode != NoBgMode ) {
00497                         cellBackgroundMode = mode->bgMode;
00498                         if (!selectedDay) cellBackgroundColor = mode->bgColor;
00499                 }
00500                 cellTextColor = mode->fgColor;
00501             }
00502 
00503             //If the cell day is the day of religious observance, then always color text red unless Custom overrides
00504             if ( ! customDay && dayOfPray ) {
00505                 KColorScheme colorScheme(palette().currentColorGroup(),
00506                                          selectedDay ? KColorScheme::Selection : KColorScheme::View);
00507                 cellTextColor = colorScheme.foreground(KColorScheme::NegativeText).color();
00508             }
00509 
00510         }
00511     }
00512 
00513     //Draw the background
00514     if (row == 0) {
00515         painter->setPen( cellBackgroundColor );
00516         painter->setBrush( cellBackgroundColor );
00517         painter->drawRect( cell );
00518     } else if (cellBackgroundColor != palette().color(backgroundRole()) || pos == d->m_hoveredPos) {
00519         QStyleOptionViewItemV4 opt;
00520         opt.initFrom(this);
00521         opt.rect = cell.toRect();
00522         if (cellBackgroundColor != palette().color(backgroundRole())) {
00523             opt.palette.setBrush(QPalette::Highlight, cellBackgroundColor);
00524             opt.state |= QStyle::State_Selected;
00525         }
00526         if (pos == d->m_hoveredPos && opt.state & QStyle::State_Enabled) {
00527             opt.state |= QStyle::State_MouseOver;
00528         } else {
00529             opt.state &= ~QStyle::State_MouseOver;
00530         }
00531         opt.showDecorationSelected = true;
00532         opt.viewItemPosition = QStyleOptionViewItemV4::OnlyOne;
00533         style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, this);
00534     }
00535 
00536     //Draw the text
00537     painter->setPen( cellTextColor );
00538     painter->setFont( cellFont );
00539     painter->drawText( cell, Qt::AlignCenter, cellText, &cell );
00540 
00541     //Draw the base line
00542     if (row == 0) {
00543         painter->setPen( palette().color(foregroundRole()) );
00544         painter->drawLine( QPointF( 0, h ), QPointF( w, h ) );
00545     }
00546 
00547     // If the day cell we just drew is bigger than the current max cell sizes,
00548     // then adjust the max to the current cell
00549     if ( cell.width() > d->m_maxCell.width() ) d->m_maxCell.setWidth( cell.width() );
00550     if ( cell.height() > d->m_maxCell.height() ) d->m_maxCell.setHeight( cell.height() );
00551 }
00552 
00553 void KDateTable::KDateTablePrivate::nextMonth()
00554 {
00555     // setDate does validity checking for us
00556     q->setDate( m_date.addMonths( 1 ).date() );
00557 }
00558 
00559 void KDateTable::KDateTablePrivate::previousMonth()
00560 {
00561     // setDate does validity checking for us
00562     q->setDate( m_date.addMonths( -1 ).date() );
00563 }
00564 
00565 void KDateTable::KDateTablePrivate::beginningOfMonth()
00566 {
00567     // setDate does validity checking for us
00568     q->setDate( m_date.firstDayOfMonth().date() );
00569 }
00570 
00571 void KDateTable::KDateTablePrivate::endOfMonth()
00572 {
00573     // setDate does validity checking for us
00574     q->setDate( m_date.lastDayOfMonth().date() );
00575 }
00576 
00577 // JPL Do these make the assumption that first day of week is weekday 1? As it may not be.
00578 void KDateTable::KDateTablePrivate::beginningOfWeek()
00579 {
00580     // setDate does validity checking for us
00581     q->setDate( m_date.addDays( 1 - m_date.dayOfWeek() ).date() );
00582 }
00583 
00584 // JPL Do these make the assumption that first day of week is weekday 1? As it may not be.
00585 void KDateTable::KDateTablePrivate::endOfWeek()
00586 {
00587     // setDate does validity checking for us
00588     q->setDate( m_date.addDays( m_date.daysInWeek() - m_date.dayOfWeek() ).date() );
00589 }
00590 
00591 void KDateTable::keyPressEvent( QKeyEvent *e )
00592 {
00593     switch( e->key() ) {
00594     case Qt::Key_Up:
00595         // setDate does validity checking for us
00596         setDate( d->m_date.addDays( - d->m_numDayColumns ).date() );
00597         break;
00598     case Qt::Key_Down:
00599         // setDate does validity checking for us
00600         setDate( d->m_date.addDays( d->m_numDayColumns ).date() );
00601         break;
00602     case Qt::Key_Left:
00603         // setDate does validity checking for us
00604         setDate( d->m_date.addDays( -1 ).date() );
00605         break;
00606     case Qt::Key_Right:
00607         // setDate does validity checking for us
00608         setDate( d->m_date.addDays( 1 ).date() );
00609         break;
00610     case Qt::Key_Minus:
00611         // setDate does validity checking for us
00612         setDate( d->m_date.addDays( -1 ).date() );
00613         break;
00614     case Qt::Key_Plus:
00615         // setDate does validity checking for us
00616         setDate( d->m_date.addDays( 1 ).date() );
00617         break;
00618     case Qt::Key_N:
00619         // setDate does validity checking for us
00620         setDate( QDate::currentDate() );
00621         break;
00622     case Qt::Key_Return:
00623     case Qt::Key_Enter:
00624         emit tableClicked();
00625         break;
00626     case Qt::Key_Control:
00627     case Qt::Key_Alt:
00628     case Qt::Key_Meta:
00629     case Qt::Key_Shift:
00630         // Don't beep for modifiers
00631         break;
00632     default:
00633         if ( !e->modifiers() ) { // hm
00634             KNotification::beep();
00635         }
00636     }
00637 }
00638 
00639 void KDateTable::setFontSize( int size )
00640 {
00641     QFontMetricsF metrics( fontMetrics() );
00642     QRectF rect;
00643     // ----- store rectangles:
00644     d->fontsize = size;
00645     // ----- find largest day name:
00646     d->m_maxCell.setWidth( 0 );
00647     d->m_maxCell.setHeight( 0 );
00648     for( int weekday = 1; weekday <= d->m_date.daysInWeek(); ++weekday ) {
00649         rect = metrics.boundingRect( calendar()->weekDayName( weekday, KCalendarSystem::ShortDayName ) );
00650         d->m_maxCell.setWidth( qMax( d->m_maxCell.width(), rect.width() ) );
00651         d->m_maxCell.setHeight( qMax( d->m_maxCell.height(), rect.height() ) );
00652     }
00653     // ----- compare with a real wide number and add some space:
00654     rect = metrics.boundingRect( QLatin1String( "88" ) );
00655     d->m_maxCell.setWidth( qMax( d->m_maxCell.width() + 2, rect.width() ) );
00656     d->m_maxCell.setHeight( qMax( d->m_maxCell.height() + 4, rect.height() ) );
00657 }
00658 
00659 void KDateTable::wheelEvent ( QWheelEvent * e )
00660 {
00661     setDate( d->m_date.addMonths( -( int )( e->delta() / 120 ) ).date() );
00662     e->accept();
00663 }
00664 
00665 bool KDateTable::event(QEvent *ev)
00666 {
00667     switch (ev->type()) {
00668         case QEvent::HoverMove:
00669         {
00670             QHoverEvent *e = static_cast<QHoverEvent *>(ev);
00671             const int row = e->pos().y() * d->m_numWeekRows / height();
00672             int col;
00673             if ( layoutDirection() == Qt::RightToLeft ) {
00674                 col = d->m_numDayColumns - ( e->pos().x() * d->m_numDayColumns / width() ) - 1;
00675             } else {
00676                 col = e->pos().x() * d->m_numDayColumns / width();
00677             }
00678 
00679             const int pos = row < 1 ? -1 : (d->m_numDayColumns * (row - 1)) + col;
00680 
00681             if (pos != d->m_hoveredPos) {
00682                 d->m_hoveredPos = pos;
00683                 update();
00684             }
00685             break;
00686         }
00687         case QEvent::HoverLeave:
00688             if (d->m_hoveredPos != -1) {
00689                 d->m_hoveredPos = -1;
00690                 update();
00691             }
00692             break;
00693         default:
00694             break;
00695     }
00696     return QWidget::event(ev);
00697 }
00698 
00699 void KDateTable::mousePressEvent( QMouseEvent *e )
00700 {
00701     if( e->type() != QEvent::MouseButtonPress ) { // the KDatePicker only reacts on mouse press events:
00702         return;
00703     }
00704 
00705     if( !isEnabled() ) {
00706         KNotification::beep();
00707         return;
00708     }
00709 
00710     int row, col, pos, temp;
00711 
00712     QPoint mouseCoord = e->pos();
00713     row = mouseCoord.y() * d->m_numWeekRows / height();
00714     if ( layoutDirection() == Qt::RightToLeft ) {
00715         col = d->m_numDayColumns - ( mouseCoord.x() * d->m_numDayColumns / width() ) - 1;
00716     } else {
00717         col = mouseCoord.x() * d->m_numDayColumns / width();
00718     }
00719 
00720     if( row < 1 || col < 0 ) { // the user clicked on the frame of the table
00721         return;
00722     }
00723 
00724     // Rows and columns are zero indexed.  The (row - 1) below is to avoid counting
00725     // the row with the days of the week in the calculation.
00726 
00727     // old selected date:
00728     temp = posFromDate( date() );
00729 
00730     // new position and date
00731     pos = ( d->m_numDayColumns * ( row - 1 ) ) + col;
00732     QDate clickedDate = dateFromPos( pos );
00733 
00734     // set the new date. If it is in the previous or next month, the month will
00735     // automatically be changed, no need to do that manually...
00736     // validity checking done inside setDate
00737     setDate( clickedDate );
00738 
00739     // This could be optimized to only call update over the regions
00740     // of old and new cell, but 99% of times there is also a call to
00741     // setDate that already calls update() so no need to optimize that
00742     // much here
00743     update();
00744 
00745     emit tableClicked();
00746 
00747     if (  e->button() == Qt::RightButton && d->m_popupMenuEnabled ) {
00748         KMenu * menu = new KMenu();
00749         menu->addTitle( d->m_date.formatDate() );
00750         emit aboutToShowContextMenu( menu, clickedDate );
00751         menu->popup( e->globalPos() );
00752     }
00753 }
00754 
00755 void KDateTable::KDateTablePrivate::setDate( const QDate& date )
00756 {
00757     m_date.setDate( date );
00758     m_refDate = date;
00759     m_weekDayFirstOfMonth = m_date.firstDayOfMonth().dayOfWeek();
00760     m_numDaysThisMonth = m_date.daysInMonth();
00761     m_numDayColumns = m_date.daysInWeek();
00762 }
00763 
00764 bool KDateTable::setDate( const QDate& toDate )
00765 {
00766     if ( !calendar()->isValid( toDate ) ) {
00767         return false;
00768     }
00769 
00770     if ( toDate == date() ) {
00771         return true;
00772     }
00773 
00774     QDate oldDate = date();
00775     d->setDate( toDate );
00776     emit( dateChanged( date(), oldDate ) );
00777     emit( dateChanged( date() ) );
00778     update();
00779 
00780     return true;
00781 }
00782 
00783 const QDate &KDateTable::date() const
00784 {
00785     return d->m_refDate;
00786 }
00787 
00788 const KCalendarSystem *KDateTable::calendar() const
00789 {
00790     return  d->m_date.calendar();
00791 }
00792 
00793 bool KDateTable::setCalendar( KCalendarSystem *newCalendar )
00794 {
00795     QDate oldDate = date();
00796     d->m_date = KLocalizedDate( oldDate, newCalendar );
00797     return setDate( oldDate );
00798 }
00799 
00800 bool KDateTable::setCalendar( const QString &newCalendarType )
00801 {
00802     return setCalendarSystem( KCalendarSystem::calendarSystemForCalendarType( newCalendarType ) );
00803 }
00804 
00805 bool KDateTable::setCalendarSystem( KLocale::CalendarSystem newCalendarSystem )
00806 {
00807     d->m_date.setCalendarSystem( newCalendarSystem );
00808     return true;
00809 }
00810 
00811 void KDateTable::focusInEvent( QFocusEvent *e )
00812 {
00813     QWidget::focusInEvent( e );
00814 }
00815 
00816 void KDateTable::focusOutEvent( QFocusEvent *e )
00817 {
00818     QWidget::focusOutEvent( e );
00819 }
00820 
00821 QSize KDateTable::sizeHint() const
00822 {
00823     if( d->m_maxCell.height() > 0 && d->m_maxCell.width() > 0 ) {
00824         return QSize( qRound( d->m_maxCell.width() * d->m_numDayColumns ),
00825                       ( qRound( d->m_maxCell.height() + 2 ) * d->m_numWeekRows ) );
00826     } else {
00827         kDebug() << "KDateTable::sizeHint: obscure failure - " << endl;
00828         return QSize( -1, -1 );
00829     }
00830 }
00831 
00832 void KDateTable::setPopupMenuEnabled( bool enable )
00833 {
00834     d->m_popupMenuEnabled = enable;
00835 }
00836 
00837 bool KDateTable::popupMenuEnabled() const
00838 {
00839     return d->m_popupMenuEnabled;
00840 }
00841 
00842 void KDateTable::setCustomDatePainting( const QDate &date, const QColor &fgColor, BackgroundMode bgMode, const QColor &bgColor )
00843 {
00844     if ( !fgColor.isValid() ) {
00845         unsetCustomDatePainting( date );
00846         return;
00847     }
00848 
00849     KDateTablePrivate::DatePaintingMode *mode = new KDateTablePrivate::DatePaintingMode;
00850     mode->bgMode = bgMode;
00851     mode->fgColor = fgColor;
00852     mode->bgColor = bgColor;
00853 
00854     d->m_customPaintingModes.insert( date.toJulianDay(), mode );
00855     d->m_useCustomColors = true;
00856     update();
00857 }
00858 
00859 void KDateTable::unsetCustomDatePainting( const QDate &date )
00860 {
00861     d->m_customPaintingModes.remove( date.toJulianDay() );
00862     if ( d->m_customPaintingModes.isEmpty() ) d->m_useCustomColors = false;
00863     update();
00864 }
00865 
00866 
00867 // JPL Shouldn't this be in own file as is used in a couple of places?  Or moved to private in KDE5?
00868 
00869 KPopupFrame::KPopupFrame( QWidget* parent )
00870             : QFrame( parent, Qt::Popup ), d( new KPopupFramePrivate( this ) )
00871 {
00872     setFrameStyle( QFrame::Box | QFrame::Raised );
00873     setMidLineWidth( 2 );
00874 }
00875 
00876 KPopupFrame::~KPopupFrame()
00877 {
00878     delete d;
00879 }
00880 
00881 void KPopupFrame::keyPressEvent( QKeyEvent* e )
00882 {
00883     if( e->key() == Qt::Key_Escape ) {
00884         d->result = 0; // rejected
00885         emit leaveModality();
00886         //qApp->exit_loop();
00887     }
00888 }
00889 
00890 void KPopupFrame::close( int r )
00891 {
00892     d->result = r;
00893     emit leaveModality();
00894     //qApp->exit_loop();
00895 }
00896 
00897 void KPopupFrame::setMainWidget( QWidget *m )
00898 {
00899     d->main = m;
00900     if( d->main ) {
00901         resize( d->main->width() + 2 * frameWidth(), d->main->height() + 2 * frameWidth() );
00902     }
00903 }
00904 
00905 void KPopupFrame::resizeEvent( QResizeEvent *e )
00906 {
00907     Q_UNUSED( e );
00908 
00909     if( d->main ) {
00910         d->main->setGeometry( frameWidth(), frameWidth(),
00911                               width() - 2 * frameWidth(), height() - 2 * frameWidth() );
00912     }
00913 }
00914 
00915 void KPopupFrame::popup( const QPoint &pos )
00916 {
00917     // Make sure the whole popup is visible.
00918     QRect desktopGeometry = KGlobalSettings::desktopGeometry( pos );
00919 
00920     int x = pos.x();
00921     int y = pos.y();
00922     int w = width();
00923     int h = height();
00924     if ( x + w > desktopGeometry.x() + desktopGeometry.width() ) {
00925         x = desktopGeometry.width() - w;
00926     }
00927     if ( y + h > desktopGeometry.y() + desktopGeometry.height() ) {
00928         y = desktopGeometry.height() - h;
00929     }
00930     if ( x < desktopGeometry.x() ) {
00931         x = 0;
00932     }
00933     if ( y < desktopGeometry.y() ) {
00934         y = 0;
00935     }
00936 
00937     // Pop the thingy up.
00938     move( x, y );
00939     show();
00940     d->main->setFocus();
00941 }
00942 
00943 int KPopupFrame::exec( const QPoint &pos )
00944 {
00945     popup( pos );
00946     repaint();
00947     d->result = 0; // rejected
00948     QEventLoop eventLoop;
00949     connect( this, SIGNAL( leaveModality() ),
00950              &eventLoop, SLOT( quit() ) );
00951     eventLoop.exec();
00952 
00953     hide();
00954     return d->result;
00955 }
00956 
00957 int KPopupFrame::exec( int x, int y )
00958 {
00959     return exec( QPoint( x, y ) );
00960 }
00961 
00962 #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
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
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