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