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