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.
tdepim/korganizer/komonthview.cpp

1222 lines
34 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 TQt, and distribute the resulting executable,
without including the source code for TQt in the source distribution.
*/
#include <tqpopupmenu.h>
#include <tqfont.h>
#include <tqfontmetrics.h>
#include <tqkeycode.h>
#include <tqhbox.h>
#include <tqvbox.h>
#include <tqpushbutton.h>
#include <tqtooltip.h>
#include <tqpainter.h>
#include <tqcursor.h>
#include <tqlistbox.h>
#include <layout.h>
#include <tqlabel.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( TQWidget *parent,
Calendar *calendar,
const TQDate &date,
KNoScrollListBox *lv )
: TQToolTip( parent ), mCalendar( calendar ), mDate( date )
{
eventlist = lv;
}
void KOMonthCellToolTip::maybeTip( const TQPoint &pos )
{
TQRect r;
TQListBoxItem *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 */
TQString tipText( IncidenceFormatter::toolTipStr( mCalendar, i->incidence(), mDate ) );
if ( !tipText.isEmpty() ) {
tip( r, tipText );
}
}
}
KNoScrollListBox::KNoScrollListBox( TQWidget *parent, const char *name )
: TQListBox( parent, name ),
mSqueezing( false )
{
TQPalette pal = palette();
pal.setColor( TQColorGroup::Foreground, KOPrefs::instance()->agendaBgColor().dark( 150 ) );
pal.setColor( TQColorGroup::Base, KOPrefs::instance()->agendaBgColor() );
setPalette( pal );
}
void KNoScrollListBox::setBackground( bool primary, bool workDay )
{
TQColor color;
if ( workDay ) {
color = KOPrefs::instance()->workingHoursColor();
} else {
color = KOPrefs::instance()->agendaBgColor();
}
TQPalette pal = palette();
if ( primary ) {
pal.setColor( TQColorGroup::Base, color );
} else {
pal.setColor( TQColorGroup::Base, color.dark( 115 ) );
}
setPalette( pal );
}
void KNoScrollListBox::keyPressEvent( TQKeyEvent *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( TQKeyEvent *e )
{
switch( e->key() ) {
case Key_Shift:
emit shiftUp();
break;
default:
break;
}
}
void KNoScrollListBox::mousePressEvent( TQMouseEvent *e )
{
TQListBox::mousePressEvent( e );
if ( e->button() == Qt::RightButton ) {
emit rightClick();
}
}
void KNoScrollListBox::contentsMouseDoubleClickEvent ( TQMouseEvent * e )
{
TQListBox::contentsMouseDoubleClickEvent( e );
TQListBoxItem *item = itemAt( e->pos() );
if ( !item ) {
emit doubleClicked( item );
}
}
void KNoScrollListBox::resizeEvent( TQResizeEvent *e )
{
bool s = count() && ( maxItemWidth() > e->size().width() );
if ( mSqueezing || s )
triggerUpdate( false );
mSqueezing = s;
TQListBox::resizeEvent( e );
}
MonthViewItem::MonthViewItem( Incidence *incidence, const TQDateTime &qd,
const TQString & s ) : TQListBoxItem()
{
setText( s );
mIncidence = incidence;
mDateTime = qd;
mEventPixmap = KOGlobals::self()->smallIcon( "appointment" );
mBirthdayPixmap = KOGlobals::self()->smallIcon( "calendarbirthday" );
mAnniversaryPixmap= KOGlobals::self()->smallIcon( "calendaranniversary" );
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" );
mEvent = false;
mTodo = false;
mTodoDone = false;
mRecur = false;
mAlarm = false;
mReply = false;
}
TQColor MonthViewItem::catColor() const
{
TQColor retColor;
if ( !mIncidence ) {
return retColor;
}
TQStringList categories = mIncidence->categories();
TQString cat;
if ( !categories.isEmpty() ) {
cat = categories.first();
}
if ( cat.isEmpty() ) {
retColor = KOPrefs::instance()->unsetCategoryColor();
} else {
retColor = *( KOPrefs::instance()->categoryColor( cat ) );
}
return retColor;
}
void MonthViewItem::paint( TQPainter *p )
{
bool sel = isSelected();
TQColor bgColor = TQColor(); // Default invalid color;
if ( mIncidence && mTodo ) {
if ( static_cast<Todo*>( mIncidence )->isOverdue() ) {
bgColor = KOPrefs::instance()->todoOverdueColor();
} else if ( static_cast<Todo*>( mIncidence )->dtDue().date() == TQDate::currentDate() ) {
bgColor = KOPrefs::instance()->todoDueTodayColor();
}
}
if ( !bgColor.isValid() ) {
if ( KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceOnly ||
KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceInsideCategoryOutside ) {
bgColor = resourceColor();
} else {
bgColor = catColor();
}
if ( !bgColor.isValid() ) {
bgColor = palette().color( TQPalette::Normal,
sel ? TQColorGroup::Highlight :
TQColorGroup::Background );
}
}
TQColor frameColor;
if ( KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceOnly ||
KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryInsideResourceOutside ) {
frameColor = resourceColor();
} else {
frameColor = catColor();
}
if ( mIncidence ) {
if ( mIncidence->categories().isEmpty() &&
KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceInsideCategoryOutside ) {
frameColor = bgColor;
}
if ( mIncidence->categories().isEmpty() &&
KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryInsideResourceOutside ) {
bgColor = frameColor;
}
}
if ( !frameColor.isValid() ) {
frameColor = palette().color( TQPalette::Normal,
sel ? TQColorGroup::Highlight :
TQColorGroup::Foreground );
} else {
frameColor = frameColor.dark( 115 );
}
// draw the box for the item
p->setBackgroundColor( frameColor );
p->eraseRect( 0, 0, listBox()->maxItemWidth(), height( listBox() ) );
int offset = 2;
p->setBackgroundColor( bgColor );
p->eraseRect( offset, offset, listBox()->maxItemWidth()-2*offset, height( listBox() )-2*offset );
int x = 3;
bool specialEvent = false;
if ( mEvent ) {
if ( mIncidence->customProperty( "KABC", "BIRTHDAY" ) == "YES" ) {
specialEvent = true;
if ( mIncidence->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) {
p->drawPixmap( x, 0, mAnniversaryPixmap );
x += mAnniversaryPixmap.width() + 2;
} else {
p->drawPixmap( x, 0, mBirthdayPixmap );
x += mBirthdayPixmap.width() + 2;
}
// Do NOT put on the event pixmap because it takes up too much space
//} else {
// 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 && !specialEvent ) {
p->drawPixmap( x, 0, mRecurPixmap );
x += mRecurPixmap.width() + 2;
}
if ( mAlarm && !specialEvent ) {
p->drawPixmap( x, 0, mAlarmPixmap );
x += mAlarmPixmap.width() + 2;
}
if ( mReply ) {
p->drawPixmap(x, 0, mReplyPixmap );
x += mReplyPixmap.width() + 2;
}
TQFontMetrics fm = p->fontMetrics();
int yPos;
int pmheight = TQMAX( mRecurPixmap.height(),
TQMAX( mAlarmPixmap.height(), mReplyPixmap.height() ) );
if( pmheight < fm.height() )
yPos = fm.ascent() + fm.leading()/2;
else
yPos = pmheight/2 - fm.height()/2 + fm.ascent();
TQColor textColor = getTextColor( bgColor );
p->setPen( textColor );
KWordWrap::drawFadeoutText( p, x, yPos, listBox()->width() - x, text() );
}
int MonthViewItem::height( const TQListBox *lb ) const
{
return TQMAX( TQMAX( mRecurPixmap.height(), mReplyPixmap.height() ),
TQMAX( mAlarmPixmap.height(), lb->fontMetrics().lineSpacing()+1) );
}
int MonthViewItem::width( const TQListBox *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)
: TQWidget( parent ),
mMonthView( parent ), mPrimary( false ), mHoliday( false ),
isSelected( false )
{
TQVBoxLayout *topLayout = new TQVBoxLayout( this );
mLabel = new TQLabel( this );
mLabel->setFrameStyle( TQFrame::Panel | TQFrame::Plain );
mLabel->setLineWidth( 1 );
mLabel->setAlignment( AlignCenter );
mItemList = new KNoScrollListBox( this );
mItemList->setMinimumSize( 10, 10 );
mItemList->setFrameStyle( TQFrame::Panel | TQFrame::Plain );
mItemList->setLineWidth( 1 );
topLayout->addWidget( mItemList );
mLabel->raise();
mStandardPalette = palette();
enableScrollBars( false );
updateConfig();
connect( mItemList, TQT_SIGNAL( doubleClicked( TQListBoxItem *) ),
TQT_SLOT( defaultAction( TQListBoxItem * ) ) );
connect( mItemList, TQT_SIGNAL( rightButtonPressed( TQListBoxItem *,
const TQPoint &) ),
TQT_SLOT( contextMenu( TQListBoxItem * ) ) );
connect( mItemList, TQT_SIGNAL( clicked( TQListBoxItem * ) ),
TQT_SLOT( select() ) );
}
void MonthViewCell::setDate( const TQDate &date )
{
// kdDebug(5850) << "MonthViewCell::setDate(): " << date.toString() << endl;
mDate = date;
setFrameWidth();
TQString 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) );
TQFontMetrics fm( mLabel->font() );
mLabel->resize( mLabelSize + TQSize( fm.width( text ), 0 ) );
} else {
mLabel->resize( mLabelSize );
text = TQString::number( KOGlobals::self()->calendarSystem()->day(mDate) );
}
mLabel->setText( text );
new KOMonthCellToolTip( mItemList->viewport(),
monthView()->calendar(),
mDate,
static_cast<KNoScrollListBox *>( mItemList ) );
resizeEvent( 0 );
}
TQDate MonthViewCell::date() const
{
return mDate;
}
void MonthViewCell::setFrameWidth()
{
// show current day with a thicker frame
if ( mDate == TQDate::currentDate() ) {
mItemList->setLineWidth( 3 );
} else if ( !isSelected ) {
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 TQString &holiday )
{
mHolidayString = holiday;
}
void MonthViewCell::updateCell()
{
setFrameWidth();
if ( mDate == TQDate::currentDate() ) {
setPalette( mTodayPalette );
TQPalette pal = mItemList->palette();
pal.setColor( TQColorGroup::Foreground, KOPrefs::instance()->highlightColor() );
mItemList->setPalette( pal );
}
else {
if ( mHoliday )
setPalette( mHolidayPalette );
else
setPalette( mStandardPalette );
TQPalette pal = mItemList->palette();
pal.setColor( TQColorGroup::Foreground, KOPrefs::instance()->agendaBgColor().dark( 150 ) );
mItemList->setPalette( pal );
}
mItemList->clear();
if ( !mHolidayString.isEmpty() ) {
MonthViewItem *item = new MonthViewItem( 0, TQDateTime( 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, TQDate date, TQPalette stdPal, int multiDay )
{
mItem = 0;
mDate = date;
mStandardPalette = stdPal;
mMultiDay = multiDay;
return incidence->accept( *this );
}
MonthViewItem *item() const { return mItem; }
TQStringList emails;
protected:
bool visit( Event *event ) {
TQString text;
TQDateTime dt( mDate );
// take the time 0:00 into account, which is non-inclusive
TQDate dtEnd = event->dtEnd().addSecs( event->doesFloat() ? 0 : -1).date();
int length = event->dtStart().daysTo( TQDateTime(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 = TQDateTime( 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()->monthItemColors() == KOPrefs::MonthItemCategoryOnly ||
KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryInsideResourceOutside ) {
TQStringList categories = event->categories();
TQString cat = categories.first();
if (cat.isEmpty()) {
mItem->setPalette(TQPalette(KOPrefs::instance()->unsetCategoryColor(),
KOPrefs::instance()->unsetCategoryColor()) );
} else {
mItem->setPalette(TQPalette(*(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 ) {
TQString text;
if ( !KOPrefs::instance()->showAllDayTodo() )
return false;
TQDateTime dt( mDate );
if ( todo->hasDueDate() && !todo->doesFloat() &&
todo->dtDue().time() != TQTime( 0,0 ) && todo->dtDue().time().isValid() ) {
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;
TQDate mDate;
TQPalette 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() );
TQColor resourceColor = KOHelper::resourceColor( monthView()->calendar(), incidence );
if ( !resourceColor.isValid() )
resourceColor = KOPrefs::instance()->unsetCategoryColor();
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;
TQDateTime dt( item->incidenceDateTime() );
while ( i < mItemList->count() && pos<0 ) {
TQListBoxItem *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 );
TQFontMetrics fm( font() );
mLabelSize = fm.size( 0, "30" ) +
TQSize( mLabel->frameWidth() * 2, mLabel->frameWidth() * 2 ) +
TQSize( 2, 2 );
// mStandardPalette = mOriginalPalette;
TQColor bg = mStandardPalette.color( TQPalette::Active, TQColorGroup::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( TQColorGroup::Background, bg);*/
mHolidayPalette = mStandardPalette;
mHolidayPalette.setColor( TQColorGroup::Foreground,
KOPrefs::instance()->holidayColor() );
mHolidayPalette.setColor( TQColorGroup::Text,
KOPrefs::instance()->holidayColor() );
mTodayPalette = mStandardPalette;
mTodayPalette.setColor( TQColorGroup::Foreground,
KOPrefs::instance()->highlightColor() );
mTodayPalette.setColor( TQColorGroup::Text,
KOPrefs::instance()->highlightColor() );
updateCell();
mItemList->setBackground( mPrimary, KOGlobals::self()->isWorkDay( mDate ) );
}
void MonthViewCell::enableScrollBars( bool enabled )
{
if ( enabled ) {
mItemList->setVScrollBarMode( TQScrollView::Auto );
mItemList->setHScrollBarMode( TQScrollView::Auto );
} else {
mItemList->setVScrollBarMode( TQScrollView::AlwaysOff );
mItemList->setHScrollBarMode( TQScrollView::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();
}
TQDate MonthViewCell::selectedIncidenceDate()
{
TQDate 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()
{
isSelected = true;
// 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 != TQDate::currentDate() ) {
mItemList->setFrameStyle( TQFrame::Sunken | TQFrame::Panel );
mItemList->setLineWidth( 3 );
}
}
void MonthViewCell::deselect()
{
isSelected = false;
mItemList->clearSelection();
mItemList->setFrameStyle( TQFrame::Plain | TQFrame::Panel );
setFrameWidth();
enableScrollBars( false );
}
void MonthViewCell::resizeEvent ( TQResizeEvent * )
{
mLabel->move( width() - mLabel->width(), height() - mLabel->height() );
}
void MonthViewCell::defaultAction( TQListBoxItem *item )
{
select();
if ( !item ) {
emit newEventSignal( 0/*ResourceCalendar*/, TQString()/*subResource*/, date() );
} else {
MonthViewItem *eventItem = static_cast<MonthViewItem *>( item );
Incidence *incidence = eventItem->incidence();
if ( incidence ) mMonthView->defaultAction( incidence );
}
}
void MonthViewCell::contextMenu( TQListBoxItem *item )
{
select();
if ( item ) {
MonthViewItem *eventItem = static_cast<MonthViewItem *>( item );
Incidence *incidence = eventItem->incidence();
if ( incidence ) {
mMonthView->showEventContextMenu( monthView()->calendar(), incidence, mDate );
}
} else {
mMonthView->showGeneralContextMenu();
}
}
KOMonthView::KOMonthView( Calendar *calendar, TQWidget *parent, const char *name )
: KOEventView( calendar, parent, name ),
mDaysPerWeek( 7 ), mNumWeeks( 6 ), mNumCells( mDaysPerWeek * mNumWeeks ),
mShortDayLabels( false ), mWidthLongDayLabel( 0 ), mSelectedCell( 0 )
{
mCells.setAutoDelete( true );
TQGridLayout *dayLayout = new TQGridLayout( this );
TQFont bfont = font();
bfont.setBold( true );
TQFont mfont = bfont;
mfont.setPointSize( 20 );
// month name on top
mLabel = new TQLabel( this );
mLabel->setFont( mfont );
mLabel->setAlignment( AlignCenter );
mLabel->setLineWidth( 0 );
mLabel->setFrameStyle( TQFrame::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++ ) {
TQLabel *label = new TQLabel( this );
label->setFont( bfont );
label->setFrameStyle( TQFrame::Panel | TQFrame::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 );
mCells.insert( row * mDaysPerWeek + col, cell );
dayLayout->addWidget( cell, row + 2, col );
connect( cell, TQT_SIGNAL(defaultAction(Incidence *)),
TQT_SLOT(defaultAction(Incidence *)) );
connect( cell, TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &,const TQDate &)),
TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &,const TQDate &)) );
}
dayLayout->setRowStretch( row + 2, 1 );
}
mEventContextMenu = eventPopup();
updateConfig();
emit incidenceSelected( 0, TQDate() );
}
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::selectedIncidenceDates()
{
DateList selected;
if ( mSelectedCell ) {
TQDate qd = mSelectedCell->selectedIncidenceDate();
if ( qd.isValid() ) selected.append( qd );
}
return selected;
}
bool KOMonthView::eventDurationHint( TQDateTime &startDt, TQDateTime &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();
TQFontMetrics 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();
}
showLabel( !KOPrefs::instance()->fullViewMonth() );
}
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 TQDate &start, const TQDate & )
{
// 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 ) ) );
showLabel( !KOPrefs::instance()->fullViewMonth() );
bool primary = false;
uint i;
for( i = 0; i < mCells.size(); ++i ) {
TQDate 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
TQStringList holidays( KOGlobals::self()->holiday( date ) );
mCells[i]->setHolidayString( holidays.join( i18n("delimiter for joining holiday names", ", " ) ) );
}
updateView();
}
TQDateTime KOMonthView::selectionStart()
{
if ( mSelectedCell) {
return TQDateTime( mSelectedCell->date() );
} else {
return TQDateTime();
}
}
TQDateTime KOMonthView::selectionEnd()
{
// Only one cell can be selected (for now)
return selectionStart();
}
void KOMonthView::showIncidences( const Incidence::List &, const TQDate & )
{
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 );
}
TQDateTime startDate() const { return mStartDate; }
TQDateTime endDate() const { return mEndDate; }
protected:
bool visit( Event *event ) {
mStartDate = event->dtStart();
mEndDate = event->dtEnd();
return true;
}
bool visit( Todo *todo ) {
if ( todo->hasDueDate() ) {
if ( todo->dtDue().time() != TQTime( 0, 0 ) &&
todo->dtDue().time().isValid() ) {
mStartDate = todo->dtDue();
mEndDate = todo->dtDue();
} else {
mStartDate = TQDateTime( todo->dtDue().date(), TQTime( 23,59 ) );
mEndDate = mStartDate;
}
}// else
// return false;
return true;
}
bool visit( Journal *journal ) {
mStartDate = journal->dtStart();
mEndDate = journal->dtStart();
return true;
}
protected:
TQDateTime mStartDate;
TQDateTime 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(), calendar() ) ) {
// handle multiday events
int length = gdv.startDate().daysTo( TQDateTime(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() ) {
TQDate endDate = gdv.endDate().addSecs( floats ? 0 : -1).date();
for ( TQDate 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( TQResizeEvent * )
{
// 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( Calendar *cal, Incidence *incidence, const TQDate &qd )
{
mEventContextMenu->showIncidencePopup( cal, incidence, qd );
}
void KOMonthView::showGeneralContextMenu()
{
showNewEventPopup();
}
void KOMonthView::setSelectedCell( MonthViewCell *cell )
{
if ( mSelectedCell && cell != mSelectedCell )
mSelectedCell->deselect();
mSelectedCell = cell;
if ( !mSelectedCell )
emit incidenceSelected( 0, TQDate() );
else
if ( selectedIncidenceDates().isEmpty() ) {
emit incidenceSelected( mSelectedCell->selectedIncidence(), TQDate() );
} else {
emit incidenceSelected( mSelectedCell->selectedIncidence(), selectedIncidenceDates().first() );
}
}
void KOMonthView::processSelectionChange()
{
Incidence::List incidences = selectedIncidences();
if (incidences.count() > 0) {
if ( selectedIncidenceDates().isEmpty() ) {
emit incidenceSelected( incidences.first(), TQDate() );
} else {
emit incidenceSelected( incidences.first(), selectedIncidenceDates().first() );
}
} else {
emit incidenceSelected( 0, TQDate() );
}
}
void KOMonthView::clearSelection()
{
if ( mSelectedCell ) {
mSelectedCell->deselect();
mSelectedCell = 0;
}
}
void KOMonthView::showLabel( bool show )
{
if ( show ) {
mLabel->show();
} else {
mLabel->hide();
}
}