komonthview.cpp
00001 /* 00002 This file is part of KOrganizer. 00003 00004 Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> 00005 Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com> 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 2 of the License, or 00010 (at your option) any later version. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program; if not, write to the Free Software 00019 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00020 00021 As a special exception, permission is given to link this program 00022 with any edition of TQt, and distribute the resulting executable, 00023 without including the source code for TQt in the source distribution. 00024 */ 00025 00026 #include <tqpopupmenu.h> 00027 #include <tqfont.h> 00028 #include <tqfontmetrics.h> 00029 #include <tqkeycode.h> 00030 #include <tqhbox.h> 00031 #include <tqvbox.h> 00032 #include <tqpushbutton.h> 00033 #include <tqtooltip.h> 00034 #include <tqpainter.h> 00035 #include <tqcursor.h> 00036 #include <tqlistbox.h> 00037 #include <tqlayout.h> 00038 #include <tqlabel.h> 00039 00040 #include <kdebug.h> 00041 #include <tdelocale.h> 00042 #include <tdeglobal.h> 00043 #include <tdeconfig.h> 00044 #include <kiconloader.h> 00045 #include <kwordwrap.h> 00046 00047 #include <kcalendarsystem.h> 00048 #include <libkcal/calfilter.h> 00049 #include <libkcal/calendar.h> 00050 #include <libkcal/incidenceformatter.h> 00051 #include <libkcal/calendarresources.h> 00052 00053 #include "koprefs.h" 00054 #include "koglobals.h" 00055 #include "koincidencetooltip.h" 00056 #include "koeventpopupmenu.h" 00057 #include "kohelper.h" 00058 00059 #include "komonthview.h" 00060 #include "komonthview.moc" 00061 00062 //-------------------------------------------------------------------------- 00063 00064 KOMonthCellToolTip::KOMonthCellToolTip( TQWidget *parent, 00065 Calendar *calendar, 00066 const TQDate &date, 00067 KNoScrollListBox *lv ) 00068 : TQToolTip( parent ), mCalendar( calendar ), mDate( date ) 00069 { 00070 eventlist = lv; 00071 } 00072 00073 void KOMonthCellToolTip::maybeTip( const TQPoint &pos ) 00074 { 00075 TQRect r; 00076 TQListBoxItem *it = eventlist->itemAt( pos ); 00077 MonthViewItem *i = static_cast<MonthViewItem*>( it ); 00078 00079 if( i && KOPrefs::instance()->mEnableToolTips ) { 00080 /* Calculate the rectangle. */ 00081 r=eventlist->itemRect( it ); 00082 /* Show the tip */ 00083 TQString tipText( IncidenceFormatter::toolTipStr( mCalendar, i->incidence(), mDate ) ); 00084 if ( !tipText.isEmpty() ) { 00085 tip( r, tipText ); 00086 } 00087 } 00088 } 00089 00090 KNoScrollListBox::KNoScrollListBox( TQWidget *parent, const char *name ) 00091 : TQListBox( parent, name ), 00092 mSqueezing( false ) 00093 { 00094 TQPalette pal = palette(); 00095 pal.setColor( TQColorGroup::Foreground, KOPrefs::instance()->agendaBgColor().dark( 150 ) ); 00096 pal.setColor( TQColorGroup::Base, KOPrefs::instance()->agendaBgColor() ); 00097 setPalette( pal ); 00098 } 00099 00100 void KNoScrollListBox::setBackground( bool primary, bool workDay ) 00101 { 00102 TQColor color; 00103 if ( workDay ) { 00104 color = KOPrefs::instance()->workingHoursColor(); 00105 } else { 00106 color = KOPrefs::instance()->agendaBgColor(); 00107 } 00108 00109 TQPalette pal = palette(); 00110 if ( primary ) { 00111 pal.setColor( TQColorGroup::Base, color ); 00112 } else { 00113 pal.setColor( TQColorGroup::Base, color.dark( 115 ) ); 00114 } 00115 setPalette( pal ); 00116 } 00117 00118 void KNoScrollListBox::keyPressEvent( TQKeyEvent *e ) 00119 { 00120 switch( e->key() ) { 00121 case Key_Right: 00122 scrollBy( 4, 0 ); 00123 break; 00124 case Key_Left: 00125 scrollBy( -4, 0 ); 00126 break; 00127 case Key_Up: 00128 if ( !count() ) break; 00129 setCurrentItem( ( currentItem() + count() - 1 ) % count() ); 00130 if ( !itemVisible( currentItem() ) ) { 00131 if ( (unsigned int)currentItem() == ( count() - 1 ) ) { 00132 setTopItem( currentItem() - numItemsVisible() + 1 ); 00133 } else { 00134 setTopItem( topItem() - 1 ); 00135 } 00136 } 00137 break; 00138 case Key_Down: 00139 if ( !count() ) break; 00140 setCurrentItem( ( currentItem() + 1 ) % count() ); 00141 if( !itemVisible( currentItem() ) ) { 00142 if( currentItem() == 0 ) { 00143 setTopItem( 0 ); 00144 } else { 00145 setTopItem( topItem() + 1 ); 00146 } 00147 } 00148 case Key_Shift: 00149 emit shiftDown(); 00150 break; 00151 default: 00152 break; 00153 } 00154 } 00155 00156 void KNoScrollListBox::keyReleaseEvent( TQKeyEvent *e ) 00157 { 00158 switch( e->key() ) { 00159 case Key_Shift: 00160 emit shiftUp(); 00161 break; 00162 default: 00163 break; 00164 } 00165 } 00166 00167 void KNoScrollListBox::mousePressEvent( TQMouseEvent *e ) 00168 { 00169 TQListBox::mousePressEvent( e ); 00170 00171 if ( e->button() == Qt::RightButton ) { 00172 emit rightClick(); 00173 } 00174 } 00175 00176 void KNoScrollListBox::contentsMouseDoubleClickEvent ( TQMouseEvent * e ) 00177 { 00178 TQListBox::contentsMouseDoubleClickEvent( e ); 00179 TQListBoxItem *item = itemAt( e->pos() ); 00180 if ( !item ) { 00181 emit doubleClicked( item ); 00182 } 00183 } 00184 00185 void KNoScrollListBox::resizeEvent( TQResizeEvent *e ) 00186 { 00187 bool s = count() && ( maxItemWidth() > e->size().width() ); 00188 if ( mSqueezing || s ) 00189 triggerUpdate( false ); 00190 00191 mSqueezing = s; 00192 TQListBox::resizeEvent( e ); 00193 } 00194 00195 MonthViewItem::MonthViewItem( Incidence *incidence, const TQDateTime &qd, 00196 const TQString & s ) : TQListBoxItem() 00197 { 00198 setText( s ); 00199 00200 mIncidence = incidence; 00201 mDateTime = qd; 00202 00203 mEventPixmap = KOGlobals::self()->smallIcon( "appointment" ); 00204 mBirthdayPixmap = KOGlobals::self()->smallIcon( "calendarbirthday" ); 00205 mAnniversaryPixmap= KOGlobals::self()->smallIcon( "calendaranniversary" ); 00206 mTodoPixmap = KOGlobals::self()->smallIcon( "todo" ); 00207 mTodoDonePixmap = KOGlobals::self()->smallIcon( "checkedbox" ); 00208 mAlarmPixmap = KOGlobals::self()->smallIcon( "bell" ); 00209 mRecurPixmap = KOGlobals::self()->smallIcon( "recur" ); 00210 mReplyPixmap = KOGlobals::self()->smallIcon( "mail-reply-sender" ); 00211 00212 mEvent = false; 00213 mTodo = false; 00214 mTodoDone = false; 00215 mRecur = false; 00216 mAlarm = false; 00217 mReply = false; 00218 } 00219 00220 TQColor MonthViewItem::catColor() const 00221 { 00222 TQColor retColor; 00223 if ( !mIncidence ) { 00224 return retColor; 00225 } 00226 00227 TQStringList categories = mIncidence->categories(); 00228 TQString cat; 00229 if ( !categories.isEmpty() ) { 00230 cat = categories.first(); 00231 } 00232 if ( cat.isEmpty() ) { 00233 retColor = KOPrefs::instance()->unsetCategoryColor(); 00234 } else { 00235 retColor = *( KOPrefs::instance()->categoryColor( cat ) ); 00236 } 00237 return retColor; 00238 } 00239 00240 void MonthViewItem::paint( TQPainter *p ) 00241 { 00242 bool sel = isSelected(); 00243 00244 TQColor bgColor = TQColor(); // Default invalid color; 00245 if ( mIncidence && mTodo ) { 00246 if ( static_cast<Todo*>( mIncidence )->isOverdue() ) { 00247 bgColor = KOPrefs::instance()->todoOverdueColor(); 00248 } else if ( static_cast<Todo*>( mIncidence )->dtDue().date() == TQDate::currentDate() ) { 00249 bgColor = KOPrefs::instance()->todoDueTodayColor(); 00250 } 00251 } 00252 00253 if ( !bgColor.isValid() ) { 00254 if ( KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceOnly || 00255 KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceInsideCategoryOutside ) { 00256 bgColor = resourceColor(); 00257 } else { 00258 bgColor = catColor(); 00259 } 00260 00261 if ( !bgColor.isValid() ) { 00262 bgColor = palette().color( TQPalette::Normal, 00263 sel ? TQColorGroup::Highlight : 00264 TQColorGroup::Background ); 00265 } 00266 } 00267 00268 TQColor frameColor; 00269 if ( KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceOnly || 00270 KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryInsideResourceOutside ) { 00271 frameColor = resourceColor(); 00272 } else { 00273 frameColor = catColor(); 00274 } 00275 00276 if ( mIncidence ) { 00277 if ( mIncidence->categories().isEmpty() && 00278 KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceInsideCategoryOutside ) { 00279 frameColor = bgColor; 00280 } 00281 00282 if ( mIncidence->categories().isEmpty() && 00283 KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryInsideResourceOutside ) { 00284 bgColor = frameColor; 00285 } 00286 } 00287 00288 if ( !frameColor.isValid() ) { 00289 frameColor = palette().color( TQPalette::Normal, 00290 sel ? TQColorGroup::Highlight : 00291 TQColorGroup::Foreground ); 00292 } else { 00293 frameColor = frameColor.dark( 115 ); 00294 } 00295 00296 // draw the box for the item 00297 p->setBackgroundColor( frameColor ); 00298 p->eraseRect( 0, 0, listBox()->maxItemWidth(), height( listBox() ) ); 00299 int offset = 2; 00300 p->setBackgroundColor( bgColor ); 00301 p->eraseRect( offset, offset, listBox()->maxItemWidth()-2*offset, height( listBox() )-2*offset ); 00302 00303 int x = 3; 00304 00305 bool specialEvent = false; 00306 if ( mEvent ) { 00307 if ( mIncidence->customProperty( "KABC", "BIRTHDAY" ) == "YES" ) { 00308 specialEvent = true; 00309 if ( mIncidence->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) { 00310 p->drawPixmap( x, 0, mAnniversaryPixmap ); 00311 x += mAnniversaryPixmap.width() + 2; 00312 } else { 00313 p->drawPixmap( x, 0, mBirthdayPixmap ); 00314 x += mBirthdayPixmap.width() + 2; 00315 } 00316 // Do NOT put on the event pixmap because it takes up too much space 00317 //} else { 00318 // p->drawPixmap( x, 0, mEventPixmap ); 00319 // x += mEventPixmap.width() + 2; 00320 // 00321 } 00322 } 00323 00324 if ( mTodo ) { 00325 p->drawPixmap( x, 0, mTodoPixmap ); 00326 x += mTodoPixmap.width() + 2; 00327 } 00328 if ( mTodoDone ) { 00329 p->drawPixmap( x, 0, mTodoDonePixmap ); 00330 x += mTodoPixmap.width() + 2; 00331 } 00332 if ( mRecur && !specialEvent ) { 00333 p->drawPixmap( x, 0, mRecurPixmap ); 00334 x += mRecurPixmap.width() + 2; 00335 } 00336 if ( mAlarm && !specialEvent ) { 00337 p->drawPixmap( x, 0, mAlarmPixmap ); 00338 x += mAlarmPixmap.width() + 2; 00339 } 00340 if ( mReply ) { 00341 p->drawPixmap(x, 0, mReplyPixmap ); 00342 x += mReplyPixmap.width() + 2; 00343 } 00344 TQFontMetrics fm = p->fontMetrics(); 00345 int yPos; 00346 int pmheight = TQMAX( mRecurPixmap.height(), 00347 TQMAX( mAlarmPixmap.height(), mReplyPixmap.height() ) ); 00348 if( pmheight < fm.height() ) 00349 yPos = fm.ascent() + fm.leading()/2; 00350 else 00351 yPos = pmheight/2 - fm.height()/2 + fm.ascent(); 00352 TQColor textColor = getTextColor( bgColor ); 00353 p->setPen( textColor ); 00354 00355 KWordWrap::drawFadeoutText( p, x, yPos, listBox()->width() - x, text() ); 00356 } 00357 00358 int MonthViewItem::height( const TQListBox *lb ) const 00359 { 00360 return TQMAX( TQMAX( mRecurPixmap.height(), mReplyPixmap.height() ), 00361 TQMAX( mAlarmPixmap.height(), lb->fontMetrics().lineSpacing()+1) ); 00362 } 00363 00364 int MonthViewItem::width( const TQListBox *lb ) const 00365 { 00366 int x = 3; 00367 if( mRecur ) { 00368 x += mRecurPixmap.width()+2; 00369 } 00370 if( mAlarm ) { 00371 x += mAlarmPixmap.width()+2; 00372 } 00373 if( mReply ) { 00374 x += mReplyPixmap.width()+2; 00375 } 00376 00377 return( x + lb->fontMetrics().boundingRect( text() ).width() + 1 ); 00378 } 00379 00380 00381 MonthViewCell::MonthViewCell( KOMonthView *parent) 00382 : TQWidget( parent ), 00383 mMonthView( parent ), mPrimary( false ), mHoliday( false ), 00384 isSelected( false ) 00385 { 00386 TQVBoxLayout *topLayout = new TQVBoxLayout( this ); 00387 00388 mLabel = new TQLabel( this ); 00389 mLabel->setFrameStyle( TQFrame::Panel | TQFrame::Plain ); 00390 mLabel->setLineWidth( 1 ); 00391 mLabel->setAlignment( AlignCenter ); 00392 00393 mItemList = new KNoScrollListBox( this ); 00394 mItemList->setMinimumSize( 10, 10 ); 00395 mItemList->setFrameStyle( TQFrame::Panel | TQFrame::Plain ); 00396 mItemList->setLineWidth( 1 ); 00397 00398 topLayout->addWidget( mItemList ); 00399 00400 mLabel->raise(); 00401 00402 mStandardPalette = palette(); 00403 00404 enableScrollBars( false ); 00405 00406 updateConfig(); 00407 00408 connect( mItemList, TQT_SIGNAL( doubleClicked( TQListBoxItem *) ), 00409 TQT_SLOT( defaultAction( TQListBoxItem * ) ) ); 00410 connect( mItemList, TQT_SIGNAL( rightButtonPressed( TQListBoxItem *, 00411 const TQPoint &) ), 00412 TQT_SLOT( contextMenu( TQListBoxItem * ) ) ); 00413 connect( mItemList, TQT_SIGNAL( clicked( TQListBoxItem * ) ), 00414 TQT_SLOT( select() ) ); 00415 } 00416 00417 void MonthViewCell::setDate( const TQDate &date ) 00418 { 00419 // kdDebug(5850) << "MonthViewCell::setDate(): " << date.toString() << endl; 00420 00421 mDate = date; 00422 00423 setFrameWidth(); 00424 00425 TQString text; 00426 if ( KOGlobals::self()->calendarSystem()->day( date ) == 1 ) { 00427 text = i18n("'Month day' for month view cells", "%1 %2") 00428 .arg( KOGlobals::self()->calendarSystem()->monthName( date, true ) ) 00429 .arg( KOGlobals::self()->calendarSystem()->day(mDate) ); 00430 TQFontMetrics fm( mLabel->font() ); 00431 mLabel->resize( mLabelSize + TQSize( fm.width( text ), 0 ) ); 00432 } else { 00433 mLabel->resize( mLabelSize ); 00434 text = TQString::number( KOGlobals::self()->calendarSystem()->day(mDate) ); 00435 } 00436 mLabel->setText( text ); 00437 00438 new KOMonthCellToolTip( mItemList->viewport(), 00439 monthView()->calendar(), 00440 mDate, 00441 static_cast<KNoScrollListBox *>( mItemList ) ); 00442 00443 resizeEvent( 0 ); 00444 } 00445 00446 TQDate MonthViewCell::date() const 00447 { 00448 return mDate; 00449 } 00450 00451 void MonthViewCell::setFrameWidth() 00452 { 00453 // show current day with a thicker frame 00454 if ( mDate == TQDate::currentDate() ) { 00455 mItemList->setLineWidth( 3 ); 00456 } else if ( !isSelected ) { 00457 mItemList->setLineWidth( 1 ); 00458 } 00459 } 00460 00461 void MonthViewCell::setPrimary( bool primary ) 00462 { 00463 mPrimary = primary; 00464 00465 if ( mPrimary ) { 00466 mLabel->setBackgroundMode( PaletteBase ); 00467 } else { 00468 mLabel->setBackgroundMode( PaletteBackground ); 00469 } 00470 00471 mItemList->setBackground( mPrimary, KOGlobals::self()->isWorkDay( mDate ) ); 00472 } 00473 00474 bool MonthViewCell::isPrimary() const 00475 { 00476 return mPrimary; 00477 } 00478 00479 void MonthViewCell::setHoliday( bool holiday ) 00480 { 00481 mHoliday = holiday; 00482 00483 if ( holiday ) { 00484 setPalette( mHolidayPalette ); 00485 } else { 00486 setPalette( mStandardPalette ); 00487 } 00488 } 00489 00490 void MonthViewCell::setHolidayString( const TQString &holiday ) 00491 { 00492 mHolidayString = holiday; 00493 } 00494 00495 void MonthViewCell::updateCell() 00496 { 00497 setFrameWidth(); 00498 00499 if ( mDate == TQDate::currentDate() ) { 00500 setPalette( mTodayPalette ); 00501 00502 TQPalette pal = mItemList->palette(); 00503 pal.setColor( TQColorGroup::Foreground, KOPrefs::instance()->highlightColor() ); 00504 mItemList->setPalette( pal ); 00505 } 00506 else { 00507 if ( mHoliday ) 00508 setPalette( mHolidayPalette ); 00509 else 00510 setPalette( mStandardPalette ); 00511 00512 TQPalette pal = mItemList->palette(); 00513 pal.setColor( TQColorGroup::Foreground, KOPrefs::instance()->agendaBgColor().dark( 150 ) ); 00514 mItemList->setPalette( pal ); 00515 } 00516 00517 mItemList->clear(); 00518 00519 if ( !mHolidayString.isEmpty() ) { 00520 MonthViewItem *item = new MonthViewItem( 0, TQDateTime( mDate ), mHolidayString ); 00521 item->setPalette( mHolidayPalette ); 00522 mItemList->insertItem( item ); 00523 } 00524 } 00525 00526 class MonthViewCell::CreateItemVisitor : 00527 public IncidenceBase::Visitor 00528 { 00529 public: 00530 CreateItemVisitor() : mItem(0) { emails = KOPrefs::instance()->allEmails(); } 00531 00532 bool act( IncidenceBase *incidence, TQDate date, TQPalette stdPal, int multiDay ) 00533 { 00534 mItem = 0; 00535 mDate = date; 00536 mStandardPalette = stdPal; 00537 mMultiDay = multiDay; 00538 return incidence->accept( *this ); 00539 } 00540 MonthViewItem *item() const { return mItem; } 00541 TQStringList emails; 00542 00543 protected: 00544 bool visit( Event *event ) { 00545 TQString text; 00546 TQDateTime dt( mDate ); 00547 // take the time 0:00 into account, which is non-inclusive 00548 TQDate dtEnd = event->dtEnd().addSecs( event->doesFloat() ? 0 : -1).date(); 00549 int length = event->dtStart().daysTo( TQDateTime(dtEnd) ); 00550 if ( event->isMultiDay() ) { 00551 if ( mDate == event->dtStart().date() 00552 || ( mMultiDay == 0 && event->recursOn( mDate ) ) ) { 00553 text = "(-- " + event->summary(); 00554 dt = event->dtStart(); 00555 } else if ( !event->doesRecur() && mDate == dtEnd 00556 // last day of a recurring multi-day event? 00557 || ( mMultiDay == length && event->recursOn( mDate.addDays( -length ) ) ) ) { 00558 text = event->summary() + " --)"; 00559 } else if (!(event->dtStart().date().daysTo(mDate) % 7) && length > 7 ) { 00560 text = "-- " + event->summary() + " --"; 00561 } else { 00562 text = "----------------"; 00563 dt = TQDateTime( mDate ); 00564 } 00565 } else { 00566 if (event->doesFloat()) 00567 text = event->summary(); 00568 else { 00569 text = TDEGlobal::locale()->formatTime(event->dtStart().time()); 00570 dt.setTime( event->dtStart().time() ); 00571 text += ' ' + event->summary(); 00572 } 00573 } 00574 00575 mItem = new MonthViewItem( event, dt, text ); 00576 mItem->setEvent( true ); 00577 if ( KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryOnly || 00578 KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryInsideResourceOutside ) { 00579 TQStringList categories = event->categories(); 00580 TQString cat = categories.first(); 00581 if (cat.isEmpty()) { 00582 mItem->setPalette(TQPalette(KOPrefs::instance()->unsetCategoryColor(), 00583 KOPrefs::instance()->unsetCategoryColor()) ); 00584 } else { 00585 mItem->setPalette(TQPalette(*(KOPrefs::instance()->categoryColor(cat)), 00586 *(KOPrefs::instance()->categoryColor(cat)))); 00587 } 00588 } else { 00589 mItem->setPalette( mStandardPalette ); 00590 } 00591 00592 Attendee *me = event->attendeeByMails( emails ); 00593 if ( me != 0 ) { 00594 mItem->setReply( me->status() == Attendee::NeedsAction && me->RSVP() ); 00595 } else 00596 mItem->setReply(false); 00597 return true; 00598 } 00599 bool visit( Todo *todo ) { 00600 TQString text; 00601 if ( !KOPrefs::instance()->showAllDayTodo() ) 00602 return false; 00603 TQDateTime dt( mDate ); 00604 if ( todo->hasDueDate() && !todo->doesFloat() && 00605 todo->dtDue().time() != TQTime( 0,0 ) && todo->dtDue().time().isValid() ) { 00606 text += TDEGlobal::locale()->formatTime( todo->dtDue().time() ); 00607 text += ' '; 00608 dt.setTime( todo->dtDue().time() ); 00609 } 00610 text += todo->summary(); 00611 00612 mItem = new MonthViewItem( todo, dt, text ); 00613 if ( todo->doesRecur() ) { 00614 mDate < todo->dtDue().date() ? 00615 mItem->setTodoDone( true ) : mItem->setTodo( true ); 00616 } 00617 else 00618 todo->isCompleted() ? mItem->setTodoDone( true ) : mItem->setTodo( true ); 00619 mItem->setPalette( mStandardPalette ); 00620 return true; 00621 } 00622 protected: 00623 MonthViewItem *mItem; 00624 TQDate mDate; 00625 TQPalette mStandardPalette; 00626 int mMultiDay; 00627 }; 00628 00629 00630 void MonthViewCell::addIncidence( Incidence *incidence, CreateItemVisitor& v, int multiDay ) 00631 { 00632 if ( v.act( incidence, mDate, mStandardPalette, multiDay ) ) { 00633 MonthViewItem *item = v.item(); 00634 if ( item ) { 00635 item->setAlarm( incidence->isAlarmEnabled() ); 00636 item->setRecur( incidence->recurrenceType() ); 00637 00638 TQColor resourceColor = KOHelper::resourceColor( monthView()->calendar(), incidence ); 00639 if ( !resourceColor.isValid() ) 00640 resourceColor = KOPrefs::instance()->unsetCategoryColor(); 00641 item->setResourceColor( resourceColor ); 00642 00643 // FIXME: Find the correct position (time-wise) to insert the item. 00644 // Currently, the items are displayed in "random" order instead of 00645 // chronologically sorted. 00646 uint i = 0; 00647 int pos = -1; 00648 TQDateTime dt( item->incidenceDateTime() ); 00649 00650 while ( i < mItemList->count() && pos<0 ) { 00651 TQListBoxItem *item = mItemList->item( i ); 00652 MonthViewItem *mvitem = dynamic_cast<MonthViewItem*>( item ); 00653 if ( mvitem && mvitem->incidenceDateTime()>dt ) { 00654 pos = i; 00655 } 00656 ++i; 00657 } 00658 mItemList->insertItem( item, pos ); 00659 } 00660 } 00661 } 00662 00663 void MonthViewCell::removeIncidence( Incidence *incidence ) 00664 { 00665 for ( uint i = 0; i < mItemList->count(); ++i ) { 00666 MonthViewItem *item = static_cast<MonthViewItem *>(mItemList->item( i ) ); 00667 if ( item && item->incidence() && 00668 item->incidence()->uid() == incidence->uid() ) { 00669 mItemList->removeItem( i ); 00670 --i; 00671 } 00672 } 00673 } 00674 00675 void MonthViewCell::updateConfig() 00676 { 00677 setFont( KOPrefs::instance()->mMonthViewFont ); 00678 00679 TQFontMetrics fm( font() ); 00680 mLabelSize = fm.size( 0, "30" ) + 00681 TQSize( mLabel->frameWidth() * 2, mLabel->frameWidth() * 2 ) + 00682 TQSize( 2, 2 ); 00683 // mStandardPalette = mOriginalPalette; 00684 TQColor bg = mStandardPalette.color( TQPalette::Active, TQColorGroup::Background ); 00685 int h,s,v; 00686 bg.getHsv( &h, &s, &v ); 00687 if ( date().month() %2 == 0 ) { 00688 if ( v < 128 ) { 00689 bg = bg.light( 125 ); 00690 } else { 00691 bg = bg.dark( 125 ); 00692 } 00693 } 00694 setPaletteBackgroundColor( bg ); 00695 // mStandardPalette.setColor( TQColorGroup::Background, bg);*/ 00696 00697 mHolidayPalette = mStandardPalette; 00698 mHolidayPalette.setColor( TQColorGroup::Foreground, 00699 KOPrefs::instance()->holidayColor() ); 00700 mHolidayPalette.setColor( TQColorGroup::Text, 00701 KOPrefs::instance()->holidayColor() ); 00702 mTodayPalette = mStandardPalette; 00703 mTodayPalette.setColor( TQColorGroup::Foreground, 00704 KOPrefs::instance()->highlightColor() ); 00705 mTodayPalette.setColor( TQColorGroup::Text, 00706 KOPrefs::instance()->highlightColor() ); 00707 updateCell(); 00708 00709 mItemList->setBackground( mPrimary, KOGlobals::self()->isWorkDay( mDate ) ); 00710 } 00711 00712 void MonthViewCell::enableScrollBars( bool enabled ) 00713 { 00714 if ( enabled ) { 00715 mItemList->setVScrollBarMode( TQScrollView::Auto ); 00716 mItemList->setHScrollBarMode( TQScrollView::Auto ); 00717 } else { 00718 mItemList->setVScrollBarMode( TQScrollView::AlwaysOff ); 00719 mItemList->setHScrollBarMode( TQScrollView::AlwaysOff ); 00720 } 00721 } 00722 00723 Incidence *MonthViewCell::selectedIncidence() 00724 { 00725 int index = mItemList->currentItem(); 00726 if ( index < 0 ) return 0; 00727 00728 MonthViewItem *item = 00729 static_cast<MonthViewItem *>( mItemList->item( index ) ); 00730 00731 if ( !item ) return 0; 00732 00733 return item->incidence(); 00734 } 00735 00736 TQDate MonthViewCell::selectedIncidenceDate() 00737 { 00738 TQDate qd; 00739 int index = mItemList->currentItem(); 00740 if ( index < 0 ) return qd; 00741 00742 MonthViewItem *item = 00743 static_cast<MonthViewItem *>( mItemList->item( index ) ); 00744 00745 if ( !item ) return qd; 00746 00747 return item->incidenceDateTime().date(); 00748 } 00749 00750 void MonthViewCell::select() 00751 { 00752 00753 isSelected = true; 00754 00755 // setSelectedCell will deselect currently selected cells 00756 mMonthView->setSelectedCell( this ); 00757 00758 if( KOPrefs::instance()->enableMonthScroll() ) 00759 enableScrollBars( true ); 00760 00761 // don't mess up the cell when it represents today 00762 if( mDate != TQDate::currentDate() ) { 00763 mItemList->setFrameStyle( TQFrame::Sunken | TQFrame::Panel ); 00764 mItemList->setLineWidth( 3 ); 00765 } 00766 } 00767 00768 void MonthViewCell::deselect() 00769 { 00770 isSelected = false; 00771 00772 mItemList->clearSelection(); 00773 mItemList->setFrameStyle( TQFrame::Plain | TQFrame::Panel ); 00774 setFrameWidth(); 00775 00776 enableScrollBars( false ); 00777 } 00778 00779 void MonthViewCell::resizeEvent ( TQResizeEvent * ) 00780 { 00781 mLabel->move( width() - mLabel->width(), height() - mLabel->height() ); 00782 } 00783 00784 void MonthViewCell::defaultAction( TQListBoxItem *item ) 00785 { 00786 select(); 00787 00788 if ( !item ) { 00789 emit newEventSignal( 0/*ResourceCalendar*/, TQString()/*subResource*/, date() ); 00790 } else { 00791 MonthViewItem *eventItem = static_cast<MonthViewItem *>( item ); 00792 Incidence *incidence = eventItem->incidence(); 00793 if ( incidence ) mMonthView->defaultAction( incidence ); 00794 } 00795 } 00796 00797 void MonthViewCell::contextMenu( TQListBoxItem *item ) 00798 { 00799 select(); 00800 00801 if ( item ) { 00802 MonthViewItem *eventItem = static_cast<MonthViewItem *>( item ); 00803 Incidence *incidence = eventItem->incidence(); 00804 if ( incidence ) { 00805 mMonthView->showEventContextMenu( monthView()->calendar(), incidence, mDate ); 00806 } 00807 } else { 00808 mMonthView->showGeneralContextMenu(); 00809 } 00810 } 00811 00812 00813 KOMonthView::KOMonthView( Calendar *calendar, TQWidget *parent, const char *name ) 00814 : KOEventView( calendar, parent, name ), 00815 mDaysPerWeek( 7 ), mNumWeeks( 6 ), mNumCells( mDaysPerWeek * mNumWeeks ), 00816 mShortDayLabels( false ), mWidthLongDayLabel( 0 ), mSelectedCell( 0 ) 00817 { 00818 mCells.setAutoDelete( true ); 00819 00820 TQGridLayout *dayLayout = new TQGridLayout( this ); 00821 00822 TQFont bfont = font(); 00823 bfont.setBold( true ); 00824 00825 TQFont mfont = bfont; 00826 mfont.setPointSize( 20 ); 00827 00828 // month name on top 00829 mLabel = new TQLabel( this ); 00830 mLabel->setFont( mfont ); 00831 mLabel->setAlignment( AlignCenter ); 00832 mLabel->setLineWidth( 0 ); 00833 mLabel->setFrameStyle( TQFrame::Plain ); 00834 00835 dayLayout->addMultiCellWidget( mLabel, 0, 0, 0, mDaysPerWeek ); 00836 00837 // create the day of the week labels (Sun, Mon, etc) and add them to 00838 // the layout. 00839 mDayLabels.resize( mDaysPerWeek ); 00840 int i; 00841 for( i = 0; i < mDaysPerWeek; i++ ) { 00842 TQLabel *label = new TQLabel( this ); 00843 label->setFont( bfont ); 00844 label->setFrameStyle( TQFrame::Panel | TQFrame::Raised ); 00845 label->setLineWidth( 1 ); 00846 label->setAlignment( AlignCenter ); 00847 00848 mDayLabels.insert( i, label ); 00849 00850 dayLayout->addWidget( label, 1, i ); 00851 dayLayout->addColSpacing( i, 10 ); 00852 dayLayout->setColStretch( i, 1 ); 00853 } 00854 00855 int row, col; 00856 00857 mCells.resize( mNumCells ); 00858 for( row = 0; row < mNumWeeks; ++row ) { 00859 for( col = 0; col < mDaysPerWeek; ++col ) { 00860 MonthViewCell *cell = new MonthViewCell( this ); 00861 mCells.insert( row * mDaysPerWeek + col, cell ); 00862 dayLayout->addWidget( cell, row + 2, col ); 00863 00864 connect( cell, TQT_SIGNAL(defaultAction(Incidence *)), 00865 TQT_SLOT(defaultAction(Incidence *)) ); 00866 connect( cell, TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &,const TQDate &)), 00867 TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &,const TQDate &)) ); 00868 } 00869 dayLayout->setRowStretch( row + 2, 1 ); 00870 } 00871 00872 mEventContextMenu = eventPopup(); 00873 00874 updateConfig(); 00875 00876 emit incidenceSelected( 0, TQDate() ); 00877 } 00878 00879 KOMonthView::~KOMonthView() 00880 { 00881 delete mEventContextMenu; 00882 } 00883 00884 int KOMonthView::maxDatesHint() 00885 { 00886 return mNumCells; 00887 } 00888 00889 int KOMonthView::currentDateCount() 00890 { 00891 return mNumCells; 00892 } 00893 00894 Incidence::List KOMonthView::selectedIncidences() 00895 { 00896 Incidence::List selected; 00897 00898 if ( mSelectedCell ) { 00899 Incidence *incidence = mSelectedCell->selectedIncidence(); 00900 if ( incidence ) selected.append( incidence ); 00901 } 00902 00903 return selected; 00904 } 00905 00906 DateList KOMonthView::selectedIncidenceDates() 00907 { 00908 DateList selected; 00909 00910 if ( mSelectedCell ) { 00911 TQDate qd = mSelectedCell->selectedIncidenceDate(); 00912 if ( qd.isValid() ) selected.append( qd ); 00913 } 00914 00915 return selected; 00916 } 00917 00918 bool KOMonthView::eventDurationHint( TQDateTime &startDt, TQDateTime &endDt, bool &allDay ) 00919 { 00920 if ( mSelectedCell ) { 00921 startDt.setDate( mSelectedCell->date() ); 00922 endDt.setDate( mSelectedCell->date() ); 00923 allDay = true; 00924 return true; 00925 } 00926 return false; 00927 } 00928 00929 void KOMonthView::updateConfig() 00930 { 00931 mWeekStartDay = TDEGlobal::locale()->weekStartDay(); 00932 00933 TQFontMetrics fontmetric( mDayLabels[0]->font() ); 00934 mWidthLongDayLabel = 0; 00935 00936 for ( int i = 0; i < 7; ++i ) { 00937 int width = 00938 fontmetric.width( KOGlobals::self()->calendarSystem()->weekDayName( i + 1 ) ); 00939 if ( width > mWidthLongDayLabel ) mWidthLongDayLabel = width; 00940 } 00941 00942 updateDayLabels(); 00943 00944 for ( uint i = 0; i < mCells.count(); ++i ) { 00945 mCells[i]->updateConfig(); 00946 } 00947 00948 showLabel( !KOPrefs::instance()->fullViewMonth() ); 00949 } 00950 00951 void KOMonthView::updateDayLabels() 00952 { 00953 kdDebug(5850) << "KOMonthView::updateDayLabels()" << endl; 00954 00955 const KCalendarSystem*calsys=KOGlobals::self()->calendarSystem(); 00956 int currDay; 00957 for ( int i = 0; i < 7; i++ ) { 00958 currDay = i+mWeekStartDay; 00959 if ( currDay > 7 ) currDay -= 7; 00960 mDayLabels[i]->setText( calsys->weekDayName( currDay, mShortDayLabels ) ); 00961 } 00962 } 00963 00964 void KOMonthView::showDates( const TQDate &start, const TQDate & ) 00965 { 00966 // kdDebug(5850) << "KOMonthView::showDates(): " << start.toString() << endl; 00967 00968 const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem(); 00969 00970 mDateToCell.clear(); 00971 00972 // show first day of month on top for readability issues 00973 mStartDate = start.addDays( -start.day() + 1 ); 00974 // correct begin of week 00975 int weekdayCol=( mStartDate.dayOfWeek() + 7 - mWeekStartDay ) % 7; 00976 mStartDate = mStartDate.addDays( -weekdayCol ); 00977 00978 mLabel->setText( i18n( "monthname year", "%1 %2" ) 00979 .arg( calSys->monthName( start ) ) 00980 .arg( calSys->year( start ) ) ); 00981 00982 showLabel( !KOPrefs::instance()->fullViewMonth() ); 00983 00984 bool primary = false; 00985 uint i; 00986 for( i = 0; i < mCells.size(); ++i ) { 00987 TQDate date = mStartDate.addDays( i ); 00988 if ( calSys->day( date ) == 1 ) { 00989 primary = !primary; 00990 } 00991 00992 mCells[i]->setDate( date ); 00993 mDateToCell[ date ] = mCells[ i ]; 00994 if( date == start ) { 00995 mCells[i]->select(); 00996 } 00997 00998 mCells[i]->setPrimary( primary ); 00999 01000 bool isHoliday = calSys->dayOfWeek( date ) == calSys->weekDayOfPray() 01001 || !KOGlobals::self()->isWorkDay( date ); 01002 mCells[i]->setHoliday( isHoliday ); 01003 01004 // add holiday, if present 01005 TQStringList holidays( KOGlobals::self()->holiday( date ) ); 01006 mCells[i]->setHolidayString( holidays.join( i18n("delimiter for joining holiday names", ", " ) ) ); 01007 } 01008 01009 updateView(); 01010 } 01011 01012 TQDateTime KOMonthView::selectionStart() 01013 { 01014 if ( mSelectedCell) { 01015 return TQDateTime( mSelectedCell->date() ); 01016 } else { 01017 return TQDateTime(); 01018 } 01019 } 01020 01021 TQDateTime KOMonthView::selectionEnd() 01022 { 01023 // Only one cell can be selected (for now) 01024 return selectionStart(); 01025 } 01026 01027 void KOMonthView::showIncidences( const Incidence::List &, const TQDate & ) 01028 { 01029 kdDebug(5850) << "KOMonthView::showIncidences( const Incidence::List & ) is not implemented yet." << endl; 01030 } 01031 01032 class KOMonthView::GetDateVisitor : public IncidenceBase::Visitor 01033 { 01034 public: 01035 GetDateVisitor() {} 01036 01037 bool act( IncidenceBase *incidence ) 01038 { 01039 return incidence->accept( *this ); 01040 } 01041 TQDateTime startDate() const { return mStartDate; } 01042 TQDateTime endDate() const { return mEndDate; } 01043 01044 protected: 01045 bool visit( Event *event ) { 01046 mStartDate = event->dtStart(); 01047 mEndDate = event->dtEnd(); 01048 return true; 01049 } 01050 bool visit( Todo *todo ) { 01051 if ( todo->hasDueDate() ) { 01052 if ( todo->dtDue().time() != TQTime( 0, 0 ) && 01053 todo->dtDue().time().isValid() ) { 01054 mStartDate = todo->dtDue(); 01055 mEndDate = todo->dtDue(); 01056 } else { 01057 mStartDate = TQDateTime( todo->dtDue().date(), TQTime( 23,59 ) ); 01058 mEndDate = mStartDate; 01059 } 01060 }// else 01061 // return false; 01062 return true; 01063 } 01064 bool visit( Journal *journal ) { 01065 mStartDate = journal->dtStart(); 01066 mEndDate = journal->dtStart(); 01067 return true; 01068 } 01069 protected: 01070 TQDateTime mStartDate; 01071 TQDateTime mEndDate; 01072 }; 01073 01074 void KOMonthView::changeIncidenceDisplayAdded( Incidence *incidence, MonthViewCell::CreateItemVisitor& v) 01075 { 01076 GetDateVisitor gdv; 01077 01078 if ( !gdv.act( incidence ) ) { 01079 kdDebug(5850) << "Visiting GetDateVisitor failed." << endl; 01080 return; 01081 } 01082 01083 bool floats = incidence->doesFloat(); 01084 01085 if ( incidence->doesRecur() ) { 01086 for ( uint i = 0; i < mCells.count(); ++i ) { 01087 if ( incidence->recursOn( mCells[i]->date(), calendar() ) ) { 01088 01089 // handle multiday events 01090 int length = gdv.startDate().daysTo( TQDateTime(gdv.endDate().addSecs( floats ? 0 : -1 ).date()) ); 01091 for ( int j = 0; j <= length && i+j < mCells.count(); ++j ) { 01092 mCells[i+j]->addIncidence( incidence, v, j ); 01093 } 01094 } 01095 } 01096 } else { 01097 // addSecs(-1) is added to handle 0:00 cases (because it's non-inclusive according to rfc) 01098 if ( gdv.endDate().isValid() ) { 01099 TQDate endDate = gdv.endDate().addSecs( floats ? 0 : -1).date(); 01100 for ( TQDate date = gdv.startDate().date(); 01101 date <= endDate; date = date.addDays( 1 ) ) { 01102 MonthViewCell *mvc = mDateToCell[ date ]; 01103 if ( mvc ) mvc->addIncidence( incidence, v ); 01104 } 01105 } 01106 } 01107 } 01108 01109 void KOMonthView::changeIncidenceDisplay( Incidence *incidence, int action ) 01110 { 01111 MonthViewCell::CreateItemVisitor v; 01112 switch ( action ) { 01113 case KOGlobals::INCIDENCEADDED: 01114 changeIncidenceDisplayAdded( incidence, v ); 01115 break; 01116 case KOGlobals::INCIDENCEEDITED: 01117 for( uint i = 0; i < mCells.count(); i++ ) 01118 mCells[i]->removeIncidence( incidence ); 01119 changeIncidenceDisplayAdded( incidence, v ); 01120 break; 01121 case KOGlobals::INCIDENCEDELETED: 01122 for( uint i = 0; i < mCells.count(); i++ ) 01123 mCells[i]->removeIncidence( incidence ); 01124 break; 01125 default: 01126 return; 01127 } 01128 } 01129 01130 void KOMonthView::updateView() 01131 { 01132 for( uint i = 0; i < mCells.count(); ++i ) { 01133 mCells[i]->updateCell(); 01134 } 01135 01136 Incidence::List incidences = calendar()->incidences(); 01137 Incidence::List::ConstIterator it; 01138 01139 MonthViewCell::CreateItemVisitor v; 01140 for ( it = incidences.begin(); it != incidences.end(); ++it ) 01141 changeIncidenceDisplayAdded( *it, v ); 01142 01143 processSelectionChange(); 01144 } 01145 01146 void KOMonthView::resizeEvent( TQResizeEvent * ) 01147 { 01148 // select the appropriate heading string size. E.g. "Wednesday" or "Wed". 01149 // note this only changes the text if the requested size crosses the 01150 // threshold between big enough to support the full name and not big 01151 // enough. 01152 if( mDayLabels[0]->width() < mWidthLongDayLabel ) { 01153 if ( !mShortDayLabels ) { 01154 mShortDayLabels = true; 01155 updateDayLabels(); 01156 } 01157 } else { 01158 if ( mShortDayLabels ) { 01159 mShortDayLabels = false; 01160 updateDayLabels(); 01161 } 01162 } 01163 } 01164 01165 void KOMonthView::showEventContextMenu( Calendar *cal, Incidence *incidence, const TQDate &qd ) 01166 { 01167 mEventContextMenu->showIncidencePopup( cal, incidence, qd ); 01168 } 01169 01170 void KOMonthView::showGeneralContextMenu() 01171 { 01172 showNewEventPopup(); 01173 } 01174 01175 void KOMonthView::setSelectedCell( MonthViewCell *cell ) 01176 { 01177 if ( mSelectedCell && cell != mSelectedCell ) 01178 mSelectedCell->deselect(); 01179 01180 mSelectedCell = cell; 01181 01182 if ( !mSelectedCell ) 01183 emit incidenceSelected( 0, TQDate() ); 01184 else 01185 if ( selectedIncidenceDates().isEmpty() ) { 01186 emit incidenceSelected( mSelectedCell->selectedIncidence(), TQDate() ); 01187 } else { 01188 emit incidenceSelected( mSelectedCell->selectedIncidence(), selectedIncidenceDates().first() ); 01189 } 01190 } 01191 01192 void KOMonthView::processSelectionChange() 01193 { 01194 Incidence::List incidences = selectedIncidences(); 01195 if (incidences.count() > 0) { 01196 if ( selectedIncidenceDates().isEmpty() ) { 01197 emit incidenceSelected( incidences.first(), TQDate() ); 01198 } else { 01199 emit incidenceSelected( incidences.first(), selectedIncidenceDates().first() ); 01200 } 01201 } else { 01202 emit incidenceSelected( 0, TQDate() ); 01203 } 01204 } 01205 01206 void KOMonthView::clearSelection() 01207 { 01208 if ( mSelectedCell ) { 01209 mSelectedCell->deselect(); 01210 mSelectedCell = 0; 01211 } 01212 } 01213 01214 void KOMonthView::showLabel( bool show ) 01215 { 01216 if ( show ) { 01217 mLabel->show(); 01218 } else { 01219 mLabel->hide(); 01220 } 01221 }