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 
64 KOMonthCellToolTip::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 
73 void 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 
90 KNoScrollListBox::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 
100 void 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 
118 void 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 
156 void 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 
167 void KNoScrollListBox::mousePressEvent( TQMouseEvent *e )
168 {
169  TQListBox::mousePressEvent( e );
170 
171  if ( e->button() == TQt::RightButton ) {
172  emit rightClick();
173  }
174 }
175 
176 void 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 
185 void 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 
195 MonthViewItem::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 
220 TQColor 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 
240 void 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 
358 int 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 
364 int 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 
381 MonthViewCell::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 
417 void 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 
446 TQDate MonthViewCell::date() const
447 {
448  return mDate;
449 }
450 
451 void 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 
461 void 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 
479 void MonthViewCell::setHoliday( bool holiday )
480 {
481  mHoliday = holiday;
482 
483  if ( holiday ) {
484  setPalette( mHolidayPalette );
485  } else {
486  setPalette( mStandardPalette );
487  }
488 }
489 
490 void MonthViewCell::setHolidayString( const TQString &holiday )
491 {
492  mHolidayString = holiday;
493 }
494 
495 void 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 
526 class 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 
630 void 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 
675 void 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 
712 void 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 
723 Incidence *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 
736 TQDate 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 
750 void 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 
768 void 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 
779 void MonthViewCell::resizeEvent ( TQResizeEvent * )
780 {
781  mLabel->move( width() - mLabel->width(), height() - mLabel->height() );
782 }
783 
784 void 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 
797 void 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 
813 KOMonthView::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 
879 KOMonthView::~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 
918 bool 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 
929 void 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 
951 void 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 
964 void 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 
1027 void KOMonthView::showIncidences( const Incidence::List &, const TQDate & )
1028 {
1029  kdDebug(5850) << "KOMonthView::showIncidences( const Incidence::List & ) is not implemented yet." << endl;
1030 }
1031 
1032 class 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 
1074 void 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 
1109 void 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 
1130 void 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 
1146 void 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 
1165 void KOMonthView::showEventContextMenu( Calendar *cal, Incidence *incidence, const TQDate &qd )
1166 {
1167  mEventContextMenu->showIncidencePopup( cal, incidence, qd );
1168 }
1169 
1170 void KOMonthView::showGeneralContextMenu()
1171 {
1172  showNewEventPopup();
1173 }
1174 
1175 void 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 
1192 void 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 
1206 void KOMonthView::clearSelection()
1207 {
1208  if ( mSelectedCell ) {
1209  mSelectedCell->deselect();
1210  mSelectedCell = 0;
1211  }
1212 }
1213 
1214 void 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.
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.
KOMonthView * monthView()
Definition: komonthview.h:149
void setDate(const TQDate &)
Sets the date of the cell.