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