You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1091 lines
30 KiB
1091 lines
30 KiB
/*
|
|
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;
|
|
}
|
|
}
|