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