korganizer

kolistview.cpp

00001 /*
00002     This file is part of KOrganizer.
00003 
00004     Copyright (c) 1999 Preston Brown <pbrown@kde.org>
00005     Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org>
00006     Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00021 
00022     As a special exception, permission is given to link this program
00023     with any edition of TQt, and distribute the resulting executable,
00024     without including the source code for TQt in the source distribution.
00025 */
00026 
00027 #include <tqlistview.h>
00028 #include <tqlayout.h>
00029 #include <tqpopupmenu.h>
00030 #include <tqcursor.h>
00031 #include <tqstyle.h>
00032 
00033 #include <tdelocale.h>
00034 #include <kdebug.h>
00035 #include <kiconloader.h>
00036 #include <tdeglobal.h>
00037 
00038 #include <libkcal/calendar.h>
00039 #include <libkcal/incidenceformatter.h>
00040 
00041 #include "koglobals.h"
00042 #include "koprefs.h"
00043 #include "koincidencetooltip.h"
00044 #include "koeventpopupmenu.h"
00045 
00046 #include "kolistview.h"
00047 #include "kolistview.moc"
00048 
00049 enum {
00050   Summary_Column = 0,
00051   Reminder_Column,
00052   Recurs_Column,
00053   StartDateTime_Column,
00054   EndDateTime_Column,
00055   Categories_Column
00056 };
00057 
00058 
00059 KOListViewToolTip::KOListViewToolTip( TQWidget* parent,
00060                                       Calendar *calendar,
00061                                       TDEListView *lv )
00062   :TQToolTip( parent ), mCalendar( calendar )
00063 {
00064   eventlist = lv;
00065 }
00066 
00067 void KOListViewToolTip::maybeTip( const TQPoint &pos )
00068 {
00069   TQRect r;
00070   TQListViewItem *it = eventlist->itemAt( pos );
00071   KOListViewItem *i = static_cast<KOListViewItem*>( it );
00072 
00073   if ( i && KOPrefs::instance()->mEnableToolTips ) {
00074     /* Calculate the rectangle. */
00075     r = eventlist->itemRect( it );
00076     /* Show the tip */
00077     TQString tipText( IncidenceFormatter::toolTipStr( mCalendar, i->data() ) );
00078     if ( !tipText.isEmpty() ) {
00079       tip( r, tipText );
00080     }
00081   }
00082 }
00083 
00088 class KOListView::ListItemVisitor : public IncidenceBase::Visitor
00089 {
00090   public:
00091     ListItemVisitor( KOListViewItem *item ) : mItem( item ) {}
00092     ~ListItemVisitor() {}
00093 
00094     bool visit( Event * );
00095     bool visit( Todo * );
00096     bool visit( Journal * );
00097 
00098   private:
00099     KOListViewItem *mItem;
00100 };
00101 
00102 bool KOListView::ListItemVisitor::visit( Event *e )
00103 {
00104   mItem->setText( Summary_Column, e->summary() );
00105   if ( e->isAlarmEnabled() ) {
00106     static const TQPixmap alarmPxmp = KOGlobals::self()->smallIcon( "bell" );
00107     mItem->setPixmap( Reminder_Column, alarmPxmp );
00108     mItem->setSortKey( Reminder_Column, "1" );
00109   } else {
00110     mItem->setSortKey( Reminder_Column, "0" );
00111   }
00112 
00113   if ( e->doesRecur() ) {
00114     static const TQPixmap recurPxmp = KOGlobals::self()->smallIcon( "recur" );
00115     mItem->setPixmap( Recurs_Column, recurPxmp );
00116     mItem->setSortKey( Recurs_Column, "1" );
00117   } else {
00118     mItem->setSortKey( Recurs_Column, "0" );
00119   }
00120 
00121   TQPixmap eventPxmp;
00122   if ( e->customProperty( "KABC", "BIRTHDAY" ) == "YES" ) {
00123     if ( e->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) {
00124       eventPxmp = KOGlobals::self()->smallIcon( "calendaranniversary" );
00125     } else {
00126       eventPxmp = KOGlobals::self()->smallIcon( "calendarbirthday" );
00127     }
00128   } else {
00129     eventPxmp = KOGlobals::self()->smallIcon( "appointment" );
00130   }
00131 
00132   mItem->setPixmap( Summary_Column, eventPxmp );
00133 
00134   TQString startDateTime;
00135   TQString endDateTime;
00136 
00137   mItem->setText( StartDateTime_Column, IncidenceFormatter::dateTimeToString( e->dtStart(), e->doesFloat() ) );
00138   mItem->setSortKey( StartDateTime_Column, e->dtStart().toString( Qt::ISODate ) );
00139   mItem->setText( EndDateTime_Column, IncidenceFormatter::dateTimeToString( e->dtEnd(), e->doesFloat() ) );
00140   mItem->setSortKey( EndDateTime_Column, e->dtEnd().toString( Qt::ISODate ) );
00141   mItem->setText( Categories_Column, e->categoriesStr() );
00142 
00143   return true;
00144 }
00145 
00146 bool KOListView::ListItemVisitor::visit( Todo *t )
00147 {
00148   static const TQPixmap todoPxmp = KOGlobals::self()->smallIcon( "todo" );
00149   static const TQPixmap todoDonePxmp = KOGlobals::self()->smallIcon( "checkedbox" );
00150   mItem->setPixmap(Summary_Column, t->isCompleted() ? todoDonePxmp : todoPxmp );
00151   mItem->setText(Summary_Column, t->summary());
00152   if ( t->isAlarmEnabled() ) {
00153     static const TQPixmap alarmPxmp = KOGlobals::self()->smallIcon( "bell" );
00154     mItem->setPixmap( Reminder_Column, alarmPxmp );
00155     mItem->setSortKey( Reminder_Column, "1" );
00156   } else {
00157     mItem->setSortKey( Reminder_Column, "0" );
00158   }
00159 
00160   if ( t->doesRecur() ) {
00161     static const TQPixmap recurPxmp = KOGlobals::self()->smallIcon( "recur" );
00162     mItem->setPixmap( Recurs_Column, recurPxmp );
00163     mItem->setSortKey( Recurs_Column, "1" );
00164   } else {
00165     mItem->setSortKey( Recurs_Column, "0" );
00166   }
00167 
00168   if ( t->hasStartDate() ) {
00169     mItem->setText( StartDateTime_Column, IncidenceFormatter::dateTimeToString( t->dtStart(), t->doesFloat() ) );
00170     mItem->setSortKey( StartDateTime_Column, t->dtStart().toString( Qt::ISODate ) );
00171   } else {
00172     mItem->setText( StartDateTime_Column, "---" );
00173   }
00174 
00175   if ( t->hasDueDate() ) {
00176     mItem->setText( EndDateTime_Column, IncidenceFormatter::dateTimeToString( t->dtDue(), t->doesFloat() ) );
00177     mItem->setSortKey( EndDateTime_Column, t->dtDue().toString( Qt::ISODate ) );
00178   } else {
00179     mItem->setText( EndDateTime_Column, "---" );
00180   }
00181   mItem->setText( Categories_Column, t->categoriesStr() );
00182 
00183   return true;
00184 }
00185 
00186 bool KOListView::ListItemVisitor::visit( Journal *j )
00187 {
00188   static const TQPixmap jornalPxmp = KOGlobals::self()->smallIcon( "journal" );
00189   mItem->setPixmap( Summary_Column, jornalPxmp );
00190   // Just use the first line
00191   mItem->setText( Summary_Column, j->description().section( "\n", 0, 0 ) );
00192   mItem->setText( StartDateTime_Column, IncidenceFormatter::dateTimeToString( j->dtStart(), j->doesFloat() ) );
00193   mItem->setSortKey( StartDateTime_Column, j->dtStart().toString( Qt::ISODate ) );
00194 
00195   return true;
00196 }
00197 
00198 KOListView::KOListView( Calendar *calendar,
00199                         TQWidget *parent,
00200                         const char *name,
00201                         bool nonInteractive )
00202   : KOEventView( calendar, parent, name )
00203 {
00204   mActiveItem = 0;
00205   mIsNonInteractive = nonInteractive;
00206 
00207   mListView = new TDEListView( this );
00208   mListView->addColumn( i18n("Summary") );
00209   mListView->addColumn( i18n("Reminder") ); // alarm set?
00210   mListView->setColumnAlignment( Reminder_Column, AlignHCenter );
00211 
00212   mListView->addColumn( i18n("Recurs") ); // recurs?
00213   mListView->setColumnAlignment( Recurs_Column, AlignHCenter );
00214 
00215   mListView->addColumn( i18n("Start Date/Time") );
00216   mListView->setColumnAlignment( StartDateTime_Column, AlignHCenter );
00217 
00218   mListView->addColumn( i18n("End Date/Time") );
00219   mListView->setColumnAlignment( EndDateTime_Column, AlignHCenter );
00220 
00221   mListView->addColumn( i18n("Categories") );
00222 
00223   TQBoxLayout *layoutTop = new TQVBoxLayout( this );
00224   layoutTop->addWidget( mListView );
00225 
00226   mPopupMenu = eventPopup();
00227 /*
00228   mPopupMenu->insertSeparator();
00229   mPopupMenu->insertItem(i18n("Show Dates"), this,
00230                       TQT_SLOT(showDates()));
00231   mPopupMenu->insertItem(i18n("Hide Dates"), this,
00232                       TQT_SLOT(hideDates()));
00233 */
00234 
00235   connect( mListView, TQT_SIGNAL( doubleClicked( TQListViewItem * ) ),
00236                     TQT_SLOT( defaultItemAction( TQListViewItem * ) ) );
00237   connect( mListView, TQT_SIGNAL( returnPressed( TQListViewItem * ) ),
00238                     TQT_SLOT( defaultItemAction( TQListViewItem * ) ) );
00239   connect( mListView, TQT_SIGNAL( rightButtonClicked ( TQListViewItem *,
00240                                                             const TQPoint &,
00241                                                             int ) ),
00242                     TQT_SLOT( popupMenu( TQListViewItem *, const TQPoint &, int ) ) );
00243   connect( mListView, TQT_SIGNAL( selectionChanged() ),
00244                     TQT_SLOT( processSelectionChange() ) );
00245 
00246 //  setMinimumSize(100,100);
00247   mListView->restoreLayout( KOGlobals::self()->config(), "KOListView Layout" );
00248 
00249   new KOListViewToolTip( mListView->viewport(), calendar, mListView );
00250 
00251   mSelectedDates.append( TQDate::currentDate() );
00252 }
00253 
00254 KOListView::~KOListView()
00255 {
00256   delete mPopupMenu;
00257 }
00258 
00259 int KOListView::maxDatesHint()
00260 {
00261   return 0;
00262 }
00263 
00264 int KOListView::currentDateCount()
00265 {
00266   return mSelectedDates.count();
00267 }
00268 
00269 Incidence::List KOListView::selectedIncidences()
00270 {
00271   Incidence::List eventList;
00272 
00273   TQListViewItem *item = mListView->selectedItem();
00274   if ( item ) {
00275     eventList.append( static_cast<KOListViewItem *>( item )->data() );
00276   }
00277 
00278   return eventList;
00279 }
00280 
00281 DateList KOListView::selectedIncidenceDates()
00282 {
00283   return mSelectedDates;
00284 }
00285 
00286 void KOListView::showDates( bool show )
00287 {
00288   // Shouldn't we set it to a value greater 0? When showDates is called with
00289   // show == true at first, then the columnwidths are set to zero.
00290   static int oldColWidth1 = 0;
00291   static int oldColWidth3 = 0;
00292 
00293   if ( !show ) {
00294     oldColWidth1 = mListView->columnWidth( 1 );
00295     oldColWidth3 = mListView->columnWidth( 3 );
00296     mListView->setColumnWidth( 1, 0 );
00297     mListView->setColumnWidth( 3, 0 );
00298   } else {
00299     mListView->setColumnWidth( 1, oldColWidth1 );
00300     mListView->setColumnWidth( 3, oldColWidth3 );
00301   }
00302   mListView->repaint();
00303 }
00304 
00305 void KOListView::showDates()
00306 {
00307   showDates( true );
00308 }
00309 
00310 void KOListView::hideDates()
00311 {
00312   showDates( false );
00313 }
00314 
00315 void KOListView::updateView()
00316 {
00317   kdDebug(5850) << "KOListView::updateView() does nothing" << endl;
00318 }
00319 
00320 void KOListView::showDates( const TQDate &start, const TQDate &end )
00321 {
00322   clear();
00323 
00324   TQDate date = start;
00325   while( date <= end ) {
00326     addIncidences( calendar()->incidences( date ), date );
00327     mSelectedDates.append( date );
00328     date = date.addDays( 1 );
00329   }
00330 
00331   emit incidenceSelected( 0, TQDate() );
00332 }
00333 
00334 void KOListView::showAll()
00335 {
00336   Incidence::List incidenceList = calendar()->incidences();
00337 
00338   Incidence::List::ConstIterator it;
00339   for( it = incidenceList.begin(); it != incidenceList.end(); ++it ) {
00340     // we don't need the date, using showAll in non interactive mode for now
00341     addIncidence( *it, TQDate() );
00342   }
00343 }
00344 
00345 void KOListView::addIncidences( const Incidence::List &incidenceList, const TQDate &date )
00346 {
00347   Incidence::List::ConstIterator it;
00348   for( it = incidenceList.begin(); it != incidenceList.end(); ++it ) {
00349     addIncidence( *it, date );
00350   }
00351 }
00352 
00353 void KOListView::addIncidence( Incidence *incidence, const TQDate &date )
00354 {
00355   if ( mUidDict.find( incidence->uid() ) ) {
00356     return;
00357   }
00358 
00359   mDateList[incidence->uid()] = date;
00360   mUidDict.insert( incidence->uid(), incidence );
00361 
00362   KOListViewItem *item = new KOListViewItem( incidence, mListView );
00363   ListItemVisitor v( item );
00364   if (incidence->accept( v ) ) {
00365     return;
00366   } else {
00367     delete item;
00368   }
00369 }
00370 
00371 void KOListView::showIncidences( const Incidence::List &incidenceList, const TQDate &date )
00372 {
00373   clear();
00374 
00375   addIncidences( incidenceList, date );
00376 
00377   // After new creation of list view no events are selected.
00378   emit incidenceSelected( 0, date );
00379 }
00380 
00381 void KOListView::changeIncidenceDisplay( Incidence *incidence, int action )
00382 {
00383   KOListViewItem *item;
00384   TQDate f = mSelectedDates.first();
00385   TQDate l = mSelectedDates.last();
00386 
00387   TQDate date;
00388   if ( incidence->type() == "Todo" ) {
00389     date = static_cast<Todo *>( incidence )->dtDue().date();
00390   } else {
00391     date = incidence->dtStart().date();
00392   }
00393 
00394   switch( action ) {
00395     case KOGlobals::INCIDENCEADDED: {
00396       if ( date >= f && date <= l )
00397         addIncidence( incidence, date );
00398       break;
00399     }
00400     case KOGlobals::INCIDENCEEDITED: {
00401       item = getItemForIncidence( incidence );
00402       if ( item ) {
00403         delete item;
00404         mUidDict.remove( incidence->uid() );
00405         mDateList.remove( incidence->uid() );
00406       }
00407       if ( date >= f && date <= l ) {
00408         addIncidence( incidence, date );
00409       }
00410     }
00411     break;
00412     case KOGlobals::INCIDENCEDELETED: {
00413       item = getItemForIncidence( incidence );
00414       if ( item ) {
00415         delete item;
00416       }
00417       break;
00418     }
00419     default:
00420       kdDebug(5850) << "KOListView::changeIncidenceDisplay(): Illegal action " << action << endl;
00421   }
00422 }
00423 
00424 KOListViewItem *KOListView::getItemForIncidence( Incidence *incidence )
00425 {
00426   KOListViewItem *item = static_cast<KOListViewItem *>( mListView->firstChild() );
00427   while ( item ) {
00428 //    kdDebug(5850) << "Item " << item->text(0) << " found" << endl;
00429     if ( item->data() == incidence ) {
00430       return item;
00431     }
00432     item = static_cast<KOListViewItem *>( item->nextSibling() );
00433   }
00434   return 0;
00435 }
00436 
00437 void KOListView::defaultItemAction( TQListViewItem *i )
00438 {
00439   if ( !mIsNonInteractive ) {
00440     KOListViewItem *item = static_cast<KOListViewItem *>( i );
00441     if ( item ) {
00442       defaultAction( item->data() );
00443     }
00444   }
00445 }
00446 
00447 void KOListView::popupMenu( TQListViewItem *item,const TQPoint &, int )
00448 {
00449   if ( !mIsNonInteractive ) {
00450     mActiveItem = static_cast<KOListViewItem *>( item );
00451     if ( mActiveItem ) {
00452       Incidence *incidence = mActiveItem->data();
00453       // FIXME: For recurring incidences we don't know the date of this
00454       // occurrence, there's no reference to it at all!
00455       mPopupMenu->showIncidencePopup( calendar(), incidence, TQDate() );
00456     } else {
00457       showNewEventPopup();
00458     }
00459   }
00460 }
00461 
00462 void KOListView::readSettings( TDEConfig *config )
00463 {
00464   mListView->restoreLayout( config,"KOListView Layout" );
00465 }
00466 
00467 void KOListView::writeSettings( TDEConfig *config )
00468 {
00469   mListView->saveLayout( config, "KOListView Layout" );
00470 }
00471 
00472 void KOListView::processSelectionChange()
00473 {
00474   if ( !mIsNonInteractive ) {
00475     kdDebug(5850) << "KOListView::processSelectionChange()" << endl;
00476 
00477     KOListViewItem *item =
00478       static_cast<KOListViewItem *>( mListView->selectedItem() );
00479 
00480     if ( !item ) {
00481       emit incidenceSelected( 0, TQDate() );
00482     } else {
00483       Incidence *incidence = static_cast<Incidence *>( item->data() );
00484       emit incidenceSelected( incidence, mDateList[incidence->uid()] );
00485     }
00486   }
00487 }
00488 
00489 void KOListView::clearSelection()
00490 {
00491   mListView->selectAll( false );
00492 }
00493 
00494 void KOListView::clear()
00495 {
00496   mSelectedDates.clear();
00497   mListView->clear();
00498   mUidDict.clear();
00499   mDateList.clear();
00500 }
00501 
00502 TQSize KOListView::sizeHint() const
00503 {
00504   const TQSize s = KOEventView::sizeHint();
00505   return TQSize( s.width() + style().pixelMetric( TQStyle::PM_ScrollBarExtent ) + 1,
00506                 s.height() );
00507 }