korganizer Library API Documentation

kotodoview.cpp

00001 /*
00002     This file is part of KOrganizer.
00003 
00004     Copyright (c) 2000,2001,2003 Cornelius Schumacher <schumacher@kde.org>
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00019 
00020     As a special exception, permission is given to link this program
00021     with any edition of Qt, and distribute the resulting executable,
00022     without including the source code for Qt in the source distribution.
00023 */
00024 
00025 #include <qlayout.h>
00026 #include <qheader.h>
00027 #include <qcursor.h>
00028 #include <qlabel.h>
00029 #include <qtimer.h>
00030 
00031 #include <kdebug.h>
00032 #include <klocale.h>
00033 #include <kglobal.h>
00034 #include <kiconloader.h>
00035 #include <kmessagebox.h>
00036 
00037 #include <libkcal/icaldrag.h>
00038 #include <libkcal/vcaldrag.h>
00039 #include <libkcal/dndfactory.h>
00040 #include <libkcal/calendarresources.h>
00041 #include <libkcal/resourcecalendar.h>
00042 #include <libkcal/calfilter.h>
00043 
00044 #include <libkdepim/clicklineedit.h>
00045 #include <libkdepim/kdatepickerpopup.h>
00046 
00047 #ifndef KORG_NOPRINTER
00048 #include "calprinter.h"
00049 #endif
00050 #include "docprefs.h"
00051 
00052 #include "koincidencetooltip.h"
00053 #include "kodialogmanager.h"
00054 #include "kotodoview.h"
00055 #include "koprefs.h"
00056 #include "koglobals.h"
00057 using namespace KOrg;
00058 #include "kohelper.h"
00059 #include "kotodoviewitem.h"
00060 #include "kotodoview.moc"
00061 
00062 const int KOTodoView::POPUP_UNSUBTODO=1234;
00063 
00064 KOTodoListViewToolTip::KOTodoListViewToolTip (QWidget* parent,
00065                                               KOTodoListView* lv )
00066   :QToolTip(parent)
00067 {
00068   todolist=lv;
00069 }
00070 
00071 void KOTodoListViewToolTip::maybeTip( const QPoint & pos)
00072 {
00073   QRect r;
00074   int headerPos;
00075   int col=todolist->header()->sectionAt(todolist->contentsX() + pos.x());
00076   KOTodoViewItem *i=(KOTodoViewItem *)todolist->itemAt(pos);
00077 
00078   /* Check wether a tooltip is necessary. */
00079   if( i && KOPrefs::instance()->mEnableToolTips )
00080   {
00081 
00082     /* Calculate the rectangle. */
00083     r=todolist->itemRect(i);
00084     headerPos = todolist->header()->sectionPos(col)-todolist->contentsX();
00085     r.setLeft( (headerPos < 0 ? 0 : headerPos) );
00086     r.setRight(headerPos + todolist->header()->sectionSize(col));
00087 
00088     /* Show the tip */
00089     QString tipText;
00090     ToolTipVisitor<KOTodoViewItem> v;
00091     if (v.act(i, &tipText, true)) {
00092       tip(r, tipText);
00093     }
00094   }
00095 
00096 }
00097 
00098 
00099 
00100 KOTodoListView::KOTodoListView( QWidget *parent, const char *name )
00101   : KListView( parent, name ), mCalendar( 0 )
00102 {
00103   mOldCurrent = 0;
00104   mMousePressed = false;
00105 
00106   /* Create a Tooltip */
00107   tooltip = new KOTodoListViewToolTip( viewport(), this );
00108 }
00109 
00110 KOTodoListView::~KOTodoListView()
00111 {
00112   delete tooltip;
00113 }
00114 
00115 void KOTodoListView::setCalendar( Calendar *cal )
00116 {
00117   mCalendar = cal;
00118   setAcceptDrops( mCalendar );
00119   viewport()->setAcceptDrops( mCalendar );
00120 }
00121 
00122 bool KOTodoListView::event(QEvent *e)
00123 {
00124   int tmp=0;
00125   KOTodoViewItem *i;
00126 
00127   /* Checks for an ApplicationPaletteChange event and updates
00128    * the small Progress bars to make therm have the right colors. */
00129   if(e->type()==QEvent::ApplicationPaletteChange)
00130   {
00131 
00132     KListView::event(e);
00133     i=(KOTodoViewItem *)itemAtIndex(tmp);
00134 
00135     while(i!=0)
00136     {
00137       i->construct();
00138       tmp++;
00139       i=(KOTodoViewItem *)itemAtIndex(tmp);
00140     }
00141 
00142   }
00143 
00144   return (KListView::event(e) || e->type()==QEvent::ApplicationPaletteChange);
00145 }
00146 
00147 void KOTodoListView::contentsDragEnterEvent(QDragEnterEvent *e)
00148 {
00149 #ifndef KORG_NODND
00150 //  kdDebug(5850) << "KOTodoListView::contentsDragEnterEvent" << endl;
00151   if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) &&
00152        !QTextDrag::canDecode( e ) ) {
00153     e->ignore();
00154     return;
00155   }
00156 
00157   mOldCurrent = currentItem();
00158 #endif
00159 }
00160 
00161 
00162 void KOTodoListView::contentsDragMoveEvent(QDragMoveEvent *e)
00163 {
00164 #ifndef KORG_NODND
00165 //  kdDebug(5850) << "KOTodoListView::contentsDragMoveEvent" << endl;
00166 
00167   if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) &&
00168        !QTextDrag::canDecode( e ) ) {
00169     e->ignore();
00170     return;
00171   }
00172 
00173   e->accept();
00174 #endif
00175 }
00176 
00177 void KOTodoListView::contentsDragLeaveEvent( QDragLeaveEvent * )
00178 {
00179 #ifndef KORG_NODND
00180 //  kdDebug(5850) << "KOTodoListView::contentsDragLeaveEvent" << endl;
00181 
00182   setCurrentItem(mOldCurrent);
00183   setSelected(mOldCurrent,true);
00184 #endif
00185 }
00186 
00187 void KOTodoListView::contentsDropEvent( QDropEvent *e )
00188 {
00189 #ifndef KORG_NODND
00190 //  kdDebug(5850) << "KOTodoListView::contentsDropEvent" << endl;
00191 
00192   if ( !mCalendar ||
00193        ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) &&
00194          !QTextDrag::canDecode( e ) ) ) {
00195     e->ignore();
00196     return;
00197   }
00198 
00199   DndFactory factory( mCalendar );
00200   Todo *todo = factory.createDropTodo(e);
00201 
00202   if (todo) {
00203     e->acceptAction();
00204 
00205     KOTodoViewItem *destination =
00206         (KOTodoViewItem *)itemAt(contentsToViewport(e->pos()));
00207     Todo *destinationEvent = 0;
00208     if (destination) destinationEvent = destination->todo();
00209 
00210     Todo *existingTodo = mCalendar->todo(todo->uid());
00211 
00212     if(existingTodo) {
00213 //       kdDebug(5850) << "Drop existing Todo " << existingTodo << " onto " << destinationEvent << endl;
00214       Incidence *to = destinationEvent;
00215       while(to) {
00216         if (to->uid() == todo->uid()) {
00217           KMessageBox::sorry(this,
00218               i18n("Cannot move To-Do to itself or a child of itself."),
00219               i18n("Drop To-Do"));
00220           delete todo;
00221           return;
00222         }
00223         to = to->relatedTo();
00224       }
00225       Todo*oldTodo = existingTodo->clone();
00226       existingTodo->setRelatedTo(destinationEvent);
00227 
00228       emit incidenceChanged( oldTodo, existingTodo );
00229       delete oldTodo;
00230       delete todo;
00231     } else {
00232 //      kdDebug(5850) << "Drop new Todo" << endl;
00233       todo->setRelatedTo(destinationEvent);
00234       if ( !mCalendar->addTodo( todo ) ) {
00235         KODialogManager::errorSaveTodo( this );
00236         return;
00237       }
00238 
00239       emit incidenceAdded( todo );
00240     }
00241   }
00242   else {
00243     QString text;
00244     KOTodoViewItem *todoi = dynamic_cast<KOTodoViewItem *>(itemAt( contentsToViewport(e->pos()) ));
00245     if ( ! todoi ) {
00246       // Not dropped on a todo item:
00247       e->ignore();
00248       kdDebug( 5850 ) << "KOTodoListView::contentsDropEvent(): Not dropped on a todo item" << endl;
00249       kdDebug( 5850 ) << "TODO: Create a new todo with the given data" << endl;
00250       // TODO: Create a new todo with the given text/contact/whatever
00251     } else if ( QTextDrag::decode(e, text) ) {
00252       //QListViewItem *qlvi = itemAt( contentsToViewport(e->pos()) );
00253       kdDebug(5850) << "Dropped : " << text << endl;
00254       QStringList emails = QStringList::split(",",text);
00255       Todo*newtodo = todoi->todo();
00256       Todo*oldtodo = newtodo->clone();
00257       for(QStringList::ConstIterator it = emails.begin();it!=emails.end();++it) {
00258         kdDebug(5850) << " Email: " << (*it) << endl;
00259         int pos = (*it).find("<");
00260         QString name = (*it).left(pos);
00261         QString email = (*it).mid(pos);
00262         if (!email.isEmpty() && todoi) {
00263           newtodo->addAttendee(new Attendee(name,email));
00264         }
00265       }
00266       emit incidenceChanged( oldtodo, newtodo );
00267     }
00268     else {
00269       kdDebug(5850) << "KOTodoListView::contentsDropEvent(): Todo from drop not decodable" << endl;
00270       e->ignore();
00271     }
00272   }
00273 #endif
00274 }
00275 
00276 void KOTodoListView::contentsMousePressEvent(QMouseEvent* e)
00277 {
00278   QListView::contentsMousePressEvent(e);
00279   QPoint p(contentsToViewport(e->pos()));
00280   QListViewItem *i = itemAt(p);
00281   if (i) {
00282     // if the user clicked into the root decoration of the item, don't
00283     // try to start a drag!
00284     if (p.x() > header()->sectionPos(header()->mapToIndex(0)) +
00285         treeStepSize() * (i->depth() + (rootIsDecorated() ? 1 : 0)) +
00286         itemMargin() ||
00287         p.x() < header()->sectionPos(header()->mapToIndex(0))) {
00288       if (e->button()==Qt::LeftButton) {
00289         mPressPos = e->pos();
00290         mMousePressed = true;
00291       }
00292     }
00293   }
00294 }
00295 
00296 void KOTodoListView::contentsMouseMoveEvent(QMouseEvent* e)
00297 {
00298 #ifndef KORG_NODND
00299 //  kdDebug(5850) << "KOTodoListView::contentsMouseMoveEvent()" << endl;
00300   QListView::contentsMouseMoveEvent(e);
00301   if (mMousePressed && (mPressPos - e->pos()).manhattanLength() >
00302       QApplication::startDragDistance()) {
00303     mMousePressed = false;
00304     QListViewItem *item = itemAt(contentsToViewport(mPressPos));
00305     if ( item && mCalendar ) {
00306 //      kdDebug(5850) << "Start Drag for item " << item->text(0) << endl;
00307       DndFactory factory( mCalendar );
00308       ICalDrag *vd = factory.createDrag(
00309                           ((KOTodoViewItem *)item)->todo(),viewport());
00310       if (vd->drag()) {
00311         kdDebug(5850) << "KOTodoListView::contentsMouseMoveEvent(): Delete drag source" << endl;
00312       }
00313 /*
00314       QString source = fullPath(item);
00315       if ( QFile::exists(source) ) {
00316         KURL url;
00317         url.setPath(source);
00318         KURLDrag* ud = KURLDrag::newDrag(KURL::List(url), viewport());
00319         if ( ud->drag() )
00320           QMessageBox::information( this, "Drag source",
00321                                     QString("Delete ")+source, "Not implemented" );
00322 */
00323     }
00324   }
00325 #endif
00326 }
00327 
00328 void KOTodoListView::contentsMouseReleaseEvent(QMouseEvent *e)
00329 {
00330   QListView::contentsMouseReleaseEvent(e);
00331   mMousePressed = false;
00332 }
00333 
00334 void KOTodoListView::contentsMouseDoubleClickEvent(QMouseEvent *e)
00335 {
00336   if (!e) return;
00337 
00338   QPoint vp = contentsToViewport(e->pos());
00339 
00340   QListViewItem *item = itemAt(vp);
00341 
00342   if (!item) return;
00343 
00344   emit doubleClicked(item,vp,0);
00345 }
00346 
00348 
00349 KOTodoView::KOTodoView( Calendar *calendar, QWidget *parent, const char* name)
00350   : KOrg::BaseView( calendar, parent, name )
00351 {
00352   QBoxLayout *topLayout = new QVBoxLayout( this );
00353 
00354   QLabel *title = new QLabel( i18n("To-do items:"), this );
00355   title->setFrameStyle( QFrame::Panel | QFrame::Raised );
00356   topLayout->addWidget( title );
00357 
00358   mQuickAdd = new KPIM::ClickLineEdit( this, i18n( "Click to add a new Todo" ) );
00359   topLayout->addWidget( mQuickAdd );
00360 
00361   if ( !KOPrefs::instance()->mEnableQuickTodo ) mQuickAdd->hide();
00362 
00363   mTodoListView = new KOTodoListView( this );
00364   topLayout->addWidget( mTodoListView );
00365 
00366   mTodoListView->setRootIsDecorated( true );
00367   mTodoListView->setAllColumnsShowFocus( true );
00368 
00369   mTodoListView->setShowSortIndicator( true );
00370 
00371   mTodoListView->addColumn( i18n("Summary") );
00372   mTodoListView->addColumn( i18n("Recurs") );
00373   mTodoListView->addColumn( i18n("Priority") );
00374   mTodoListView->setColumnAlignment( 2, AlignHCenter );
00375   mTodoListView->addColumn( i18n("Complete") );
00376   mTodoListView->setColumnAlignment( 3, AlignRight );
00377   mTodoListView->addColumn( i18n("Due Date/Time") );
00378   mTodoListView->setColumnAlignment( 4, AlignLeft );
00379   mTodoListView->addColumn( i18n("Categories") );
00380 #if 0
00381   mTodoListView->addColumn( i18n("Sort Id") );
00382   mTodoListView->setColumnAlignment( 4, AlignHCenter );
00383 #endif
00384 
00385   mTodoListView->setMinimumHeight( 60 );
00386   mTodoListView->setItemsRenameable( true );
00387   mTodoListView->setRenameable( 0 );
00388 
00389   mTodoListView->setColumnWidthMode( 0, QListView::Manual );
00390   mTodoListView->setColumnWidthMode( 1, QListView::Manual );
00391   mTodoListView->setColumnWidthMode( 2, QListView::Manual );
00392   mTodoListView->setColumnWidthMode( 3, QListView::Manual );
00393   mTodoListView->setColumnWidthMode( 4, QListView::Manual );
00394   mTodoListView->setColumnWidthMode( 5, QListView::Manual );
00395 #if 0
00396   mTodoListView->setColumnWidthMode( 6, QListView::Manual );
00397 #endif
00398 
00399   mPriorityPopupMenu = new QPopupMenu( this );
00400   for ( int i = 1; i <= 5; i++ ) {
00401     QString label = QString ("%1").arg( i );
00402     mPriority[ mPriorityPopupMenu->insertItem( label ) ] = i;
00403   }
00404   connect( mPriorityPopupMenu, SIGNAL( activated( int ) ),
00405            SLOT( setNewPriority( int ) ));
00406 
00407   mPercentageCompletedPopupMenu = new QPopupMenu(this);
00408   for (int i = 0; i <= 100; i+=10) {
00409     QString label = QString ("%1 %").arg (i);
00410     mPercentage[mPercentageCompletedPopupMenu->insertItem (label)] = i;
00411   }
00412   connect( mPercentageCompletedPopupMenu, SIGNAL( activated( int ) ),
00413            SLOT( setNewPercentage( int ) ) );
00414 
00415   mMovePopupMenu = new KDatePickerPopup(
00416                              KDatePickerPopup::NoDate |
00417                              KDatePickerPopup::DatePicker |
00418                              KDatePickerPopup::Words );
00419   mCopyPopupMenu = new KDatePickerPopup(
00420                              KDatePickerPopup::NoDate |
00421                              KDatePickerPopup::DatePicker |
00422                              KDatePickerPopup::Words );
00423 
00424 
00425   connect( mMovePopupMenu, SIGNAL( dateChanged( QDate )),
00426            SLOT( setNewDate( QDate ) ) );
00427   connect( mCopyPopupMenu, SIGNAL( dateChanged( QDate )),
00428            SLOT( copyTodoToDate( QDate ) ) );
00429 
00430   mItemPopupMenu = new QPopupMenu(this);
00431   mItemPopupMenu->insertItem(i18n("Show"), this,
00432                              SLOT (showTodo()));
00433   mItemPopupMenu->insertItem(i18n("Edit..."), this,
00434                              SLOT (editTodo()));
00435   mItemPopupMenu->insertItem(KOGlobals::self()->smallIconSet("editdelete"), i18n("Delete"), this,
00436                              SLOT (deleteTodo()));
00437   mItemPopupMenu->insertSeparator();
00438   mItemPopupMenu->insertItem(KOGlobals::self()->smallIconSet("todo"), i18n("New To-Do..."), this,
00439                              SLOT (newTodo()));
00440   mItemPopupMenu->insertItem(i18n("New Sub-To-Do..."), this,
00441                              SLOT (newSubTodo()));
00442   mItemPopupMenu->insertItem( i18n("Make Sub-To-Do Independent"), this,
00443       SIGNAL( unSubTodoSignal() ), 0, POPUP_UNSUBTODO );
00444   mItemPopupMenu->insertSeparator();
00445   mItemPopupMenu->insertItem( i18n("Copy To"), mCopyPopupMenu );
00446   mItemPopupMenu->insertItem(i18n("Move To"), mMovePopupMenu);
00447   mItemPopupMenu->insertSeparator();
00448   mItemPopupMenu->insertItem(i18n("delete completed To-Dos","Purge Completed"),
00449                              this, SLOT( purgeCompleted() ) );
00450 
00451   connect( mMovePopupMenu, SIGNAL( dateChanged( QDate ) ),
00452            mItemPopupMenu, SLOT( hide() ) );
00453   connect( mCopyPopupMenu, SIGNAL( dateChanged( QDate ) ),
00454            mItemPopupMenu, SLOT( hide() ) );
00455 
00456   mPopupMenu = new QPopupMenu(this);
00457   mPopupMenu->insertItem(KOGlobals::self()->smallIconSet("todo"), i18n("New To-Do..."), this,
00458                          SLOT (newTodo()));
00459   mPopupMenu->insertItem(i18n("delete completed To-Dos","Purge Completed"),
00460                          this, SLOT(purgeCompleted()));
00461 
00462   mDocPrefs = new DocPrefs( name );
00463 
00464   // Double clicking conflicts with opening/closing the subtree
00465   connect( mTodoListView, SIGNAL( doubleClicked( QListViewItem *,
00466                                                  const QPoint &, int ) ),
00467            SLOT( editItem( QListViewItem *, const QPoint &, int ) ) );
00468   connect( mTodoListView, SIGNAL( returnPressed( QListViewItem * ) ),
00469            SLOT( editItem( QListViewItem * ) ) );
00470   connect( mTodoListView, SIGNAL( contextMenuRequested( QListViewItem *,
00471                                                         const QPoint &, int ) ),
00472            SLOT( popupMenu( QListViewItem *, const QPoint &, int ) ) );
00473   connect( mTodoListView, SIGNAL( expanded( QListViewItem * ) ),
00474            SLOT( itemStateChanged( QListViewItem * ) ) );
00475   connect( mTodoListView, SIGNAL( collapsed( QListViewItem * ) ),
00476            SLOT( itemStateChanged( QListViewItem * ) ) );
00477 
00478 #if 0
00479   connect(mTodoListView,SIGNAL(selectionChanged(QListViewItem *)),
00480           SLOT(selectionChanged(QListViewItem *)));
00481   connect(mTodoListView,SIGNAL(clicked(QListViewItem *)),
00482           SLOT(selectionChanged(QListViewItem *)));
00483   connect(mTodoListView,SIGNAL(pressed(QListViewItem *)),
00484           SLOT(selectionChanged(QListViewItem *)));
00485 #endif
00486   connect( mTodoListView, SIGNAL(selectionChanged() ),
00487            SLOT( processSelectionChange() ) );
00488   connect( mQuickAdd, SIGNAL( returnPressed () ),
00489            SLOT( addQuickTodo() ) );
00490 
00491   connect( mTodoListView, SIGNAL( incidenceAdded( Incidence* ) ),
00492            SIGNAL( incidenceAdded( Incidence* ) ) );
00493   connect( mTodoListView, SIGNAL( incidenceChanged( Incidence*, Incidence* ) ),
00494            SIGNAL( incidenceChanged( Incidence*, Incidence* ) ) );
00495   connect( mTodoListView, SIGNAL( incidenceToBeDeleted( Incidence* ) ),
00496            SIGNAL( incidenceToBeDeleted( Incidence* ) ) );
00497   connect( mTodoListView, SIGNAL( incidenceDeleted( Incidence* ) ),
00498            SIGNAL( incidenceDeleted( Incidence* ) ) );
00499 }
00500 
00501 KOTodoView::~KOTodoView()
00502 {
00503   delete mDocPrefs;
00504 }
00505 
00506 void KOTodoView::setCalendar( Calendar *cal )
00507 {
00508   BaseView::setCalendar( cal );
00509   mTodoListView->setCalendar( cal );
00510 }
00511 
00512 void KOTodoView::updateView()
00513 {
00514 //  kdDebug(5850) << "KOTodoView::updateView()" << endl;
00515   int oldPos = mTodoListView->contentsY();
00516   mItemsToDelete.clear();
00517   mTodoListView->clear();
00518 
00519   Todo::List todoList = calendar()->todos();
00520 
00521 /*
00522   kdDebug(5850) << "KOTodoView::updateView(): Todo List:" << endl;
00523   Event *t;
00524   for(t = todoList.first(); t; t = todoList.next()) {
00525     kdDebug(5850) << "  " << t->getSummary() << endl;
00526 
00527     if (t->getRelatedTo()) {
00528       kdDebug(5850) << "      (related to " << t->getRelatedTo()->getSummary() << ")" << endl;
00529     }
00530 
00531     QPtrList<Event> l = t->getRelations();
00532     Event *c;
00533     for(c=l.first();c;c=l.next()) {
00534       kdDebug(5850) << "    - relation: " << c->getSummary() << endl;
00535     }
00536   }
00537 */
00538 
00539   // Put for each Event a KOTodoViewItem in the list view. Don't rely on a
00540   // specific order of events. That means that we have to generate parent items
00541   // recursively for proper hierarchical display of Todos.
00542   mTodoMap.clear();
00543   Todo::List::ConstIterator it;
00544   for( it = todoList.begin(); it != todoList.end(); ++it ) {
00545     if ( !mTodoMap.contains( *it ) ) {
00546       insertTodoItem( *it );
00547     }
00548   }
00549 
00550   // Restore opened/closed state
00551   mTodoListView->blockSignals( true );
00552   if( mDocPrefs ) restoreItemState( mTodoListView->firstChild() );
00553   mTodoListView->blockSignals( false );
00554 
00555   mTodoListView->setContentsPos( 0, oldPos );
00556 
00557   processSelectionChange();
00558 }
00559 
00560 void KOTodoView::restoreItemState( QListViewItem *item )
00561 {
00562   while( item ) {
00563     KOTodoViewItem *todoItem = (KOTodoViewItem *)item;
00564     todoItem->setOpen( mDocPrefs->readBoolEntry( todoItem->todo()->uid() ) );
00565     if( item->childCount() > 0 ) restoreItemState( item->firstChild() );
00566     item = item->nextSibling();
00567   }
00568 }
00569 
00570 
00571 QMap<Todo *,KOTodoViewItem *>::ConstIterator
00572   KOTodoView::insertTodoItem(Todo *todo)
00573 {
00574 //  kdDebug(5850) << "KOTodoView::insertTodoItem(): " << todo->getSummary() << endl;
00575   Incidence *incidence = todo->relatedTo();
00576   if (incidence && incidence->type() == "Todo") {
00577     // Use dynamic_cast, because in the future the related item might also be an event
00578     Todo *relatedTodo = dynamic_cast<Todo *>(incidence);
00579 
00580 //    kdDebug(5850) << "  has Related" << endl;
00581     QMap<Todo *,KOTodoViewItem *>::ConstIterator itemIterator;
00582     itemIterator = mTodoMap.find(relatedTodo);
00583     if (itemIterator == mTodoMap.end()) {
00584 //      kdDebug(5850) << "    related not yet in list" << endl;
00585       itemIterator = insertTodoItem (relatedTodo);
00586     }
00587     // isn't this pretty stupid? We give one Todo  to the KOTodoViewItem
00588     // and one into the map. Sure finding is more easy but why? -zecke
00589     KOTodoViewItem *todoItem = new KOTodoViewItem(*itemIterator,todo,this);
00590     todoItem->setResourceColor( KOHelper::resourceColor( mTodoListView->calendar(), incidence ) );
00591     return mTodoMap.insert(todo,todoItem);
00592   } else {
00593 //    kdDebug(5850) << "  no Related" << endl;
00594       // see above -zecke
00595     KOTodoViewItem *todoItem = new KOTodoViewItem(mTodoListView,todo,this);
00596     todoItem->setResourceColor( KOHelper::resourceColor( mTodoListView->calendar(), todo ) );
00597     return mTodoMap.insert(todo,todoItem);
00598   }
00599 }
00600 
00601 void KOTodoView::removeTodoItems()
00602 {
00603   KOTodoViewItem *item;
00604   for ( item = mItemsToDelete.first(); item; item = mItemsToDelete.next() ) {
00605     Todo *todo = item->todo();
00606     if ( todo && mTodoMap.contains( todo ) ) {
00607       mTodoMap.remove( todo );
00608     }
00609     delete item;
00610   }
00611   mItemsToDelete.clear();
00612 }
00613 
00614 
00615 bool KOTodoView::scheduleRemoveTodoItem( KOTodoViewItem *todoItem )
00616 {
00617   if ( todoItem ) {
00618     mItemsToDelete.append( todoItem );
00619     QTimer::singleShot( 0, this, SLOT( removeTodoItems() ) );
00620     return true;
00621   } else
00622     return false;
00623 }
00624 
00625 void KOTodoView::updateConfig()
00626 {
00627   mTodoListView->repaintContents();
00628 }
00629 
00630 Incidence::List KOTodoView::selectedIncidences()
00631 {
00632   Incidence::List selected;
00633 
00634   KOTodoViewItem *item = (KOTodoViewItem *)(mTodoListView->selectedItem());
00635 //  if (!item) item = mActiveItem;
00636   if (item) selected.append(item->todo());
00637 
00638   return selected;
00639 }
00640 
00641 Todo::List KOTodoView::selectedTodos()
00642 {
00643   Todo::List selected;
00644 
00645   KOTodoViewItem *item = (KOTodoViewItem *)(mTodoListView->selectedItem());
00646 //  if (!item) item = mActiveItem;
00647   if (item) selected.append(item->todo());
00648 
00649   return selected;
00650 }
00651 
00652 void KOTodoView::changeIncidenceDisplay(Incidence *incidence, int action)
00653 {
00654   // The todo view only displays todos, so exit on all other incidences
00655   if ( incidence->type() != "Todo" )
00656     return;
00657   bool isFiltered = !calendar()->filter()->filterIncidence( incidence );
00658   Todo *todo = static_cast<Todo *>(incidence);
00659   if ( todo ) {
00660     KOTodoViewItem *todoItem = 0;
00661     if ( mTodoMap.contains( todo ) ) {
00662       todoItem = mTodoMap[todo];
00663     }
00664     switch ( action ) {
00665       case KOGlobals::INCIDENCEADDED:
00666       case KOGlobals::INCIDENCEEDITED:
00667         // If it's already there, edit it, otherwise just add
00668         if ( todoItem ) {
00669           if ( isFiltered ) {
00670             scheduleRemoveTodoItem( todoItem );
00671           } else {
00672             // correctly update changes in relations
00673             Todo*parent = dynamic_cast<Todo*>( todo->relatedTo() );
00674             KOTodoViewItem*parentItem = 0;
00675             if ( parent && mTodoMap.contains(parent) ) {
00676               parentItem = mTodoMap[ parent ];
00677             }
00678             if ( todoItem->parent() != parentItem ) {
00679               // The relations changed
00680               if ( parentItem ) {
00681                 parentItem->insertItem( todoItem );
00682               } else {
00683                 mTodoListView->insertItem( todoItem );
00684               }
00685             }
00686             todoItem->construct();
00687           }
00688         } else {
00689           if ( !isFiltered ) {
00690             insertTodoItem( todo );
00691           }
00692         }
00693         break;
00694       case KOGlobals::INCIDENCEDELETED:
00695         if ( todoItem ) {
00696           scheduleRemoveTodoItem( todoItem );
00697         }
00698         break;
00699       default:
00700         QTimer::singleShot( 0, this, SLOT( updateView() ) );
00701     }
00702   } else {
00703     // use a QTimer here, because when marking todos finished using
00704     // the checkbox, this slot gets called, but we cannot update the views
00705     // because we're still inside KOTodoViewItem::stateChange
00706     QTimer::singleShot(0,this,SLOT(updateView()));
00707   }
00708 }
00709 
00710 void KOTodoView::showDates(const QDate &, const QDate &)
00711 {
00712 }
00713 
00714 void KOTodoView::showIncidences( const Incidence::List & )
00715 {
00716   kdDebug(5850) << "KOTodoView::showIncidences( const Incidence::List & ): not yet implemented" << endl;
00717 }
00718 
00719 void KOTodoView::printPreview(CalPrinter *calPrinter, const QDate &fd,
00720                               const QDate &td)
00721 {
00722 #ifndef KORG_NOPRINTER
00723   calPrinter->preview(CalPrinter::Todolist, fd, td);
00724 #endif
00725 }
00726 
00727 CalPrinter::PrintType KOTodoView::printType()
00728 {
00729   return CalPrinter::Todolist;
00730 }
00731 
00732 void KOTodoView::editItem( QListViewItem *item )
00733 {
00734   if (item)
00735     emit editIncidenceSignal( static_cast<KOTodoViewItem *>( item )->todo() );
00736 }
00737 
00738 void KOTodoView::editItem( QListViewItem *item, const QPoint &, int )
00739 {
00740   editItem( item );
00741 }
00742 
00743 void KOTodoView::showItem( QListViewItem *item )
00744 {
00745   if (item)
00746     emit showIncidenceSignal( static_cast<KOTodoViewItem *>( item )->todo() );
00747 }
00748 
00749 void KOTodoView::showItem( QListViewItem *item, const QPoint &, int )
00750 {
00751   showItem( item );
00752 }
00753 
00754 void KOTodoView::popupMenu( QListViewItem *item, const QPoint &, int column )
00755 {
00756   mActiveItem = static_cast<KOTodoViewItem *>( item );
00757   if ( mActiveItem && !mActiveItem->todo()->isReadOnly() ) {
00758     QDate date = mActiveItem->todo()->dtDue().date();
00759     if ( mActiveItem->todo()->hasDueDate () ) {
00760       mMovePopupMenu->datePicker()->setDate( date );
00761     } else {
00762       mMovePopupMenu->datePicker()->setDate( QDate::currentDate() );
00763     }
00764     switch ( column ) {
00765       case 2:
00766         mPriorityPopupMenu->popup( QCursor::pos() );
00767         break;
00768       case 3: {
00769         mPercentageCompletedPopupMenu->popup( QCursor::pos() );
00770         break;
00771       }
00772       case 4:
00773         mMovePopupMenu->popup( QCursor::pos() );
00774         break;
00775       case 5:
00776         getCategoryPopupMenu( mActiveItem )->popup( QCursor::pos() );
00777         break;
00778       default:
00779         mCopyPopupMenu->datePicker()->setDate( date );
00780         mCopyPopupMenu->datePicker()->setDate( QDate::currentDate() );
00781         mItemPopupMenu->setItemEnabled( POPUP_UNSUBTODO,
00782                                         mActiveItem->todo()->relatedTo() );
00783         mItemPopupMenu->popup( QCursor::pos() );
00784     }
00785   } else mPopupMenu->popup( QCursor::pos() );
00786 }
00787 
00788 void KOTodoView::newTodo()
00789 {
00790   emit newTodoSignal( QDate::currentDate().addDays(7) );
00791 }
00792 
00793 void KOTodoView::newSubTodo()
00794 {
00795   if (mActiveItem) {
00796     emit newSubTodoSignal(mActiveItem->todo());
00797   }
00798 }
00799 
00800 void KOTodoView::editTodo()
00801 {
00802   editItem( mActiveItem );
00803 }
00804 
00805 void KOTodoView::showTodo()
00806 {
00807   showItem( mActiveItem );
00808 }
00809 
00810 void KOTodoView::deleteTodo()
00811 {
00812   if (mActiveItem) {
00813     if (mActiveItem->childCount()) {
00814       KMessageBox::sorry(this,i18n("Cannot delete To-Do which has children."),
00815                          i18n("Delete To-Do"));
00816     } else {
00817       emit deleteIncidenceSignal(mActiveItem->todo());
00818     }
00819   }
00820 }
00821 
00822 void KOTodoView::setNewPriority(int index)
00823 {
00824   if (mActiveItem && !mActiveItem->todo()->isReadOnly ()) {
00825     Todo *todo = mActiveItem->todo();
00826     Todo *oldTodo = todo->clone();
00827     todo->setPriority(mPriority[index]);
00828     mActiveItem->construct();
00829     emit incidenceChanged( oldTodo, todo, KOGlobals::PRIORITY_MODIFIED );
00830     delete oldTodo;
00831   }
00832 }
00833 
00834 void KOTodoView::setNewPercentage(int index)
00835 {
00836   if ( mActiveItem && !mActiveItem->todo()->isReadOnly () ) {
00837     Todo *todo = mActiveItem->todo();
00838     Todo *oldTodo = todo->clone();
00839 
00840     if (mPercentage[index] == 100) {
00841       emit todoCompleted( todo );
00842     } else {
00843       todo->setCompleted(false);
00844     }
00845     todo->setPercentComplete(mPercentage[index]);
00846     mActiveItem->construct();
00847     emit incidenceChanged( oldTodo, todo, KOGlobals::COMPLETION_MODIFIED );
00848     delete oldTodo;
00849   }
00850 }
00851 
00852 void KOTodoView::setNewDate(QDate date)
00853 {
00854   if ( mActiveItem && !mActiveItem->todo()->isReadOnly()) {
00855     Todo *todo = mActiveItem->todo();
00856 
00857     QDateTime dt;
00858     dt.setDate( date );
00859 
00860     if ( !todo->doesFloat() )
00861       dt.setTime( todo->dtDue().time() );
00862 
00863     Todo *oldTodo = todo->clone();
00864 
00865     if ( date.isNull() )
00866       todo->setHasDueDate( false );
00867     else if ( !todo->hasDueDate() )
00868       todo->setHasDueDate( true );
00869     todo->setDtDue( dt );
00870     todo->setRevision( todo->revision() + 1 );
00871 
00872     mActiveItem->construct();
00873     emit incidenceChanged( oldTodo, todo, KOGlobals::DATE_MODIFIED );
00874     delete oldTodo;
00875   }
00876 }
00877 
00878 void KOTodoView::copyTodoToDate( QDate date )
00879 {
00880   QDateTime dt;
00881   dt.setDate( date );
00882 
00883   if ( mActiveItem ) {
00884     Todo *newTodo = mActiveItem->todo()->clone();
00885     newTodo->recreate();
00886 
00887    if ( date.isNull() )
00888      newTodo->setHasDueDate( false );
00889    newTodo->setDtDue( dt );
00890    newTodo->setPercentComplete( 0 );
00891 
00892    // avoid forking
00893    if ( newTodo->doesRecur() )
00894      newTodo->recurrence()->unsetRecurs();
00895 
00896    calendar()->addTodo( newTodo );
00897    emit incidenceAdded( newTodo );
00898  }
00899 }
00900 
00901 QPopupMenu *KOTodoView::getCategoryPopupMenu( KOTodoViewItem *todoItem )
00902 {
00903   QPopupMenu *tempMenu = new QPopupMenu( this );
00904   QStringList checkedCategories = todoItem->todo()->categories();
00905 
00906   tempMenu->setCheckable( true );
00907   QStringList::Iterator it;
00908   for ( it = KOPrefs::instance()->mCustomCategories.begin();
00909         it != KOPrefs::instance()->mCustomCategories.end();
00910         ++it ) {
00911     int index = tempMenu->insertItem( *it );
00912     mCategory[ index ] = *it;
00913     if ( checkedCategories.find( *it ) != checkedCategories.end() )
00914       tempMenu->setItemChecked( index, true );
00915   }
00916 
00917   connect ( tempMenu, SIGNAL( activated( int ) ),
00918             SLOT( changedCategories( int ) ) );
00919   return tempMenu;
00920 }
00921 
00922 void KOTodoView::changedCategories(int index)
00923 {
00924   if (mActiveItem && !mActiveItem->todo()->isReadOnly ()) {
00925     Todo*todo = mActiveItem->todo();
00926     Todo*oldTodo = todo->clone();
00927     QStringList categories = todo->categories ();
00928     if (categories.find (mCategory[index]) != categories.end ())
00929       categories.remove (mCategory[index]);
00930     else
00931       categories.insert (categories.end(), mCategory[index]);
00932     categories.sort ();
00933     todo->setCategories (categories);
00934     mActiveItem->construct();
00935     emit incidenceChanged( oldTodo, todo, KOGlobals::CATEGORY_MODIFIED);
00936     delete oldTodo;
00937   }
00938 }
00939 
00940 void KOTodoView::setDocumentId( const QString &id )
00941 {
00942   kdDebug(5850) << "KOTodoView::setDocumentId()" << endl;
00943 
00944   mDocPrefs->setDoc( id );
00945 }
00946 
00947 void KOTodoView::itemStateChanged( QListViewItem *item )
00948 {
00949   if (!item) return;
00950 
00951   KOTodoViewItem *todoItem = (KOTodoViewItem *)item;
00952 
00953 //  kdDebug(5850) << "KOTodoView::itemStateChanged(): " << todoItem->todo()->summary() << endl;
00954 
00955   if( mDocPrefs ) mDocPrefs->writeEntry( todoItem->todo()->uid(), todoItem->isOpen() );
00956 }
00957 
00958 void KOTodoView::saveLayout(KConfig *config, const QString &group) const
00959 {
00960   mTodoListView->saveLayout(config,group);
00961 }
00962 
00963 void KOTodoView::restoreLayout(KConfig *config, const QString &group)
00964 {
00965   mTodoListView->restoreLayout(config,group);
00966 }
00967 
00968 void KOTodoView::processSelectionChange()
00969 {
00970 //  kdDebug(5850) << "KOTodoView::processSelectionChange()" << endl;
00971 
00972   KOTodoViewItem *item =
00973     static_cast<KOTodoViewItem *>( mTodoListView->selectedItem() );
00974 
00975   if ( !item ) {
00976     emit incidenceSelected( 0 );
00977   } else {
00978     emit incidenceSelected( item->todo() );
00979   }
00980 }
00981 
00982 void KOTodoView::clearSelection()
00983 {
00984   mTodoListView->selectAll( false );
00985 }
00986 
00987 void KOTodoView::purgeCompleted()
00988 {
00989   emit purgeCompletedSignal();
00990 }
00991 
00992 void KOTodoView::addQuickTodo()
00993 {
00994   if ( ! mQuickAdd->text().stripWhiteSpace().isEmpty() ) {
00995     Todo *todo = new Todo();
00996     todo->setSummary( mQuickAdd->text() );
00997     todo->setOrganizer( Person( KOPrefs::instance()->fullName(),
00998                         KOPrefs::instance()->email() ) );
00999     if ( !calendar()->addTodo( todo ) ) {
01000       KODialogManager::errorSaveTodo( this );
01001       return;
01002     }
01003     mQuickAdd->setText( QString::null );
01004     emit incidenceAdded( todo );
01005     updateView();
01006   }
01007 }
01008 
01009 void KOTodoView::emitCompletedSignal( Todo *todo )
01010 {
01011   emit todoCompleted( todo );
01012 }
KDE Logo
This file is part of the documentation for korganizer Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Oct 17 09:56:26 2007 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003