korganizer

komonthview.cpp
1/*
2 This file is part of KOrganizer.
3
4 Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org>
5 Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
21 As a special exception, permission is given to link this program
22 with any edition of TQt, and distribute the resulting executable,
23 without including the source code for TQt in the source distribution.
24*/
25
26#include <tqpopupmenu.h>
27#include <tqfont.h>
28#include <tqfontmetrics.h>
29#include <tqkeycode.h>
30#include <tqhbox.h>
31#include <tqvbox.h>
32#include <tqpushbutton.h>
33#include <tqtooltip.h>
34#include <tqpainter.h>
35#include <tqcursor.h>
36#include <tqlistbox.h>
37#include <tqlayout.h>
38#include <tqlabel.h>
39
40#include <kdebug.h>
41#include <tdelocale.h>
42#include <tdeglobal.h>
43#include <tdeconfig.h>
44#include <kiconloader.h>
45#include <kwordwrap.h>
46
47#include <kcalendarsystem.h>
48#include <libkcal/calfilter.h>
49#include <libkcal/calendar.h>
50#include <libkcal/incidenceformatter.h>
52
53#include "koprefs.h"
54#include "koglobals.h"
55#include "koincidencetooltip.h"
56#include "koeventpopupmenu.h"
57#include "kohelper.h"
58
59#include "komonthview.h"
60#include "komonthview.moc"
61
62//--------------------------------------------------------------------------
63
64KOMonthCellToolTip::KOMonthCellToolTip( TQWidget *parent,
65 Calendar *calendar,
66 const TQDate &date,
67 KNoScrollListBox *lv )
68 : TQToolTip( parent ), mCalendar( calendar ), mDate( date )
69{
70 eventlist = lv;
71}
72
73void KOMonthCellToolTip::maybeTip( const TQPoint &pos )
74{
75 TQRect r;
76 TQListBoxItem *it = eventlist->itemAt( pos );
77 MonthViewItem *i = static_cast<MonthViewItem*>( it );
78
79 if( i && KOPrefs::instance()->mEnableToolTips ) {
80 /* Calculate the rectangle. */
81 r=eventlist->itemRect( it );
82 /* Show the tip */
83 TQString tipText( IncidenceFormatter::toolTipStr( mCalendar, i->incidence(), mDate ) );
84 if ( tipText.isEmpty() && !i->incidence() ) {
85 const TQStringList holidays = KOGlobals::self()->holiday( mDate );
86 tipText = "<qt><b>" + holidays.join( "<br/>" ) + "</b><br/>----------<br/>";
87 tipText += i18n( "<i>Date:</i>&nbsp;%1" )
88 .arg( TDEGlobal::locale()->formatDate( mDate ).replace( " ", "&nbsp;" ) );
89 tipText += "<br/>" + i18n( "<i>Day of year:</i>&nbsp;%1" )
90 .arg( KOGlobals::self()->calendarSystem()->dayOfYear( mDate ) );
91 tipText += "</qt>";
92 }
93 if ( !tipText.isEmpty() ) {
94 tip( r, tipText );
95 }
96 }
97}
98
99KNoScrollListBox::KNoScrollListBox( TQWidget *parent, const char *name )
100 : TQListBox( parent, name ),
101 mSqueezing( false )
102{
103 TQPalette pal = palette();
104 pal.setColor( TQColorGroup::Foreground, KOPrefs::instance()->agendaBgColor().dark( 150 ) );
105 pal.setColor( TQColorGroup::Base, KOPrefs::instance()->agendaBgColor() );
106 setPalette( pal );
107}
108
109void KNoScrollListBox::setBackground( bool primary, bool workDay )
110{
111 TQColor color;
112 if ( workDay ) {
113 color = KOPrefs::instance()->workingHoursColor();
114 } else {
115 color = KOPrefs::instance()->agendaBgColor();
116 }
117
118 TQPalette pal = palette();
119 if ( primary ) {
120 pal.setColor( TQColorGroup::Base, color );
121 } else {
122 pal.setColor( TQColorGroup::Base, color.dark( 115 ) );
123 }
124 setPalette( pal );
125}
126
127void KNoScrollListBox::keyPressEvent( TQKeyEvent *e )
128{
129 switch( e->key() ) {
130 case Key_Right:
131 scrollBy( 4, 0 );
132 break;
133 case Key_Left:
134 scrollBy( -4, 0 );
135 break;
136 case Key_Up:
137 if ( !count() ) break;
138 setCurrentItem( ( currentItem() + count() - 1 ) % count() );
139 if ( !itemVisible( currentItem() ) ) {
140 if ( (unsigned int)currentItem() == ( count() - 1 ) ) {
141 setTopItem( currentItem() - numItemsVisible() + 1 );
142 } else {
143 setTopItem( topItem() - 1 );
144 }
145 }
146 break;
147 case Key_Down:
148 if ( !count() ) break;
149 setCurrentItem( ( currentItem() + 1 ) % count() );
150 if( !itemVisible( currentItem() ) ) {
151 if( currentItem() == 0 ) {
152 setTopItem( 0 );
153 } else {
154 setTopItem( topItem() + 1 );
155 }
156 }
157 case Key_Shift:
158 emit shiftDown();
159 break;
160 default:
161 break;
162 }
163}
164
165void KNoScrollListBox::keyReleaseEvent( TQKeyEvent *e )
166{
167 switch( e->key() ) {
168 case Key_Shift:
169 emit shiftUp();
170 break;
171 default:
172 break;
173 }
174}
175
176void KNoScrollListBox::mousePressEvent( TQMouseEvent *e )
177{
178 TQListBox::mousePressEvent( e );
179
180 if ( e->button() == TQt::RightButton ) {
181 emit rightClick();
182 }
183}
184
185void KNoScrollListBox::contentsMouseDoubleClickEvent ( TQMouseEvent * e )
186{
187 TQListBox::contentsMouseDoubleClickEvent( e );
188 TQListBoxItem *item = itemAt( e->pos() );
189 if ( !item ) {
190 emit doubleClicked( item );
191 }
192}
193
194void KNoScrollListBox::resizeEvent( TQResizeEvent *e )
195{
196 bool s = count() && ( maxItemWidth() > e->size().width() );
197 if ( mSqueezing || s )
198 triggerUpdate( false );
199
200 mSqueezing = s;
201 TQListBox::resizeEvent( e );
202}
203
204MonthViewItem::MonthViewItem( Incidence *incidence, const TQDateTime &qd,
205 const TQString & s ) : TQListBoxItem()
206{
207 setText( s );
208
209 mIncidence = incidence;
210 mDateTime = qd;
211
212 mEventPixmap = KOGlobals::self()->smallIcon( "appointment" );
213 mBirthdayPixmap = KOGlobals::self()->smallIcon( "calendarbirthday" );
214 mAnniversaryPixmap= KOGlobals::self()->smallIcon( "calendaranniversary" );
215 mTodoPixmap = KOGlobals::self()->smallIcon( "todo" );
216 mTodoDonePixmap = KOGlobals::self()->smallIcon( "checkedbox" );
217 mAlarmPixmap = KOGlobals::self()->smallIcon( "bell" );
218 mRecurPixmap = KOGlobals::self()->smallIcon( "recur" );
219 mReplyPixmap = KOGlobals::self()->smallIcon( "mail-reply-sender" );
220
221 mEvent = false;
222 mTodo = false;
223 mTodoDone = false;
224 mRecur = false;
225 mAlarm = false;
226 mReply = false;
227}
228
229TQColor MonthViewItem::catColor() const
230{
231 TQColor retColor;
232 if ( !mIncidence ) {
233 return retColor;
234 }
235
236 TQStringList categories = mIncidence->categories();
237 TQString cat;
238 if ( !categories.isEmpty() ) {
239 cat = categories.first();
240 }
241 if ( cat.isEmpty() ) {
242 retColor = KOPrefs::instance()->unsetCategoryColor();
243 } else {
244 retColor = *( KOPrefs::instance()->categoryColor( cat ) );
245 }
246 return retColor;
247}
248
249void MonthViewItem::paint( TQPainter *p )
250{
251 bool sel = isSelected();
252
253 TQColor bgColor = TQColor(); // Default invalid color;
254 if ( mIncidence && mTodo ) {
255 if ( static_cast<Todo*>( mIncidence )->isOverdue() ) {
256 bgColor = KOPrefs::instance()->todoOverdueColor();
257 } else if ( static_cast<Todo*>( mIncidence )->dtDue().date() == TQDate::currentDate() ) {
258 bgColor = KOPrefs::instance()->todoDueTodayColor();
259 }
260 }
261
262 if ( !bgColor.isValid() ) {
263 if ( KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceOnly ||
264 KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceInsideCategoryOutside ) {
265 bgColor = resourceColor();
266 } else {
267 bgColor = catColor();
268 }
269
270 if ( !bgColor.isValid() ) {
271 bgColor = palette().color( TQPalette::Active,
272 sel ? TQColorGroup::Highlight :
273 TQColorGroup::Background );
274 }
275 }
276
277 TQColor frameColor;
278 if ( KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceOnly ||
279 KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryInsideResourceOutside ) {
280 frameColor = resourceColor();
281 } else {
282 frameColor = catColor();
283 }
284
285 if ( mIncidence ) {
286 if ( mIncidence->categories().isEmpty() &&
287 KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceInsideCategoryOutside ) {
288 frameColor = bgColor;
289 }
290
291 if ( mIncidence->categories().isEmpty() &&
292 KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryInsideResourceOutside ) {
293 bgColor = frameColor;
294 }
295 }
296
297 if ( !frameColor.isValid() ) {
298 frameColor = palette().color( TQPalette::Active,
299 sel ? TQColorGroup::Highlight :
300 TQColorGroup::Foreground );
301 } else {
302 frameColor = frameColor.dark( 115 );
303 }
304
305 // draw the box for the item
306 p->setBackgroundColor( frameColor );
307 p->eraseRect( 0, 0, listBox()->maxItemWidth(), height( listBox() ) );
308 int offset = 2;
309 p->setBackgroundColor( bgColor );
310 p->eraseRect( offset, offset, listBox()->maxItemWidth()-2*offset, height( listBox() )-2*offset );
311
312 int x = 3;
313
314 bool specialEvent = false;
315 if ( mEvent ) {
316 if ( mIncidence->customProperty( "KABC", "BIRTHDAY" ) == "YES" ) {
317 specialEvent = true;
318 if ( mIncidence->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) {
319 p->drawPixmap( x, 0, mAnniversaryPixmap );
320 x += mAnniversaryPixmap.width() + 2;
321 } else {
322 p->drawPixmap( x, 0, mBirthdayPixmap );
323 x += mBirthdayPixmap.width() + 2;
324 }
325 // Do NOT put on the event pixmap because it takes up too much space
326 //} else {
327 // p->drawPixmap( x, 0, mEventPixmap );
328 // x += mEventPixmap.width() + 2;
329 //
330 }
331 }
332
333 if ( mTodo ) {
334 p->drawPixmap( x, 0, mTodoPixmap );
335 x += mTodoPixmap.width() + 2;
336 }
337 if ( mTodoDone ) {
338 p->drawPixmap( x, 0, mTodoDonePixmap );
339 x += mTodoPixmap.width() + 2;
340 }
341 if ( mRecur && !specialEvent ) {
342 p->drawPixmap( x, 0, mRecurPixmap );
343 x += mRecurPixmap.width() + 2;
344 }
345 if ( mAlarm && !specialEvent ) {
346 p->drawPixmap( x, 0, mAlarmPixmap );
347 x += mAlarmPixmap.width() + 2;
348 }
349 if ( mReply ) {
350 p->drawPixmap(x, 0, mReplyPixmap );
351 x += mReplyPixmap.width() + 2;
352 }
353 TQFontMetrics fm = p->fontMetrics();
354 int yPos;
355 int pmheight = TQMAX( mRecurPixmap.height(),
356 TQMAX( mAlarmPixmap.height(), mReplyPixmap.height() ) );
357 if( pmheight < fm.height() )
358 yPos = fm.ascent() + fm.leading()/2;
359 else
360 yPos = pmheight/2 - fm.height()/2 + fm.ascent();
361 TQColor textColor = getTextColor( bgColor );
362 p->setPen( textColor );
363
364 KWordWrap::drawFadeoutText( p, x, yPos, listBox()->width() - x, text() );
365}
366
367int MonthViewItem::height( const TQListBox *lb ) const
368{
369 return TQMAX( TQMAX( mRecurPixmap.height(), mReplyPixmap.height() ),
370 TQMAX( mAlarmPixmap.height(), lb->fontMetrics().lineSpacing()+1) );
371}
372
373int MonthViewItem::width( const TQListBox *lb ) const
374{
375 int x = 3;
376 if( mRecur ) {
377 x += mRecurPixmap.width()+2;
378 }
379 if( mAlarm ) {
380 x += mAlarmPixmap.width()+2;
381 }
382 if( mReply ) {
383 x += mReplyPixmap.width()+2;
384 }
385
386 return( x + lb->fontMetrics().boundingRect( text() ).width() + 1 );
387}
388
389
390MonthViewCell::MonthViewCell( KOMonthView *parent)
391 : TQWidget( parent ),
392 mMonthView( parent ), mPrimary( false ), mHoliday( false ),
393 isSelected( false )
394{
395 TQVBoxLayout *topLayout = new TQVBoxLayout( this );
396
397 mLabel = new TQLabel( this );
398 mLabel->setFrameStyle( TQFrame::Panel | TQFrame::Plain );
399 mLabel->setLineWidth( 1 );
400 mLabel->setAlignment( AlignCenter );
401
402 mItemList = new KNoScrollListBox( this );
403 mItemList->setMinimumSize( 10, 10 );
404 mItemList->setFrameStyle( TQFrame::Panel | TQFrame::Plain );
405 mItemList->setLineWidth( 1 );
406
407 topLayout->addWidget( mItemList );
408
409 mLabel->raise();
410
411 mStandardPalette = palette();
412
413 enableScrollBars( false );
414
415 updateConfig();
416
417 connect( mItemList, TQ_SIGNAL( doubleClicked( TQListBoxItem *) ),
418 TQ_SLOT( defaultAction( TQListBoxItem * ) ) );
419 connect( mItemList, TQ_SIGNAL( rightButtonPressed( TQListBoxItem *,
420 const TQPoint &) ),
421 TQ_SLOT( contextMenu( TQListBoxItem * ) ) );
422 connect( mItemList, TQ_SIGNAL( clicked( TQListBoxItem * ) ),
423 TQ_SLOT( select() ) );
424}
425
426void MonthViewCell::setDate( const TQDate &date )
427{
428// kdDebug(5850) << "MonthViewCell::setDate(): " << date.toString() << endl;
429
430 mDate = date;
431
432 setFrameWidth();
433
434 TQString text;
435 if ( KOGlobals::self()->calendarSystem()->day( date ) == 1 ) {
436 text = i18n("'Month day' for month view cells", "%1 %2")
437 .arg( KOGlobals::self()->calendarSystem()->monthName( date, true ) )
438 .arg( KOGlobals::self()->calendarSystem()->day(mDate) );
439 TQFontMetrics fm( mLabel->font() );
440 mLabel->resize( mLabelSize + TQSize( fm.width( text ), 0 ) );
441 } else {
442 mLabel->resize( mLabelSize );
443 text = TQString::number( KOGlobals::self()->calendarSystem()->day(mDate) );
444 }
445 mLabel->setText( text );
446
447 new KOMonthCellToolTip( mItemList->viewport(),
448 monthView()->calendar(),
449 mDate,
450 static_cast<KNoScrollListBox *>( mItemList ) );
451
452 resizeEvent( 0 );
453}
454
456{
457 return mDate;
458}
459
460void MonthViewCell::setFrameWidth()
461{
462 // show current day with a thicker frame
463 if ( mDate == TQDate::currentDate() ) {
464 mItemList->setLineWidth( 3 );
465 } else if ( !isSelected ) {
466 mItemList->setLineWidth( 1 );
467 }
468}
469
470void MonthViewCell::setPrimary( bool primary )
471{
472 mPrimary = primary;
473
474 if ( mPrimary ) {
475 mLabel->setBackgroundMode( PaletteBase );
476 } else {
477 mLabel->setBackgroundMode( PaletteBackground );
478 }
479
480 mItemList->setBackground( mPrimary, KOGlobals::self()->isWorkDay( mDate ) );
481}
482
484{
485 return mPrimary;
486}
487
488void MonthViewCell::setHoliday( bool holiday )
489{
490 mHoliday = holiday;
491
492 if ( holiday ) {
493 setPalette( mHolidayPalette );
494 } else {
495 setPalette( mStandardPalette );
496 }
497}
498
499void MonthViewCell::setHolidayString( const TQString &holiday )
500{
501 mHolidayString = holiday;
502}
503
504void MonthViewCell::updateCell()
505{
506 setFrameWidth();
507
508 if ( mDate == TQDate::currentDate() ) {
509 setPalette( mTodayPalette );
510
511 TQPalette pal = mItemList->palette();
512 pal.setColor( TQColorGroup::Foreground, KOPrefs::instance()->highlightColor() );
513 mItemList->setPalette( pal );
514 }
515 else {
516 if ( mHoliday )
517 setPalette( mHolidayPalette );
518 else
519 setPalette( mStandardPalette );
520
521 TQPalette pal = mItemList->palette();
522 pal.setColor( TQColorGroup::Foreground, KOPrefs::instance()->agendaBgColor().dark( 150 ) );
523 mItemList->setPalette( pal );
524 }
525
526 mItemList->clear();
527
528 if ( !mHolidayString.isEmpty() ) {
529 MonthViewItem *item = new MonthViewItem( 0, TQDateTime( mDate ), mHolidayString );
530 item->setPalette( mHolidayPalette );
531 mItemList->insertItem( item );
532 }
533}
534
535class MonthViewCell::CreateItemVisitor :
537{
538 public:
539 CreateItemVisitor() : mItem(0) { emails = KOPrefs::instance()->allEmails(); }
540
541 bool act( IncidenceBase *incidence, TQDate date, TQPalette stdPal, int multiDay )
542 {
543 mItem = 0;
544 mDate = date;
545 mStandardPalette = stdPal;
546 mMultiDay = multiDay;
547 return incidence->accept( *this );
548 }
549 MonthViewItem *item() const { return mItem; }
550 TQStringList emails;
551
552 protected:
553 bool visit( Event *event ) {
554 TQString text;
555 TQDateTime dt( mDate );
556 // take the time 0:00 into account, which is non-inclusive
557 TQDate dtEnd = event->dtEnd().addSecs( event->doesFloat() ? 0 : -1).date();
558 int length = event->dtStart().daysTo( TQDateTime(dtEnd) );
559 if ( event->isMultiDay() ) {
560 if ( mDate == event->dtStart().date()
561 || ( mMultiDay == 0 && event->recursOn( mDate ) ) ) {
562 text = "(-- " + event->summary();
563 dt = event->dtStart();
564 } else if ( !event->doesRecur() && mDate == dtEnd
565 // last day of a recurring multi-day event?
566 || ( mMultiDay == length && event->recursOn( mDate.addDays( -length ) ) ) ) {
567 text = event->summary() + " --)";
568 } else if (!(event->dtStart().date().daysTo(mDate) % 7) && length > 7 ) {
569 text = "-- " + event->summary() + " --";
570 } else {
571 text = "----------------";
572 dt = TQDateTime( mDate );
573 }
574 } else {
575 if (event->doesFloat())
576 text = event->summary();
577 else {
578 text = TDEGlobal::locale()->formatTime(event->dtStart().time());
579 dt.setTime( event->dtStart().time() );
580 text += ' ' + event->summary();
581 }
582 }
583
584 mItem = new MonthViewItem( event, dt, text );
585 mItem->setEvent( true );
586 if ( KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryOnly ||
587 KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryInsideResourceOutside ) {
588 TQStringList categories = event->categories();
589 TQString cat = categories.first();
590 if (cat.isEmpty()) {
591 mItem->setPalette(TQPalette(KOPrefs::instance()->unsetCategoryColor(),
592 KOPrefs::instance()->unsetCategoryColor()) );
593 } else {
594 mItem->setPalette(TQPalette(*(KOPrefs::instance()->categoryColor(cat)),
595 *(KOPrefs::instance()->categoryColor(cat))));
596 }
597 } else {
598 mItem->setPalette( mStandardPalette );
599 }
600
601 Attendee *me = event->attendeeByMails( emails );
602 if ( me != 0 ) {
603 mItem->setReply( me->status() == Attendee::NeedsAction && me->RSVP() );
604 } else
605 mItem->setReply(false);
606 return true;
607 }
608 bool visit( Todo *todo ) {
609 TQString text;
610 if ( !KOPrefs::instance()->showAllDayTodo() )
611 return false;
612 TQDateTime dt( mDate );
613 if ( todo->hasDueDate() && !todo->doesFloat() &&
614 todo->dtDue().time() != TQTime( 0,0 ) && todo->dtDue().time().isValid() ) {
615 text += TDEGlobal::locale()->formatTime( todo->dtDue().time() );
616 text += ' ';
617 dt.setTime( todo->dtDue().time() );
618 }
619 text += todo->summary();
620
621 mItem = new MonthViewItem( todo, dt, text );
622 if ( todo->doesRecur() ) {
623 mDate < todo->dtDue().date() ?
624 mItem->setTodoDone( true ) : mItem->setTodo( true );
625 }
626 else
627 todo->isCompleted() ? mItem->setTodoDone( true ) : mItem->setTodo( true );
628 mItem->setPalette( mStandardPalette );
629 return true;
630 }
631 protected:
632 MonthViewItem *mItem;
633 TQDate mDate;
634 TQPalette mStandardPalette;
635 int mMultiDay;
636};
637
638
639void MonthViewCell::addIncidence( Incidence *incidence, CreateItemVisitor& v, int multiDay )
640{
641 if ( v.act( incidence, mDate, mStandardPalette, multiDay ) ) {
642 MonthViewItem *item = v.item();
643 if ( item ) {
644 item->setAlarm( incidence->isAlarmEnabled() );
645 item->setRecur( incidence->recurrenceType() );
646
647 TQColor resourceColor = KOHelper::resourceColor( monthView()->calendar(), incidence );
648 if ( !resourceColor.isValid() )
649 resourceColor = KOPrefs::instance()->unsetCategoryColor();
650 item->setResourceColor( resourceColor );
651
652 // FIXME: Find the correct position (time-wise) to insert the item.
653 // Currently, the items are displayed in "random" order instead of
654 // chronologically sorted.
655 uint i = 0;
656 int pos = -1;
657 TQDateTime dt( item->incidenceDateTime() );
658
659 while ( i < mItemList->count() && pos<0 ) {
660 TQListBoxItem *item = mItemList->item( i );
661 MonthViewItem *mvitem = dynamic_cast<MonthViewItem*>( item );
662 if ( mvitem && mvitem->incidenceDateTime()>dt ) {
663 pos = i;
664 }
665 ++i;
666 }
667 mItemList->insertItem( item, pos );
668 }
669 }
670}
671
673{
674 for ( uint i = 0; i < mItemList->count(); ++i ) {
675 MonthViewItem *item = static_cast<MonthViewItem *>(mItemList->item( i ) );
676 if ( item && item->incidence() &&
677 item->incidence()->uid() == incidence->uid() ) {
678 mItemList->removeItem( i );
679 --i;
680 }
681 }
682}
683
684void MonthViewCell::updateConfig()
685{
686 setFont( KOPrefs::instance()->mMonthViewFont );
687
688 TQFontMetrics fm( font() );
689 mLabelSize = fm.size( 0, "30" ) +
690 TQSize( mLabel->frameWidth() * 2, mLabel->frameWidth() * 2 ) +
691 TQSize( 2, 2 );
692// mStandardPalette = mOriginalPalette;
693 TQColor bg = mStandardPalette.color( TQPalette::Active, TQColorGroup::Background );
694 int h,s,v;
695 bg.getHsv( &h, &s, &v );
696 if ( date().month() %2 == 0 ) {
697 if ( v < 128 ) {
698 bg = bg.light( 125 );
699 } else {
700 bg = bg.dark( 125 );
701 }
702 }
703 setPaletteBackgroundColor( bg );
704// mStandardPalette.setColor( TQColorGroup::Background, bg);*/
705
706 mHolidayPalette = mStandardPalette;
707 mHolidayPalette.setColor( TQColorGroup::Foreground,
708 KOPrefs::instance()->holidayColor() );
709 mHolidayPalette.setColor( TQColorGroup::Text,
710 KOPrefs::instance()->holidayColor() );
711 mTodayPalette = mStandardPalette;
712 mTodayPalette.setColor( TQColorGroup::Foreground,
713 KOPrefs::instance()->highlightColor() );
714 mTodayPalette.setColor( TQColorGroup::Text,
715 KOPrefs::instance()->highlightColor() );
716 updateCell();
717
718 mItemList->setBackground( mPrimary, KOGlobals::self()->isWorkDay( mDate ) );
719}
720
721void MonthViewCell::enableScrollBars( bool enabled )
722{
723 if ( enabled ) {
724 mItemList->setVScrollBarMode( TQScrollView::Auto );
725 mItemList->setHScrollBarMode( TQScrollView::Auto );
726 } else {
727 mItemList->setVScrollBarMode( TQScrollView::AlwaysOff );
728 mItemList->setHScrollBarMode( TQScrollView::AlwaysOff );
729 }
730}
731
732Incidence *MonthViewCell::selectedIncidence()
733{
734 int index = mItemList->currentItem();
735 if ( index < 0 ) return 0;
736
737 MonthViewItem *item =
738 static_cast<MonthViewItem *>( mItemList->item( index ) );
739
740 if ( !item ) return 0;
741
742 return item->incidence();
743}
744
745TQDate MonthViewCell::selectedIncidenceDate()
746{
747 TQDate qd;
748 int index = mItemList->currentItem();
749 if ( index < 0 ) return qd;
750
751 MonthViewItem *item =
752 static_cast<MonthViewItem *>( mItemList->item( index ) );
753
754 if ( !item ) return qd;
755
756 return item->incidenceDateTime().date();
757}
758
759void MonthViewCell::select()
760{
761
762 isSelected = true;
763
764 // setSelectedCell will deselect currently selected cells
765 mMonthView->setSelectedCell( this );
766
767 if( KOPrefs::instance()->enableMonthScroll() )
768 enableScrollBars( true );
769
770 // don't mess up the cell when it represents today
771 if( mDate != TQDate::currentDate() ) {
772 mItemList->setFrameStyle( TQFrame::Sunken | TQFrame::Panel );
773 mItemList->setLineWidth( 3 );
774 }
775}
776
777void MonthViewCell::deselect()
778{
779 isSelected = false;
780
781 mItemList->clearSelection();
782 mItemList->setFrameStyle( TQFrame::Plain | TQFrame::Panel );
783 setFrameWidth();
784
785 enableScrollBars( false );
786}
787
788void MonthViewCell::resizeEvent ( TQResizeEvent * )
789{
790 mLabel->move( width() - mLabel->width(), height() - mLabel->height() );
791}
792
793void MonthViewCell::defaultAction( TQListBoxItem *item )
794{
795 select();
796
797 if ( !item ) {
798 emit newEventSignal( 0/*ResourceCalendar*/, TQString()/*subResource*/, date() );
799 } else {
800 MonthViewItem *eventItem = static_cast<MonthViewItem *>( item );
801 Incidence *incidence = eventItem->incidence();
802 if ( incidence ) mMonthView->defaultAction( incidence );
803 }
804}
805
806void MonthViewCell::contextMenu( TQListBoxItem *item )
807{
808 select();
809
810 if ( item ) {
811 MonthViewItem *eventItem = static_cast<MonthViewItem *>( item );
812 Incidence *incidence = eventItem->incidence();
813 if ( incidence ) {
814 mMonthView->showEventContextMenu( monthView()->calendar(), incidence, mDate );
815 }
816 } else {
817 mMonthView->showGeneralContextMenu();
818 }
819}
820
821
822KOMonthView::KOMonthView( Calendar *calendar, TQWidget *parent, const char *name )
823 : KOEventView( calendar, parent, name ),
824 mDaysPerWeek( 7 ), mNumWeeks( 6 ), mNumCells( mDaysPerWeek * mNumWeeks ),
825 mShortDayLabels( false ), mWidthLongDayLabel( 0 ), mSelectedCell( 0 )
826{
827 mCells.setAutoDelete( true );
828
829 TQGridLayout *dayLayout = new TQGridLayout( this );
830
831 TQFont bfont = font();
832 bfont.setBold( true );
833
834 TQFont mfont = bfont;
835 mfont.setPointSize( 20 );
836
837 // month name on top
838 mLabel = new TQLabel( this );
839 mLabel->setFont( mfont );
840 mLabel->setAlignment( AlignCenter );
841 mLabel->setLineWidth( 0 );
842 mLabel->setFrameStyle( TQFrame::Plain );
843
844 dayLayout->addMultiCellWidget( mLabel, 0, 0, 0, mDaysPerWeek );
845
846 // create the day of the week labels (Sun, Mon, etc) and add them to
847 // the layout.
848 mDayLabels.resize( mDaysPerWeek );
849 int i;
850 for( i = 0; i < mDaysPerWeek; i++ ) {
851 TQLabel *label = new TQLabel( this );
852 label->setFont( bfont );
853 label->setFrameStyle( TQFrame::Panel | TQFrame::Raised );
854 label->setLineWidth( 1 );
855 label->setAlignment( AlignCenter );
856
857 mDayLabels.insert( i, label );
858
859 dayLayout->addWidget( label, 1, i );
860 dayLayout->addColSpacing( i, 10 );
861 dayLayout->setColStretch( i, 1 );
862 }
863
864 int row, col;
865
866 mCells.resize( mNumCells );
867 for( row = 0; row < mNumWeeks; ++row ) {
868 for( col = 0; col < mDaysPerWeek; ++col ) {
869 MonthViewCell *cell = new MonthViewCell( this );
870 mCells.insert( row * mDaysPerWeek + col, cell );
871 dayLayout->addWidget( cell, row + 2, col );
872
873 connect( cell, TQ_SIGNAL(defaultAction(Incidence *)),
874 TQ_SLOT(defaultAction(Incidence *)) );
875 connect( cell, TQ_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &,const TQDate &)),
876 TQ_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &,const TQDate &)) );
877 }
878 dayLayout->setRowStretch( row + 2, 1 );
879 }
880
881 mEventContextMenu = eventPopup();
882
883 updateConfig();
884
885 emit incidenceSelected( 0, TQDate() );
886}
887
888KOMonthView::~KOMonthView()
889{
890 delete mEventContextMenu;
891}
892
894{
895 return mNumCells;
896}
897
899{
900 return mNumCells;
901}
902
904{
905 Incidence::List selected;
906
907 if ( mSelectedCell ) {
908 Incidence *incidence = mSelectedCell->selectedIncidence();
909 if ( incidence ) selected.append( incidence );
910 }
911
912 return selected;
913}
914
916{
917 DateList selected;
918
919 if ( mSelectedCell ) {
920 TQDate qd = mSelectedCell->selectedIncidenceDate();
921 if ( qd.isValid() ) selected.append( qd );
922 }
923
924 return selected;
925}
926
927bool KOMonthView::eventDurationHint( TQDateTime &startDt, TQDateTime &endDt, bool &allDay )
928{
929 if ( mSelectedCell ) {
930 startDt.setDate( mSelectedCell->date() );
931 endDt.setDate( mSelectedCell->date() );
932 allDay = true;
933 return true;
934 }
935 return false;
936}
937
938void KOMonthView::updateConfig()
939{
940 mWeekStartDay = TDEGlobal::locale()->weekStartDay();
941
942 TQFontMetrics fontmetric( mDayLabels[0]->font() );
943 mWidthLongDayLabel = 0;
944
945 for ( int i = 0; i < 7; ++i ) {
946 int width =
947 fontmetric.width( KOGlobals::self()->calendarSystem()->weekDayName( i + 1 ) );
948 if ( width > mWidthLongDayLabel ) mWidthLongDayLabel = width;
949 }
950
951 updateDayLabels();
952
953 for ( uint i = 0; i < mCells.count(); ++i ) {
954 mCells[i]->updateConfig();
955 }
956
957 showLabel( !KOPrefs::instance()->fullViewMonth() );
958}
959
960void KOMonthView::updateDayLabels()
961{
962 kdDebug(5850) << "KOMonthView::updateDayLabels()" << endl;
963
964 const KCalendarSystem*calsys=KOGlobals::self()->calendarSystem();
965 int currDay;
966 for ( int i = 0; i < 7; i++ ) {
967 currDay = i+mWeekStartDay;
968 if ( currDay > 7 ) currDay -= 7;
969 mDayLabels[i]->setText( calsys->weekDayName( currDay, mShortDayLabels ) );
970 }
971}
972
973void KOMonthView::showDates( const TQDate &start, const TQDate & )
974{
975// kdDebug(5850) << "KOMonthView::showDates(): " << start.toString() << endl;
976
977 const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
978
979 mDateToCell.clear();
980
981 // show first day of month on top for readability issues
982 mStartDate = start.addDays( -start.day() + 1 );
983 // correct begin of week
984 int weekdayCol=( mStartDate.dayOfWeek() + 7 - mWeekStartDay ) % 7;
985 mStartDate = mStartDate.addDays( -weekdayCol );
986
987 mLabel->setText( i18n( "monthname year", "%1 %2" )
988 .arg( calSys->monthName( start ) )
989 .arg( calSys->year( start ) ) );
990
991 showLabel( !KOPrefs::instance()->fullViewMonth() );
992
993 bool primary = false;
994 uint i;
995 for( i = 0; i < mCells.size(); ++i ) {
996 TQDate date = mStartDate.addDays( i );
997 if ( calSys->day( date ) == 1 ) {
998 primary = !primary;
999 }
1000
1001 mCells[i]->setDate( date );
1002 mDateToCell[ date ] = mCells[ i ];
1003 if( date == start ) {
1004 mCells[i]->select();
1005 }
1006
1007 mCells[i]->setPrimary( primary );
1008
1009 bool isHoliday = calSys->dayOfWeek( date ) == calSys->weekDayOfPray()
1010 || !KOGlobals::self()->isWorkDay( date );
1011 mCells[i]->setHoliday( isHoliday );
1012
1013 // add holiday, if present
1014 TQStringList holidays( KOGlobals::self()->holiday( date ) );
1015 mCells[i]->setHolidayString( holidays.join( i18n("delimiter for joining holiday names", ", " ) ) );
1016 }
1017
1018 updateView();
1019}
1020
1022{
1023 if ( mSelectedCell) {
1024 return TQDateTime( mSelectedCell->date() );
1025 } else {
1026 return TQDateTime();
1027 }
1028}
1029
1031{
1032 // Only one cell can be selected (for now)
1033 return selectionStart();
1034}
1035
1036void KOMonthView::showIncidences( const Incidence::List &, const TQDate & )
1037{
1038 kdDebug(5850) << "KOMonthView::showIncidences( const Incidence::List & ) is not implemented yet." << endl;
1039}
1040
1041class KOMonthView::GetDateVisitor : public IncidenceBase::Visitor
1042{
1043 public:
1044 GetDateVisitor() {}
1045
1046 bool act( IncidenceBase *incidence )
1047 {
1048 return incidence->accept( *this );
1049 }
1050 TQDateTime startDate() const { return mStartDate; }
1051 TQDateTime endDate() const { return mEndDate; }
1052
1053 protected:
1054 bool visit( Event *event ) {
1055 mStartDate = event->dtStart();
1056 mEndDate = event->dtEnd();
1057 return true;
1058 }
1059 bool visit( Todo *todo ) {
1060 if ( todo->hasDueDate() ) {
1061 if ( todo->dtDue().time() != TQTime( 0, 0 ) &&
1062 todo->dtDue().time().isValid() ) {
1063 mStartDate = todo->dtDue();
1064 mEndDate = todo->dtDue();
1065 } else {
1066 mStartDate = TQDateTime( todo->dtDue().date(), TQTime( 23,59 ) );
1067 mEndDate = mStartDate;
1068 }
1069 }// else
1070// return false;
1071 return true;
1072 }
1073 bool visit( Journal *journal ) {
1074 mStartDate = journal->dtStart();
1075 mEndDate = journal->dtStart();
1076 return true;
1077 }
1078 protected:
1079 TQDateTime mStartDate;
1080 TQDateTime mEndDate;
1081};
1082
1083void KOMonthView::changeIncidenceDisplayAdded( Incidence *incidence, MonthViewCell::CreateItemVisitor& v)
1084{
1085 GetDateVisitor gdv;
1086
1087 if ( !gdv.act( incidence ) ) {
1088 kdDebug(5850) << "Visiting GetDateVisitor failed." << endl;
1089 return;
1090 }
1091
1092 bool floats = incidence->doesFloat();
1093
1094 if ( incidence->doesRecur() ) {
1095 for ( uint i = 0; i < mCells.count(); ++i ) {
1096 if ( incidence->recursOn( mCells[i]->date(), calendar() ) ) {
1097
1098 // handle multiday events
1099 int length = gdv.startDate().daysTo( TQDateTime(gdv.endDate().addSecs( floats ? 0 : -1 ).date()) );
1100 for ( int j = 0; j <= length && i+j < mCells.count(); ++j ) {
1101 mCells[i+j]->addIncidence( incidence, v, j );
1102 }
1103 }
1104 }
1105 } else {
1106 // addSecs(-1) is added to handle 0:00 cases (because it's non-inclusive according to rfc)
1107 if ( gdv.endDate().isValid() ) {
1108 TQDate endDate = gdv.endDate().addSecs( floats ? 0 : -1).date();
1109 for ( TQDate date = gdv.startDate().date();
1110 date <= endDate; date = date.addDays( 1 ) ) {
1111 MonthViewCell *mvc = mDateToCell[ date ];
1112 if ( mvc ) mvc->addIncidence( incidence, v );
1113 }
1114 }
1115 }
1116}
1117
1118void KOMonthView::changeIncidenceDisplay( Incidence *incidence, int action )
1119{
1120 MonthViewCell::CreateItemVisitor v;
1121 switch ( action ) {
1122 case KOGlobals::INCIDENCEADDED:
1123 changeIncidenceDisplayAdded( incidence, v );
1124 break;
1125 case KOGlobals::INCIDENCEEDITED:
1126 for( uint i = 0; i < mCells.count(); i++ )
1127 mCells[i]->removeIncidence( incidence );
1128 changeIncidenceDisplayAdded( incidence, v );
1129 break;
1130 case KOGlobals::INCIDENCEDELETED:
1131 for( uint i = 0; i < mCells.count(); i++ )
1132 mCells[i]->removeIncidence( incidence );
1133 break;
1134 default:
1135 return;
1136 }
1137}
1138
1139void KOMonthView::updateView()
1140{
1141 for( uint i = 0; i < mCells.count(); ++i ) {
1142 mCells[i]->updateCell();
1143 }
1144
1145 Incidence::List incidences = calendar()->incidences();
1146 Incidence::List::ConstIterator it;
1147
1148 MonthViewCell::CreateItemVisitor v;
1149 for ( it = incidences.begin(); it != incidences.end(); ++it )
1150 changeIncidenceDisplayAdded( *it, v );
1151
1152 processSelectionChange();
1153}
1154
1155void KOMonthView::resizeEvent( TQResizeEvent * )
1156{
1157 // select the appropriate heading string size. E.g. "Wednesday" or "Wed".
1158 // note this only changes the text if the requested size crosses the
1159 // threshold between big enough to support the full name and not big
1160 // enough.
1161 if( mDayLabels[0]->width() < mWidthLongDayLabel ) {
1162 if ( !mShortDayLabels ) {
1163 mShortDayLabels = true;
1164 updateDayLabels();
1165 }
1166 } else {
1167 if ( mShortDayLabels ) {
1168 mShortDayLabels = false;
1169 updateDayLabels();
1170 }
1171 }
1172}
1173
1174void KOMonthView::showEventContextMenu( Calendar *cal, Incidence *incidence, const TQDate &qd )
1175{
1176 mEventContextMenu->showIncidencePopup( cal, incidence, qd );
1177}
1178
1179void KOMonthView::showGeneralContextMenu()
1180{
1181 showNewEventPopup();
1182}
1183
1184void KOMonthView::setSelectedCell( MonthViewCell *cell )
1185{
1186 if ( mSelectedCell && cell != mSelectedCell )
1187 mSelectedCell->deselect();
1188
1189 mSelectedCell = cell;
1190
1191 if ( !mSelectedCell )
1192 emit incidenceSelected( 0, TQDate() );
1193 else
1194 if ( selectedIncidenceDates().isEmpty() ) {
1195 emit incidenceSelected( mSelectedCell->selectedIncidence(), TQDate() );
1196 } else {
1197 emit incidenceSelected( mSelectedCell->selectedIncidence(), selectedIncidenceDates().first() );
1198 }
1199}
1200
1201void KOMonthView::processSelectionChange()
1202{
1203 Incidence::List incidences = selectedIncidences();
1204 if (incidences.count() > 0) {
1205 if ( selectedIncidenceDates().isEmpty() ) {
1206 emit incidenceSelected( incidences.first(), TQDate() );
1207 } else {
1208 emit incidenceSelected( incidences.first(), selectedIncidenceDates().first() );
1209 }
1210 } else {
1211 emit incidenceSelected( 0, TQDate() );
1212 }
1213}
1214
1215void KOMonthView::clearSelection()
1216{
1217 if ( mSelectedCell ) {
1218 mSelectedCell->deselect();
1219 mSelectedCell = 0;
1220 }
1221}
1222
1223void KOMonthView::showLabel( bool show )
1224{
1225 if ( show ) {
1226 mLabel->show();
1227 } else {
1228 mLabel->hide();
1229 }
1230}
bool RSVP() const
PartStat status() const
virtual Incidence::List incidences()
bool isMultiDay() const
virtual bool visit(Event *)
bool doesFloat() const
TQString uid() const
virtual TQDateTime dtStart() const
virtual bool accept(Visitor &)
TQStringList categories() const
bool doesRecur() const
bool isAlarmEnabled() const
TQString summary() const
virtual bool recursOn(const TQDate &qd) const
bool hasDueDate() const
bool isCompleted() const
TQDateTime dtDue(bool first=false) const
KOEventView is the abstract base class from which all other calendar views for event data are derived...
Definition koeventview.h:56
void defaultAction(Incidence *)
Perform the default action for an incidence, e.g.
The class KOMonthView represents the monthly view in KOrganizer.
virtual bool eventDurationHint(TQDateTime &startDt, TQDateTime &endDt, bool &allDay)
Set the default start/end date/time for new events.
virtual DateList selectedIncidenceDates()
Returns dates of the currently selected events.
virtual TQDateTime selectionEnd()
Returns the end of the selection, or an invalid TQDateTime if there is no selection or the view doesn...
virtual int currentDateCount()
Returns number of currently shown dates.
virtual Incidence::List selectedIncidences()
Returns the currently selected events.
virtual int maxDatesHint()
Returns maximum number of days supported by the komonthview.
virtual TQDateTime selectionStart()
Returns the start of the selection, or an invalid TQDateTime if there is no selection or the view doe...
virtual Calendar * calendar()
Return calendar object of this view.
Definition baseview.h:89
This class represents one day in KOrganizer's month view.
void setPrimary(bool primary)
Set this cell as primary if primary is true.
void removeIncidence(Incidence *)
Removes an incidence from the cell.
void setHolidayString(const TQString &name)
Sets the holiday name to this cell.
KOMonthView * monthView()
void addIncidence(Incidence *incidence, MonthViewCell::CreateItemVisitor &v, int multiDay=0)
Adds an incidence to the cell.
void setHoliday(bool)
Make this cell show as a holiday.
TQDate date() const
bool isPrimary() const
void newEventSignal(ResourceCalendar *res, const TQString &subResource, const TQDate &date)
Notify the view manager that we want to create a new event, so an editor will pop up.
void setDate(const TQDate &)
Sets the date of the cell.