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