summaryrefslogtreecommitdiffstats
path: root/korganizer/komonthview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'korganizer/komonthview.cpp')
-rw-r--r--korganizer/komonthview.cpp1090
1 files changed, 1090 insertions, 0 deletions
diff --git a/korganizer/komonthview.cpp b/korganizer/komonthview.cpp
new file mode 100644
index 000000000..3c88bb01f
--- /dev/null
+++ b/korganizer/komonthview.cpp
@@ -0,0 +1,1090 @@
+/*
+ This file is part of KOrganizer.
+
+ Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+
+#include <qpopupmenu.h>
+#include <qfont.h>
+#include <qfontmetrics.h>
+#include <qkeycode.h>
+#include <qhbox.h>
+#include <qvbox.h>
+#include <qpushbutton.h>
+#include <qtooltip.h>
+#include <qpainter.h>
+#include <qcursor.h>
+#include <qlistbox.h>
+#include <qlayout.h>
+#include <qlabel.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <kiconloader.h>
+#include <kwordwrap.h>
+
+#include <kcalendarsystem.h>
+#include <libkcal/calfilter.h>
+#include <libkcal/calendar.h>
+#include <libkcal/incidenceformatter.h>
+#include <libkcal/calendarresources.h>
+
+#include "koprefs.h"
+#include "koglobals.h"
+#include "koincidencetooltip.h"
+#include "koeventpopupmenu.h"
+#include "kohelper.h"
+
+#include "komonthview.h"
+#include "komonthview.moc"
+
+//--------------------------------------------------------------------------
+
+KOMonthCellToolTip::KOMonthCellToolTip( QWidget *parent,
+ KNoScrollListBox *lv )
+ : QToolTip( parent )
+{
+ eventlist = lv;
+}
+
+void KOMonthCellToolTip::maybeTip( const QPoint & pos )
+{
+ QRect r;
+ QListBoxItem *it = eventlist->itemAt( pos );
+ MonthViewItem *i = static_cast<MonthViewItem*>( it );
+
+ if( i && KOPrefs::instance()->mEnableToolTips ) {
+ /* Calculate the rectangle. */
+ r=eventlist->itemRect( it );
+ /* Show the tip */
+ QString tipText( IncidenceFormatter::toolTipString( i->incidence() ) );
+ if ( !tipText.isEmpty() ) {
+ tip( r, tipText );
+ }
+ }
+}
+
+KNoScrollListBox::KNoScrollListBox( QWidget *parent, const char *name )
+ : QListBox( parent, name ),
+ mSqueezing( false )
+{
+ QPalette pal = palette();
+ pal.setColor( QColorGroup::Foreground, KOPrefs::instance()->agendaBgColor().dark( 150 ) );
+ pal.setColor( QColorGroup::Base, KOPrefs::instance()->agendaBgColor() );
+ setPalette( pal );
+}
+
+void KNoScrollListBox::setBackground( bool primary, bool workDay )
+{
+ QColor color;
+ if ( workDay ) {
+ color = KOPrefs::instance()->workingHoursColor();
+ } else {
+ color = KOPrefs::instance()->agendaBgColor();
+ }
+
+ QPalette pal = palette();
+ if ( primary ) {
+ pal.setColor( QColorGroup::Base, color );
+ } else {
+ pal.setColor( QColorGroup::Base, color.dark( 115 ) );
+ }
+ setPalette( pal );
+}
+
+void KNoScrollListBox::keyPressEvent( QKeyEvent *e )
+{
+ switch( e->key() ) {
+ case Key_Right:
+ scrollBy( 4, 0 );
+ break;
+ case Key_Left:
+ scrollBy( -4, 0 );
+ break;
+ case Key_Up:
+ if ( !count() ) break;
+ setCurrentItem( ( currentItem() + count() - 1 ) % count() );
+ if ( !itemVisible( currentItem() ) ) {
+ if ( (unsigned int)currentItem() == ( count() - 1 ) ) {
+ setTopItem( currentItem() - numItemsVisible() + 1 );
+ } else {
+ setTopItem( topItem() - 1 );
+ }
+ }
+ break;
+ case Key_Down:
+ if ( !count() ) break;
+ setCurrentItem( ( currentItem() + 1 ) % count() );
+ if( !itemVisible( currentItem() ) ) {
+ if( currentItem() == 0 ) {
+ setTopItem( 0 );
+ } else {
+ setTopItem( topItem() + 1 );
+ }
+ }
+ case Key_Shift:
+ emit shiftDown();
+ break;
+ default:
+ break;
+ }
+}
+
+void KNoScrollListBox::keyReleaseEvent( QKeyEvent *e )
+{
+ switch( e->key() ) {
+ case Key_Shift:
+ emit shiftUp();
+ break;
+ default:
+ break;
+ }
+}
+
+void KNoScrollListBox::mousePressEvent( QMouseEvent *e )
+{
+ QListBox::mousePressEvent( e );
+
+ if ( e->button() == RightButton ) {
+ emit rightClick();
+ }
+}
+
+void KNoScrollListBox::contentsMouseDoubleClickEvent ( QMouseEvent * e )
+{
+ QListBox::contentsMouseDoubleClickEvent( e );
+ QListBoxItem *item = itemAt( e->pos() );
+ if ( !item ) {
+ emit doubleClicked( item );
+ }
+}
+
+void KNoScrollListBox::resizeEvent( QResizeEvent *e )
+{
+ bool s = count() && ( maxItemWidth() > e->size().width() );
+ if ( mSqueezing || s )
+ triggerUpdate( false );
+
+ mSqueezing = s;
+ QListBox::resizeEvent( e );
+}
+
+MonthViewItem::MonthViewItem( Incidence *incidence, const QDateTime &qd,
+ const QString & s ) : QListBoxItem()
+{
+ setText( s );
+
+ mIncidence = incidence;
+ mDateTime = qd;
+
+ mEventPixmap = KOGlobals::self()->smallIcon( "appointment" );
+ mTodoPixmap = KOGlobals::self()->smallIcon( "todo" );
+ mTodoDonePixmap = KOGlobals::self()->smallIcon( "checkedbox" );
+ mAlarmPixmap = KOGlobals::self()->smallIcon( "bell" );
+ mRecurPixmap = KOGlobals::self()->smallIcon( "recur" );
+ mReplyPixmap = KOGlobals::self()->smallIcon( "mail_reply" );
+
+ mResourceColor = QColor();
+ mEvent = false;
+ mTodo = false;
+ mTodoDone = false;
+ mRecur = false;
+ mAlarm = false;
+ mReply = false;
+}
+
+void MonthViewItem::paint( QPainter *p )
+{
+#if QT_VERSION >= 0x030000
+ bool sel = isSelected();
+#else
+ bool sel = selected();
+#endif
+
+ QColor bgColor = palette().color( QPalette::Normal,
+ sel ? QColorGroup::Highlight : QColorGroup::Background );
+ int offset=0;
+ if ( KOPrefs::instance()->monthViewUsesResourceColor() &&
+ mResourceColor.isValid() ) {
+ p->setBackgroundColor( mResourceColor );
+ p->eraseRect( 0, 0, listBox()->maxItemWidth(), height( listBox() ) );
+ offset=2;
+ }
+ if ( KOPrefs::instance()->monthViewUsesCategoryColor() ) {
+ p->setBackgroundColor( bgColor );
+ p->eraseRect( offset, offset, listBox()->maxItemWidth()-2*offset, height( listBox() )-2*offset );
+ }
+ int x = 3;
+// Do NOT put on the event pixmap because it takes up too much space
+// if ( mEvent ) {
+// p->drawPixmap( x, 0, mEventPixmap );
+// x += mEventPixmap.width() + 2;
+// }
+ if ( mTodo ) {
+ p->drawPixmap( x, 0, mTodoPixmap );
+ x += mTodoPixmap.width() + 2;
+ }
+ if ( mTodoDone ) {
+ p->drawPixmap( x, 0, mTodoDonePixmap );
+ x += mTodoPixmap.width() + 2;
+ }
+ if ( mRecur ) {
+ p->drawPixmap( x, 0, mRecurPixmap );
+ x += mRecurPixmap.width() + 2;
+ }
+ if ( mAlarm ) {
+ p->drawPixmap( x, 0, mAlarmPixmap );
+ x += mAlarmPixmap.width() + 2;
+ }
+ if ( mReply ) {
+ p->drawPixmap(x, 0, mReplyPixmap );
+ x += mReplyPixmap.width() + 2;
+ }
+ QFontMetrics fm = p->fontMetrics();
+ int yPos;
+ int pmheight = QMAX( mRecurPixmap.height(),
+ QMAX( mAlarmPixmap.height(), mReplyPixmap.height() ) );
+ if( pmheight < fm.height() )
+ yPos = fm.ascent() + fm.leading()/2;
+ else
+ yPos = pmheight/2 - fm.height()/2 + fm.ascent();
+ QColor textColor = getTextColor( bgColor );
+ p->setPen( textColor );
+
+ KWordWrap::drawFadeoutText( p, x, yPos, listBox()->width() - x, text() );
+}
+
+int MonthViewItem::height( const QListBox *lb ) const
+{
+ return QMAX( QMAX( mRecurPixmap.height(), mReplyPixmap.height() ),
+ QMAX( mAlarmPixmap.height(), lb->fontMetrics().lineSpacing()+1) );
+}
+
+int MonthViewItem::width( const QListBox *lb ) const
+{
+ int x = 3;
+ if( mRecur ) {
+ x += mRecurPixmap.width()+2;
+ }
+ if( mAlarm ) {
+ x += mAlarmPixmap.width()+2;
+ }
+ if( mReply ) {
+ x += mReplyPixmap.width()+2;
+ }
+
+ return( x + lb->fontMetrics().boundingRect( text() ).width() + 1 );
+}
+
+
+MonthViewCell::MonthViewCell( KOMonthView *parent)
+ : QWidget( parent ),
+ mMonthView( parent ), mPrimary( false ), mHoliday( false )
+{
+ QVBoxLayout *topLayout = new QVBoxLayout( this );
+
+ mLabel = new QLabel( this );
+ mLabel->setFrameStyle( QFrame::Panel | QFrame::Plain );
+ mLabel->setLineWidth( 1 );
+ mLabel->setAlignment( AlignCenter );
+
+ mItemList = new KNoScrollListBox( this );
+ mItemList->setMinimumSize( 10, 10 );
+ mItemList->setFrameStyle( QFrame::Panel | QFrame::Plain );
+ mItemList->setLineWidth( 1 );
+
+ new KOMonthCellToolTip( mItemList->viewport(),
+ static_cast<KNoScrollListBox *>( mItemList ) );
+
+ topLayout->addWidget( mItemList );
+
+ mLabel->raise();
+
+ mStandardPalette = palette();
+
+ enableScrollBars( false );
+
+ updateConfig();
+
+ connect( mItemList, SIGNAL( doubleClicked( QListBoxItem *) ),
+ SLOT( defaultAction( QListBoxItem * ) ) );
+ connect( mItemList, SIGNAL( rightButtonPressed( QListBoxItem *,
+ const QPoint &) ),
+ SLOT( contextMenu( QListBoxItem * ) ) );
+ connect( mItemList, SIGNAL( clicked( QListBoxItem * ) ),
+ SLOT( select() ) );
+}
+
+void MonthViewCell::setDate( const QDate &date )
+{
+// kdDebug(5850) << "MonthViewCell::setDate(): " << date.toString() << endl;
+
+ mDate = date;
+
+ setFrameWidth();
+
+ QString text;
+ if ( KOGlobals::self()->calendarSystem()->day( date ) == 1 ) {
+ text = i18n("'Month day' for month view cells", "%1 %2")
+ .arg( KOGlobals::self()->calendarSystem()->monthName( date, true ) )
+ .arg( KOGlobals::self()->calendarSystem()->day(mDate) );
+ QFontMetrics fm( mLabel->font() );
+ mLabel->resize( mLabelSize + QSize( fm.width( text ), 0 ) );
+ } else {
+ mLabel->resize( mLabelSize );
+ text = QString::number( KOGlobals::self()->calendarSystem()->day(mDate) );
+ }
+ mLabel->setText( text );
+
+ resizeEvent( 0 );
+}
+
+QDate MonthViewCell::date() const
+{
+ return mDate;
+}
+
+void MonthViewCell::setFrameWidth()
+{
+ // show current day with a thicker frame
+ if ( mDate == QDate::currentDate() )
+ mItemList->setLineWidth( 3 );
+ else
+ mItemList->setLineWidth( 1 );
+}
+
+void MonthViewCell::setPrimary( bool primary )
+{
+ mPrimary = primary;
+
+ if ( mPrimary ) {
+ mLabel->setBackgroundMode( PaletteBase );
+ } else {
+ mLabel->setBackgroundMode( PaletteBackground );
+ }
+
+ mItemList->setBackground( mPrimary, KOGlobals::self()->isWorkDay( mDate ) );
+}
+
+bool MonthViewCell::isPrimary() const
+{
+ return mPrimary;
+}
+
+void MonthViewCell::setHoliday( bool holiday )
+{
+ mHoliday = holiday;
+
+ if ( holiday ) {
+ setPalette( mHolidayPalette );
+ } else {
+ setPalette( mStandardPalette );
+ }
+}
+
+void MonthViewCell::setHolidayString( const QString &holiday )
+{
+ mHolidayString = holiday;
+}
+
+void MonthViewCell::updateCell()
+{
+ setFrameWidth();
+
+ if ( mDate == QDate::currentDate() ) {
+ setPalette( mTodayPalette );
+
+ QPalette pal = mItemList->palette();
+ pal.setColor( QColorGroup::Foreground, KOPrefs::instance()->highlightColor() );
+ mItemList->setPalette( pal );
+ }
+ else {
+ if ( mHoliday )
+ setPalette( mHolidayPalette );
+ else
+ setPalette( mStandardPalette );
+
+ QPalette pal = mItemList->palette();
+ pal.setColor( QColorGroup::Foreground, KOPrefs::instance()->agendaBgColor().dark( 150 ) );
+ mItemList->setPalette( pal );
+ }
+
+ mItemList->clear();
+
+ if ( !mHolidayString.isEmpty() ) {
+ MonthViewItem *item = new MonthViewItem( 0, QDateTime( mDate ), mHolidayString );
+ item->setPalette( mHolidayPalette );
+ mItemList->insertItem( item );
+ }
+}
+
+class MonthViewCell::CreateItemVisitor :
+ public IncidenceBase::Visitor
+{
+ public:
+ CreateItemVisitor() : mItem(0) { emails = KOPrefs::instance()->allEmails(); }
+
+ bool act( IncidenceBase *incidence, QDate date, QPalette stdPal, int multiDay )
+ {
+ mItem = 0;
+ mDate = date;
+ mStandardPalette = stdPal;
+ mMultiDay = multiDay;
+ return incidence->accept( *this );
+ }
+ MonthViewItem *item() const { return mItem; }
+ QStringList emails;
+
+ protected:
+ bool visit( Event *event ) {
+ QString text;
+ QDateTime dt( mDate );
+ // take the time 0:00 into account, which is non-inclusive
+ QDate dtEnd = event->dtEnd().addSecs( event->doesFloat() ? 0 : -1).date();
+ int length = event->dtStart().daysTo( dtEnd );
+ if ( event->isMultiDay() ) {
+ if ( mDate == event->dtStart().date()
+ || ( mMultiDay == 0 && event->recursOn( mDate ) ) ) {
+ text = "(-- " + event->summary();
+ dt = event->dtStart();
+ } else if ( !event->doesRecur() && mDate == dtEnd
+ // last day of a recurring multi-day event?
+ || ( mMultiDay == length && event->recursOn( mDate.addDays( -length ) ) ) ) {
+ text = event->summary() + " --)";
+ } else if (!(event->dtStart().date().daysTo(mDate) % 7) && length > 7 ) {
+ text = "-- " + event->summary() + " --";
+ } else {
+ text = "----------------";
+ dt = QDateTime( mDate );
+ }
+ } else {
+ if (event->doesFloat())
+ text = event->summary();
+ else {
+ text = KGlobal::locale()->formatTime(event->dtStart().time());
+ dt.setTime( event->dtStart().time() );
+ text += ' ' + event->summary();
+ }
+ }
+
+ mItem = new MonthViewItem( event, dt, text );
+ mItem->setEvent( true );
+ if (KOPrefs::instance()->monthViewUsesCategoryColor()) {
+ QStringList categories = event->categories();
+ QString cat = categories.first();
+ if (cat.isEmpty()) {
+ mItem->setPalette(QPalette(KOPrefs::instance()->mEventColor, KOPrefs::instance()->mEventColor));
+ } else {
+ mItem->setPalette(QPalette(*(KOPrefs::instance()->categoryColor(cat)), *(KOPrefs::instance()->categoryColor(cat))));
+ }
+ } else {
+ mItem->setPalette( mStandardPalette );
+ }
+
+ Attendee *me = event->attendeeByMails( emails );
+ if ( me != 0 ) {
+ mItem->setReply( me->status() == Attendee::NeedsAction && me->RSVP() );
+ } else
+ mItem->setReply(false);
+ return true;
+ }
+ bool visit( Todo *todo ) {
+ QString text;
+ if ( !KOPrefs::instance()->showAllDayTodo() )
+ return false;
+ QDateTime dt( mDate );
+ if ( todo->hasDueDate() && !todo->doesFloat() ) {
+ text += KGlobal::locale()->formatTime( todo->dtDue().time() );
+ text += ' ';
+ dt.setTime( todo->dtDue().time() );
+ }
+ text += todo->summary();
+
+ mItem = new MonthViewItem( todo, dt, text );
+ if ( todo->doesRecur() ) {
+ mDate < todo->dtDue().date() ?
+ mItem->setTodoDone( true ) : mItem->setTodo( true );
+ }
+ else
+ todo->isCompleted() ? mItem->setTodoDone( true ) : mItem->setTodo( true );
+ mItem->setPalette( mStandardPalette );
+ return true;
+ }
+ protected:
+ MonthViewItem *mItem;
+ QDate mDate;
+ QPalette mStandardPalette;
+ int mMultiDay;
+};
+
+
+void MonthViewCell::addIncidence( Incidence *incidence, CreateItemVisitor& v, int multiDay )
+{
+ if ( v.act( incidence, mDate, mStandardPalette, multiDay ) ) {
+ MonthViewItem *item = v.item();
+ if ( item ) {
+ item->setAlarm( incidence->isAlarmEnabled() );
+ item->setRecur( incidence->recurrenceType() );
+
+ QColor resourceColor = KOHelper::resourceColor( mCalendar, incidence );
+ if ( !resourceColor.isValid() )
+ resourceColor = KOPrefs::instance()->mEventColor;
+ item->setResourceColor( resourceColor );
+
+ // FIXME: Find the correct position (time-wise) to insert the item.
+ // Currently, the items are displayed in "random" order instead of
+ // chronologically sorted.
+ uint i = 0;
+ int pos = -1;
+ QDateTime dt( item->incidenceDateTime() );
+
+ while ( i < mItemList->count() && pos<0 ) {
+ QListBoxItem *item = mItemList->item( i );
+ MonthViewItem *mvitem = dynamic_cast<MonthViewItem*>( item );
+ if ( mvitem && mvitem->incidenceDateTime()>dt ) {
+ pos = i;
+ }
+ ++i;
+ }
+ mItemList->insertItem( item, pos );
+ }
+ }
+}
+
+void MonthViewCell::removeIncidence( Incidence *incidence )
+{
+ for ( uint i = 0; i < mItemList->count(); ++i ) {
+ MonthViewItem *item = static_cast<MonthViewItem *>(mItemList->item( i ) );
+ if ( item && item->incidence() &&
+ item->incidence()->uid() == incidence->uid() ) {
+ mItemList->removeItem( i );
+ --i;
+ }
+ }
+}
+
+void MonthViewCell::updateConfig()
+{
+ setFont( KOPrefs::instance()->mMonthViewFont );
+
+ QFontMetrics fm( font() );
+ mLabelSize = fm.size( 0, "30" ) +
+ QSize( mLabel->frameWidth() * 2, mLabel->frameWidth() * 2 ) +
+ QSize( 2, 2 );
+// mStandardPalette = mOriginalPalette;
+ QColor bg = mStandardPalette.color( QPalette::Active, QColorGroup::Background );
+ int h,s,v;
+ bg.getHsv( &h, &s, &v );
+ if ( date().month() %2 == 0 ) {
+ if ( v < 128 ) {
+ bg = bg.light( 125 );
+ } else {
+ bg = bg.dark( 125 );
+ }
+ }
+ setPaletteBackgroundColor( bg );
+// mStandardPalette.setColor( QColorGroup::Background, bg);*/
+
+ mHolidayPalette = mStandardPalette;
+ mHolidayPalette.setColor( QColorGroup::Foreground,
+ KOPrefs::instance()->holidayColor() );
+ mHolidayPalette.setColor( QColorGroup::Text,
+ KOPrefs::instance()->holidayColor() );
+ mTodayPalette = mStandardPalette;
+ mTodayPalette.setColor( QColorGroup::Foreground,
+ KOPrefs::instance()->highlightColor() );
+ mTodayPalette.setColor( QColorGroup::Text,
+ KOPrefs::instance()->highlightColor() );
+ updateCell();
+
+ mItemList->setBackground( mPrimary, KOGlobals::self()->isWorkDay( mDate ) );
+}
+
+void MonthViewCell::enableScrollBars( bool enabled )
+{
+ if ( enabled ) {
+ mItemList->setVScrollBarMode( QScrollView::Auto );
+ mItemList->setHScrollBarMode( QScrollView::Auto );
+ } else {
+ mItemList->setVScrollBarMode( QScrollView::AlwaysOff );
+ mItemList->setHScrollBarMode( QScrollView::AlwaysOff );
+ }
+}
+
+Incidence *MonthViewCell::selectedIncidence()
+{
+ int index = mItemList->currentItem();
+ if ( index < 0 ) return 0;
+
+ MonthViewItem *item =
+ static_cast<MonthViewItem *>( mItemList->item( index ) );
+
+ if ( !item ) return 0;
+
+ return item->incidence();
+}
+
+QDate MonthViewCell::selectedIncidenceDate()
+{
+ QDate qd;
+ int index = mItemList->currentItem();
+ if ( index < 0 ) return qd;
+
+ MonthViewItem *item =
+ static_cast<MonthViewItem *>( mItemList->item( index ) );
+
+ if ( !item ) return qd;
+
+ return item->incidenceDateTime().date();
+}
+
+void MonthViewCell::select()
+{
+ // setSelectedCell will deselect currently selected cells
+ mMonthView->setSelectedCell( this );
+
+ if( KOPrefs::instance()->enableMonthScroll() )
+ enableScrollBars( true );
+
+ // don't mess up the cell when it represents today
+ if( mDate != QDate::currentDate() ) {
+ mItemList->setFrameStyle( QFrame::Sunken | QFrame::Panel );
+ mItemList->setLineWidth( 3 );
+ }
+}
+
+void MonthViewCell::deselect()
+{
+ mItemList->clearSelection();
+ mItemList->setFrameStyle( QFrame::Plain | QFrame::Panel );
+ setFrameWidth();
+
+ enableScrollBars( false );
+}
+
+void MonthViewCell::resizeEvent ( QResizeEvent * )
+{
+ mLabel->move( width() - mLabel->width(), height() - mLabel->height() );
+}
+
+void MonthViewCell::defaultAction( QListBoxItem *item )
+{
+ select();
+
+ if ( !item ) {
+ emit newEventSignal( date() );
+ } else {
+ MonthViewItem *eventItem = static_cast<MonthViewItem *>( item );
+ Incidence *incidence = eventItem->incidence();
+ if ( incidence ) mMonthView->defaultAction( incidence );
+ }
+}
+
+void MonthViewCell::contextMenu( QListBoxItem *item )
+{
+ select();
+
+ if ( item ) {
+ MonthViewItem *eventItem = static_cast<MonthViewItem *>( item );
+ Incidence *incidence = eventItem->incidence();
+ if ( incidence ) mMonthView->showEventContextMenu( incidence, date() );
+ }
+ else {
+ mMonthView->showGeneralContextMenu();
+ }
+}
+
+
+KOMonthView::KOMonthView( Calendar *calendar, QWidget *parent, const char *name )
+ : KOEventView( calendar, parent, name ),
+ mDaysPerWeek( 7 ), mNumWeeks( 6 ), mNumCells( mDaysPerWeek * mNumWeeks ),
+ mShortDayLabels( false ), mWidthLongDayLabel( 0 ), mSelectedCell( 0 )
+{
+ mCells.setAutoDelete( true );
+
+ QGridLayout *dayLayout = new QGridLayout( this );
+
+ QFont bfont = font();
+ bfont.setBold( true );
+
+ QFont mfont = bfont;
+ mfont.setPointSize( 20 );
+
+ // month name on top
+ mLabel = new QLabel( this );
+ mLabel->setFont( mfont );
+ mLabel->setAlignment( AlignCenter );
+ mLabel->setLineWidth( 0 );
+ mLabel->setFrameStyle( QFrame::Plain );
+
+ dayLayout->addMultiCellWidget( mLabel, 0, 0, 0, mDaysPerWeek );
+
+ // create the day of the week labels (Sun, Mon, etc) and add them to
+ // the layout.
+ mDayLabels.resize( mDaysPerWeek );
+ int i;
+ for( i = 0; i < mDaysPerWeek; i++ ) {
+ QLabel *label = new QLabel( this );
+ label->setFont( bfont );
+ label->setFrameStyle( QFrame::Panel | QFrame::Raised );
+ label->setLineWidth( 1 );
+ label->setAlignment( AlignCenter );
+
+ mDayLabels.insert( i, label );
+
+ dayLayout->addWidget( label, 1, i );
+ dayLayout->addColSpacing( i, 10 );
+ dayLayout->setColStretch( i, 1 );
+ }
+
+ int row, col;
+
+ mCells.resize( mNumCells );
+ for( row = 0; row < mNumWeeks; ++row ) {
+ for( col = 0; col < mDaysPerWeek; ++col ) {
+ MonthViewCell *cell = new MonthViewCell( this );
+ cell->setCalendar(calendar);
+ mCells.insert( row * mDaysPerWeek + col, cell );
+ dayLayout->addWidget( cell, row + 2, col );
+
+ connect( cell, SIGNAL( defaultAction( Incidence * ) ),
+ SLOT( defaultAction( Incidence * ) ) );
+ connect( cell, SIGNAL( newEventSignal( const QDate & ) ),
+ SIGNAL( newEventSignal( const QDate & ) ) );
+ }
+ dayLayout->setRowStretch( row + 2, 1 );
+ }
+
+ mEventContextMenu = eventPopup();
+
+ updateConfig();
+
+ emit incidenceSelected( 0 );
+}
+
+KOMonthView::~KOMonthView()
+{
+ delete mEventContextMenu;
+}
+
+int KOMonthView::maxDatesHint()
+{
+ return mNumCells;
+}
+
+int KOMonthView::currentDateCount()
+{
+ return mNumCells;
+}
+
+Incidence::List KOMonthView::selectedIncidences()
+{
+ Incidence::List selected;
+
+ if ( mSelectedCell ) {
+ Incidence *incidence = mSelectedCell->selectedIncidence();
+ if ( incidence ) selected.append( incidence );
+ }
+
+ return selected;
+}
+
+DateList KOMonthView::selectedDates()
+{
+ DateList selected;
+
+ if ( mSelectedCell ) {
+ QDate qd = mSelectedCell->selectedIncidenceDate();
+ if ( qd.isValid() ) selected.append( qd );
+ }
+
+ return selected;
+}
+
+bool KOMonthView::eventDurationHint( QDateTime &startDt, QDateTime &endDt, bool &allDay )
+{
+ if ( mSelectedCell ) {
+ startDt.setDate( mSelectedCell->date() );
+ endDt.setDate( mSelectedCell->date() );
+ allDay = true;
+ return true;
+ }
+ return false;
+}
+
+void KOMonthView::updateConfig()
+{
+ mWeekStartDay = KGlobal::locale()->weekStartDay();
+
+ QFontMetrics fontmetric( mDayLabels[0]->font() );
+ mWidthLongDayLabel = 0;
+
+ for ( int i = 0; i < 7; ++i ) {
+ int width =
+ fontmetric.width( KOGlobals::self()->calendarSystem()->weekDayName( i + 1 ) );
+ if ( width > mWidthLongDayLabel ) mWidthLongDayLabel = width;
+ }
+
+ updateDayLabels();
+
+ for ( uint i = 0; i < mCells.count(); ++i ) {
+ mCells[i]->updateConfig();
+ }
+}
+
+void KOMonthView::updateDayLabels()
+{
+ kdDebug(5850) << "KOMonthView::updateDayLabels()" << endl;
+
+ const KCalendarSystem*calsys=KOGlobals::self()->calendarSystem();
+ int currDay;
+ for ( int i = 0; i < 7; i++ ) {
+ currDay = i+mWeekStartDay;
+ if ( currDay > 7 ) currDay -= 7;
+ mDayLabels[i]->setText( calsys->weekDayName( currDay, mShortDayLabels ) );
+ }
+}
+
+void KOMonthView::showDates( const QDate &start, const QDate & )
+{
+// kdDebug(5850) << "KOMonthView::showDates(): " << start.toString() << endl;
+
+ const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
+
+ mDateToCell.clear();
+
+ // show first day of month on top for readability issues
+ mStartDate = start.addDays( -start.day() + 1 );
+ // correct begin of week
+ int weekdayCol=( mStartDate.dayOfWeek() + 7 - mWeekStartDay ) % 7;
+ mStartDate = mStartDate.addDays( -weekdayCol );
+
+ mLabel->setText( i18n( "monthname year", "%1 %2" )
+ .arg( calSys->monthName( start ) )
+ .arg( calSys->year( start ) ) );
+ if ( !KOPrefs::instance()->fullViewMonth() ) {
+ mLabel->show();
+ } else {
+ mLabel->hide();
+ }
+
+ bool primary = false;
+ uint i;
+ for( i = 0; i < mCells.size(); ++i ) {
+ QDate date = mStartDate.addDays( i );
+ if ( calSys->day( date ) == 1 ) {
+ primary = !primary;
+ }
+
+ mCells[i]->setDate( date );
+ mDateToCell[ date ] = mCells[ i ];
+ if( date == start )
+ mCells[i]->select();
+
+ mCells[i]->setPrimary( primary );
+
+ bool isHoliday = calSys->dayOfWeek( date ) == calSys->weekDayOfPray()
+ || !KOGlobals::self()->isWorkDay( date );
+ mCells[i]->setHoliday( isHoliday );
+
+ // add holiday, if present
+ QStringList holidays( KOGlobals::self()->holiday( date ) );
+ mCells[i]->setHolidayString( holidays.join( i18n("delimiter for joining holiday names", ", " ) ) );
+ }
+
+ updateView();
+}
+
+void KOMonthView::showIncidences( const Incidence::List & )
+{
+ kdDebug(5850) << "KOMonthView::showIncidences( const Incidence::List & ) is not implemented yet." << endl;
+}
+
+class KOMonthView::GetDateVisitor : public IncidenceBase::Visitor
+{
+ public:
+ GetDateVisitor() {}
+
+ bool act( IncidenceBase *incidence )
+ {
+ return incidence->accept( *this );
+ }
+ QDateTime startDate() const { return mStartDate; }
+ QDateTime endDate() const { return mEndDate; }
+
+ protected:
+ bool visit( Event *event ) {
+ mStartDate = event->dtStart();
+ mEndDate = event->dtEnd();
+ return true;
+ }
+ bool visit( Todo *todo ) {
+ if ( todo->hasDueDate() ) {
+ mStartDate = todo->dtDue();
+ mEndDate = todo->dtDue();
+ }// else
+// return false;
+ return true;
+ }
+ bool visit( Journal *journal ) {
+ mStartDate = journal->dtStart();
+ mEndDate = journal->dtStart();
+ return true;
+ }
+ protected:
+ QDateTime mStartDate;
+ QDateTime mEndDate;
+};
+
+void KOMonthView::changeIncidenceDisplayAdded( Incidence *incidence, MonthViewCell::CreateItemVisitor& v)
+{
+ GetDateVisitor gdv;
+
+ if ( !gdv.act( incidence ) ) {
+ kdDebug(5850) << "Visiting GetDateVisitor failed." << endl;
+ return;
+ }
+
+ bool floats = incidence->doesFloat();
+
+ if ( incidence->doesRecur() ) {
+ for ( uint i = 0; i < mCells.count(); ++i ) {
+ if ( incidence->recursOn( mCells[i]->date() ) ) {
+
+ // handle multiday events
+ int length = gdv.startDate().daysTo( gdv.endDate().addSecs( floats ? 0 : -1 ).date() );
+ for ( int j = 0; j <= length && i+j < mCells.count(); ++j ) {
+ mCells[i+j]->addIncidence( incidence, v, j );
+ }
+ }
+ }
+ } else {
+ // addSecs(-1) is added to handle 0:00 cases (because it's non-inclusive according to rfc)
+ if ( gdv.endDate().isValid() ) {
+ QDate endDate = gdv.endDate().addSecs( floats ? 0 : -1).date();
+ for ( QDate date = gdv.startDate().date();
+ date <= endDate; date = date.addDays( 1 ) ) {
+ MonthViewCell *mvc = mDateToCell[ date ];
+ if ( mvc ) mvc->addIncidence( incidence, v );
+ }
+ }
+ }
+}
+
+void KOMonthView::changeIncidenceDisplay( Incidence *incidence, int action )
+{
+ MonthViewCell::CreateItemVisitor v;
+ switch ( action ) {
+ case KOGlobals::INCIDENCEADDED:
+ changeIncidenceDisplayAdded( incidence, v );
+ break;
+ case KOGlobals::INCIDENCEEDITED:
+ for( uint i = 0; i < mCells.count(); i++ )
+ mCells[i]->removeIncidence( incidence );
+ changeIncidenceDisplayAdded( incidence, v );
+ break;
+ case KOGlobals::INCIDENCEDELETED:
+ for( uint i = 0; i < mCells.count(); i++ )
+ mCells[i]->removeIncidence( incidence );
+ break;
+ default:
+ return;
+ }
+}
+
+void KOMonthView::updateView()
+{
+ for( uint i = 0; i < mCells.count(); ++i ) {
+ mCells[i]->updateCell();
+ }
+
+ Incidence::List incidences = calendar()->incidences();
+ Incidence::List::ConstIterator it;
+
+ MonthViewCell::CreateItemVisitor v;
+ for ( it = incidences.begin(); it != incidences.end(); ++it )
+ changeIncidenceDisplayAdded( *it, v );
+
+ processSelectionChange();
+}
+
+void KOMonthView::resizeEvent( QResizeEvent * )
+{
+ // select the appropriate heading string size. E.g. "Wednesday" or "Wed".
+ // note this only changes the text if the requested size crosses the
+ // threshold between big enough to support the full name and not big
+ // enough.
+ if( mDayLabels[0]->width() < mWidthLongDayLabel ) {
+ if ( !mShortDayLabels ) {
+ mShortDayLabels = true;
+ updateDayLabels();
+ }
+ } else {
+ if ( mShortDayLabels ) {
+ mShortDayLabels = false;
+ updateDayLabels();
+ }
+ }
+}
+
+void KOMonthView::showEventContextMenu( Incidence *incidence, const QDate &qd )
+{
+ mEventContextMenu->showIncidencePopup( incidence, qd );
+}
+
+void KOMonthView::showGeneralContextMenu()
+{
+ showNewEventPopup();
+}
+
+void KOMonthView::setSelectedCell( MonthViewCell *cell )
+{
+ if ( mSelectedCell && cell != mSelectedCell )
+ mSelectedCell->deselect();
+
+ mSelectedCell = cell;
+
+ if ( !mSelectedCell )
+ emit incidenceSelected( 0 );
+ else
+ emit incidenceSelected( mSelectedCell->selectedIncidence() );
+}
+
+void KOMonthView::processSelectionChange()
+{
+ Incidence::List incidences = selectedIncidences();
+ if (incidences.count() > 0) {
+ emit incidenceSelected( incidences.first() );
+ } else {
+ emit incidenceSelected( 0 );
+ }
+}
+
+void KOMonthView::clearSelection()
+{
+ if ( mSelectedCell ) {
+ mSelectedCell->deselect();
+ mSelectedCell = 0;
+ }
+}