00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <qlayout.h>
00027 #include <qheader.h>
00028 #include <qcursor.h>
00029 #include <qlabel.h>
00030 #include <qtimer.h>
00031
00032 #include <kdebug.h>
00033 #include <klocale.h>
00034 #include <kglobal.h>
00035 #include <kiconloader.h>
00036 #include <kmessagebox.h>
00037
00038 #include <libkcal/calhelper.h>
00039 #include <libkcal/icaldrag.h>
00040 #include <libkcal/vcaldrag.h>
00041 #include <libkcal/dndfactory.h>
00042 #include <libkcal/calendarresources.h>
00043 #include <libkcal/resourcecalendar.h>
00044 #include <libkcal/calfilter.h>
00045 #include <libkcal/incidenceformatter.h>
00046
00047 #include <libkdepim/clicklineedit.h>
00048 #include <libkdepim/kdatepickerpopup.h>
00049
00050 #include <libemailfunctions/email.h>
00051
00052 #include "docprefs.h"
00053
00054 #include "koincidencetooltip.h"
00055 #include "kodialogmanager.h"
00056 #include "kotodoview.h"
00057 #include "koprefs.h"
00058 #include "koglobals.h"
00059 using namespace KOrg;
00060 #include "kotodoviewitem.h"
00061 #include "kotodoview.moc"
00062 #ifndef KORG_NOPRINTER
00063 #include "kocorehelper.h"
00064 #include "calprinter.h"
00065 #endif
00066
00067 KOTodoListViewToolTip::KOTodoListViewToolTip (QWidget *parent,
00068 Calendar *calendar,
00069 KOTodoListView *lv )
00070 :QToolTip(parent), mCalendar( calendar )
00071 {
00072 todolist=lv;
00073 }
00074
00075 void KOTodoListViewToolTip::maybeTip( const QPoint & pos)
00076 {
00077 QRect r;
00078 int headerPos;
00079 int col=todolist->header()->sectionAt(todolist->contentsX() + pos.x());
00080 KOTodoViewItem *i=(KOTodoViewItem *)todolist->itemAt(pos);
00081
00082
00083 if( i && KOPrefs::instance()->mEnableToolTips )
00084 {
00085
00086
00087 r=todolist->itemRect(i);
00088 headerPos = todolist->header()->sectionPos(col)-todolist->contentsX();
00089 r.setLeft( (headerPos < 0 ? 0 : headerPos) );
00090 r.setRight(headerPos + todolist->header()->sectionSize(col));
00091
00092
00093 QString tipText( IncidenceFormatter::toolTipStr( mCalendar, i->todo(), QDate(), true ) );;
00094 if ( !tipText.isEmpty() ) {
00095 tip(r, tipText);
00096 }
00097 }
00098
00099 }
00100
00101
00102
00103 KOTodoListView::KOTodoListView( QWidget *parent, const char *name )
00104 : KListView( parent, name ), mCalendar( 0 ), mChanger( 0 )
00105 {
00106 mOldCurrent = 0;
00107 mMousePressed = false;
00108
00109
00110 tooltip = new KOTodoListViewToolTip( viewport(), mCalendar, this );
00111 }
00112
00113 KOTodoListView::~KOTodoListView()
00114 {
00115 delete tooltip;
00116 }
00117
00118 void KOTodoListView::setCalendar( Calendar *cal )
00119 {
00120 mCalendar = cal;
00121 setAcceptDrops( mCalendar );
00122 viewport()->setAcceptDrops( mCalendar );
00123 }
00124
00125 bool KOTodoListView::event(QEvent *e)
00126 {
00127 int tmp=0;
00128 KOTodoViewItem *i;
00129
00130
00131
00132 if(e->type()==QEvent::ApplicationPaletteChange)
00133 {
00134
00135 KListView::event(e);
00136 i=(KOTodoViewItem *)itemAtIndex(tmp);
00137
00138 while(i!=0)
00139 {
00140 i->construct();
00141 tmp++;
00142 i=(KOTodoViewItem *)itemAtIndex(tmp);
00143 }
00144
00145 }
00146
00147 return (KListView::event(e) || e->type()==QEvent::ApplicationPaletteChange);
00148 }
00149
00150 void KOTodoListView::contentsDragEnterEvent(QDragEnterEvent *e)
00151 {
00152 #ifndef KORG_NODND
00153
00154 if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) &&
00155 !QTextDrag::canDecode( e ) ) {
00156 e->ignore();
00157 return;
00158 }
00159
00160 mOldCurrent = currentItem();
00161 #endif
00162 }
00163
00164 void KOTodoListView::contentsDragMoveEvent(QDragMoveEvent *e)
00165 {
00166 #ifndef KORG_NODND
00167
00168
00169 if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) &&
00170 !QTextDrag::canDecode( e ) ) {
00171 e->ignore();
00172 return;
00173 }
00174
00175 e->accept();
00176 #endif
00177 }
00178
00179 void KOTodoListView::contentsDragLeaveEvent( QDragLeaveEvent * )
00180 {
00181 #ifndef KORG_NODND
00182
00183
00184 setCurrentItem(mOldCurrent);
00185 setSelected(mOldCurrent,true);
00186 #endif
00187 }
00188
00189 void KOTodoListView::contentsDropEvent( QDropEvent *e )
00190 {
00191 #ifndef KORG_NODND
00192 kdDebug(5850) << "KOTodoListView::contentsDropEvent" << endl;
00193
00194 if ( !mCalendar || !mChanger ||
00195 ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) &&
00196 !QTextDrag::canDecode( e ) ) ) {
00197 e->ignore();
00198 return;
00199 }
00200
00201 DndFactory factory( mCalendar );
00202 Todo *todo = factory.createDropTodo(e);
00203
00204 if ( todo ) {
00205 e->acceptAction();
00206
00207 KOTodoViewItem *destination =
00208 (KOTodoViewItem *)itemAt(contentsToViewport(e->pos()));
00209 Todo *destinationEvent = 0;
00210 if (destination) destinationEvent = destination->todo();
00211
00212 Todo *existingTodo = mCalendar->todo(todo->uid());
00213
00214 if( existingTodo ) {
00215 kdDebug(5850) << "Drop existing Todo " << existingTodo << " onto " << destinationEvent << endl;
00216 Incidence *to = destinationEvent;
00217 while(to) {
00218 if (to->uid() == todo->uid()) {
00219 KMessageBox::information(this,
00220 i18n("Cannot move to-do to itself or a child of itself."),
00221 i18n("Drop To-do"), "NoDropTodoOntoItself" );
00222 delete todo;
00223 return;
00224 }
00225 to = to->relatedTo();
00226 }
00227
00228 Todo*oldTodo = existingTodo->clone();
00229 if ( mChanger->beginChange( existingTodo, 0, QString() ) ) {
00230 existingTodo->setRelatedTo( destinationEvent );
00231 mChanger->changeIncidence( oldTodo, existingTodo, KOGlobals::RELATION_MODIFIED, this );
00232 mChanger->endChange( existingTodo, 0, QString() );
00233 } else {
00234 KMessageBox::sorry( this, i18n("Unable to change to-do's parent, "
00235 "because the to-do cannot be locked.") );
00236 }
00237 delete oldTodo;
00238 delete todo;
00239 } else {
00240
00241 todo->setRelatedTo(destinationEvent);
00242 if ( !mChanger->addIncidence( todo, 0, QString(), this ) ) {
00243 KODialogManager::errorSaveIncidence( this, todo );
00244 delete todo;
00245 return;
00246 }
00247 }
00248 } else {
00249 QString text;
00250 KOTodoViewItem *todoi = dynamic_cast<KOTodoViewItem *>(itemAt( contentsToViewport(e->pos()) ));
00251 if ( ! todoi ) {
00252
00253 e->ignore();
00254 kdDebug( 5850 ) << "KOTodoListView::contentsDropEvent(): Not dropped on a todo item" << endl;
00255 kdDebug( 5850 ) << "TODO: Create a new todo with the given data" << endl;
00256
00257 } else if ( QTextDrag::decode(e, text) ) {
00258
00259 kdDebug(5850) << "Dropped : " << text << endl;
00260 Todo*todo = todoi->todo();
00261 if( mChanger->beginChange( todo, 0, QString() ) ) {
00262 Todo*oldtodo = todo->clone();
00263
00264 if( text.startsWith( "file:" ) ) {
00265 todo->addAttachment( new Attachment( text ) );
00266 } else {
00267 QStringList emails = KPIM::splitEmailAddrList( text );
00268 for(QStringList::ConstIterator it = emails.begin();it!=emails.end();++it) {
00269 kdDebug(5850) << " Email: " << (*it) << endl;
00270 int pos = (*it).find("<");
00271 QString name = (*it).left(pos);
00272 QString email = (*it).mid(pos);
00273 if (!email.isEmpty() && todoi) {
00274 todo->addAttendee( new Attendee( name, email ) );
00275 }
00276 }
00277 }
00278
00279 mChanger->changeIncidence( oldtodo, todo, KOGlobals::NOTHING_MODIFIED, this );
00280 mChanger->endChange( todo, 0, QString() );
00281 } else {
00282 KMessageBox::sorry( this, i18n("Unable to add attendees to the to-do, "
00283 "because the to-do cannot be locked.") );
00284 }
00285 }
00286 else {
00287 kdDebug(5850) << "KOTodoListView::contentsDropEvent(): Todo from drop not decodable" << endl;
00288 e->ignore();
00289 }
00290 }
00291 #endif
00292 }
00293
00294 void KOTodoListView::contentsMousePressEvent(QMouseEvent* e)
00295 {
00296 QListView::contentsMousePressEvent(e);
00297 QPoint p(contentsToViewport(e->pos()));
00298 QListViewItem *i = itemAt(p);
00299 if (i) {
00300
00301
00302 if (p.x() > header()->sectionPos(header()->mapToIndex(0)) +
00303 treeStepSize() * (i->depth() + (rootIsDecorated() ? 1 : 0)) +
00304 itemMargin() ||
00305 p.x() < header()->sectionPos(header()->mapToIndex(0))) {
00306 if (e->button()==Qt::LeftButton) {
00307 mPressPos = e->pos();
00308 mMousePressed = true;
00309 }
00310 }
00311 }
00312 }
00313
00314 void KOTodoListView::contentsMouseMoveEvent(QMouseEvent* e)
00315 {
00316 #ifndef KORG_NODND
00317
00318 QListView::contentsMouseMoveEvent(e);
00319 if (mMousePressed && (mPressPos - e->pos()).manhattanLength() >
00320 QApplication::startDragDistance()) {
00321 mMousePressed = false;
00322 QListViewItem *item = itemAt(contentsToViewport(mPressPos));
00323 if ( item && mCalendar ) {
00324
00325 DndFactory factory( mCalendar );
00326 ICalDrag *vd = factory.createDrag(
00327 ((KOTodoViewItem *)item)->todo(),viewport());
00328 if (vd->drag()) {
00329 kdDebug(5850) << "KOTodoListView::contentsMouseMoveEvent(): Delete drag source" << endl;
00330 }
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341 }
00342 }
00343 #endif
00344 }
00345
00346 void KOTodoListView::contentsMouseReleaseEvent(QMouseEvent *e)
00347 {
00348 QListView::contentsMouseReleaseEvent(e);
00349 mMousePressed = false;
00350 }
00351
00352 void KOTodoListView::contentsMouseDoubleClickEvent(QMouseEvent *e)
00353 {
00354 if (!e) return;
00355
00356 QPoint vp = contentsToViewport(e->pos());
00357
00358 QListViewItem *item = itemAt(vp);
00359
00360 if (!item) return;
00361
00362 emit doubleClicked(item,vp,0);
00363 }
00364
00366
00367 KOTodoView::KOTodoView( Calendar *calendar, QWidget *parent, const char* name)
00368 : KOrg::BaseView( calendar, parent, name )
00369 {
00370 QBoxLayout *topLayout = new QVBoxLayout( this );
00371
00372 QLabel *title = new QLabel( i18n("To-dos:"), this );
00373 title->setFrameStyle( QFrame::Panel | QFrame::Raised );
00374 topLayout->addWidget( title );
00375
00376 mQuickAdd = new KPIM::ClickLineEdit( this, i18n( "Click to add a new to-do" ) );
00377 mQuickAdd->setAcceptDrops( false );
00378 topLayout->addWidget( mQuickAdd );
00379
00380 if ( !KOPrefs::instance()->mEnableQuickTodo ) mQuickAdd->hide();
00381
00382 mTodoListView = new KOTodoListView( this );
00383 topLayout->addWidget( mTodoListView );
00384
00385 mTodoListView->setRootIsDecorated( true );
00386 mTodoListView->setAllColumnsShowFocus( true );
00387
00388 mTodoListView->setShowSortIndicator( true );
00389
00390 mTodoListView->addColumn( i18n("Summary") );
00391 mTodoListView->addColumn( i18n("Recurs") );
00392 mTodoListView->addColumn( i18n("Priority") );
00393 mTodoListView->setColumnAlignment( ePriorityColumn, AlignHCenter );
00394 mTodoListView->addColumn( i18n("Complete") );
00395 mTodoListView->setColumnAlignment( ePercentColumn, AlignRight );
00396 mTodoListView->addColumn( i18n("Due Date/Time") );
00397 mTodoListView->setColumnAlignment( eDueDateColumn, AlignLeft );
00398 mTodoListView->addColumn( i18n("Categories") );
00399 #if 0
00400 mTodoListView->addColumn( i18n("Sort Id") );
00401 mTodoListView->setColumnAlignment( 4, AlignHCenter );
00402 #endif
00403
00404 mTodoListView->setMinimumHeight( 60 );
00405 mTodoListView->setItemsRenameable( true );
00406 mTodoListView->setRenameable( 0 );
00407
00408 mTodoListView->setColumnWidthMode( eSummaryColumn, QListView::Manual );
00409 mTodoListView->setColumnWidthMode( eRecurColumn, QListView::Manual );
00410 mTodoListView->setColumnWidthMode( ePriorityColumn, QListView::Manual );
00411 mTodoListView->setColumnWidthMode( ePercentColumn, QListView::Manual );
00412 mTodoListView->setColumnWidthMode( eDueDateColumn, QListView::Manual );
00413 mTodoListView->setColumnWidthMode( eCategoriesColumn, QListView::Manual );
00414 #if 0
00415 mTodoListView->setColumnWidthMode( eDescriptionColumn, QListView::Manual );
00416 #endif
00417
00418 mPriorityPopupMenu = new QPopupMenu( this );
00419 mPriority[ mPriorityPopupMenu->insertItem( i18n("Unspecified priority", "unspecified") ) ] = 0;
00420 mPriority[ mPriorityPopupMenu->insertItem( i18n( "1 (highest)") ) ] = 1;
00421 mPriority[ mPriorityPopupMenu->insertItem( i18n( "2" ) ) ] = 2;
00422 mPriority[ mPriorityPopupMenu->insertItem( i18n( "3" ) ) ] = 3;
00423 mPriority[ mPriorityPopupMenu->insertItem( i18n( "4" ) ) ] = 4;
00424 mPriority[ mPriorityPopupMenu->insertItem( i18n( "5 (medium)" ) ) ] = 5;
00425 mPriority[ mPriorityPopupMenu->insertItem( i18n( "6" ) ) ] = 6;
00426 mPriority[ mPriorityPopupMenu->insertItem( i18n( "7" ) ) ] = 7;
00427 mPriority[ mPriorityPopupMenu->insertItem( i18n( "8" ) ) ] = 8;
00428 mPriority[ mPriorityPopupMenu->insertItem( i18n( "9 (lowest)" ) ) ] = 9;
00429 connect( mPriorityPopupMenu, SIGNAL( activated( int ) ),
00430 SLOT( setNewPriority( int ) ));
00431
00432 mPercentageCompletedPopupMenu = new QPopupMenu(this);
00433 for (int i = 0; i <= 100; i+=10) {
00434 QString label = QString ("%1 %").arg (i);
00435 mPercentage[mPercentageCompletedPopupMenu->insertItem (label)] = i;
00436 }
00437 connect( mPercentageCompletedPopupMenu, SIGNAL( activated( int ) ),
00438 SLOT( setNewPercentage( int ) ) );
00439
00440 mMovePopupMenu = new KDatePickerPopup(
00441 KDatePickerPopup::NoDate |
00442 KDatePickerPopup::DatePicker |
00443 KDatePickerPopup::Words );
00444 mCopyPopupMenu = new KDatePickerPopup(
00445 KDatePickerPopup::NoDate |
00446 KDatePickerPopup::DatePicker |
00447 KDatePickerPopup::Words );
00448
00449
00450 connect( mMovePopupMenu, SIGNAL( dateChanged( QDate )),
00451 SLOT( setNewDate( QDate ) ) );
00452 connect( mCopyPopupMenu, SIGNAL( dateChanged( QDate )),
00453 SLOT( copyTodoToDate( QDate ) ) );
00454
00455 mItemPopupMenu = new QPopupMenu(this);
00456 mItemPopupMenu->insertItem(i18n("&Show"), this,
00457 SLOT (showTodo()));
00458 mItemPopupMenu->insertItem(i18n("&Edit..."), this,
00459 SLOT (editTodo()), 0, ePopupEdit );
00460 #ifndef KORG_NOPRINTER
00461 mItemPopupMenu->insertItem(KOGlobals::self()->smallIcon("printer1"), i18n("&Print..."), this, SLOT( printTodo() ) );
00462 #endif
00463 mItemPopupMenu->insertItem(KOGlobals::self()->smallIconSet("editdelete"), i18n("&Delete"), this,
00464 SLOT (deleteTodo()), 0, ePopupDelete );
00465 mItemPopupMenu->insertSeparator();
00466 mItemPopupMenu->insertItem(KOGlobals::self()->smallIconSet("todo"), i18n("New &To-do..."), this,
00467 SLOT (newTodo()) );
00468 mItemPopupMenu->insertItem(i18n("New Su&b-to-do..."), this,
00469 SLOT (newSubTodo()));
00470 mItemPopupMenu->insertItem( i18n("&Make this To-do Independent"), this,
00471 SIGNAL( unSubTodoSignal() ), 0, ePopupUnSubTodo );
00472 mItemPopupMenu->insertItem( i18n("Make all Sub-to-dos &Independent"), this,
00473 SIGNAL( unAllSubTodoSignal() ), 0, ePopupUnAllSubTodo );
00474 mItemPopupMenu->insertSeparator();
00475 mItemPopupMenu->insertItem( i18n("&Copy To"), mCopyPopupMenu, ePopupCopyTo );
00476 mItemPopupMenu->insertItem(i18n("&Move To"), mMovePopupMenu, ePopupMoveTo );
00477 mItemPopupMenu->insertSeparator();
00478 mItemPopupMenu->insertItem(i18n("delete completed to-dos","Pur&ge Completed"),
00479 this, SLOT( purgeCompleted() ) );
00480
00481 connect( mMovePopupMenu, SIGNAL( dateChanged( QDate ) ),
00482 mItemPopupMenu, SLOT( hide() ) );
00483 connect( mCopyPopupMenu, SIGNAL( dateChanged( QDate ) ),
00484 mItemPopupMenu, SLOT( hide() ) );
00485
00486 mPopupMenu = new QPopupMenu(this);
00487 mPopupMenu->insertItem(KOGlobals::self()->smallIconSet("todo"), i18n("&New To-do..."), this,
00488 SLOT(newTodo()) );
00489 mPopupMenu->insertItem(i18n("delete completed to-dos","&Purge Completed"),
00490 this, SLOT(purgeCompleted()));
00491
00492 mDocPrefs = new DocPrefs( name );
00493
00494
00495 connect( mTodoListView, SIGNAL( doubleClicked( QListViewItem *,
00496 const QPoint &, int ) ),
00497 SLOT( editItem( QListViewItem *, const QPoint &, int ) ) );
00498 connect( mTodoListView, SIGNAL( returnPressed( QListViewItem * ) ),
00499 SLOT( editItem( QListViewItem * ) ) );
00500 connect( mTodoListView, SIGNAL( contextMenuRequested( QListViewItem *,
00501 const QPoint &, int ) ),
00502 SLOT( popupMenu( QListViewItem *, const QPoint &, int ) ) );
00503 connect( mTodoListView, SIGNAL( expanded( QListViewItem * ) ),
00504 SLOT( itemStateChanged( QListViewItem * ) ) );
00505 connect( mTodoListView, SIGNAL( collapsed( QListViewItem * ) ),
00506 SLOT( itemStateChanged( QListViewItem * ) ) );
00507
00508 #if 0
00509 connect(mTodoListView,SIGNAL(selectionChanged(QListViewItem *)),
00510 SLOT(selectionChanged(QListViewItem *)));
00511 connect(mTodoListView,SIGNAL(clicked(QListViewItem *)),
00512 SLOT(selectionChanged(QListViewItem *)));
00513 connect(mTodoListView,SIGNAL(pressed(QListViewItem *)),
00514 SLOT(selectionChanged(QListViewItem *)));
00515 #endif
00516 connect( mTodoListView, SIGNAL(selectionChanged() ),
00517 SLOT( processSelectionChange() ) );
00518 connect( mQuickAdd, SIGNAL( returnPressed () ),
00519 SLOT( addQuickTodo() ) );
00520 }
00521
00522 KOTodoView::~KOTodoView()
00523 {
00524 delete mDocPrefs;
00525 }
00526
00527 void KOTodoView::setCalendar( Calendar *cal )
00528 {
00529 BaseView::setCalendar( cal );
00530 mTodoListView->setCalendar( cal );
00531 }
00532
00533 void KOTodoView::updateView()
00534 {
00535
00536 int oldPos = mTodoListView->contentsY();
00537 mItemsToDelete.clear();
00538 mTodoListView->clear();
00539
00540 Todo::List todoList = calendar()->todos();
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563 mTodoMap.clear();
00564 Todo::List::ConstIterator it;
00565 for( it = todoList.begin(); it != todoList.end(); ++it ) {
00566 if ( !mTodoMap.contains( *it ) ) {
00567 insertTodoItem( *it );
00568 }
00569 }
00570
00571
00572 mTodoListView->blockSignals( true );
00573 if( mDocPrefs ) restoreItemState( mTodoListView->firstChild() );
00574 mTodoListView->blockSignals( false );
00575
00576 mTodoListView->setContentsPos( 0, oldPos );
00577
00578 processSelectionChange();
00579 }
00580
00581 void KOTodoView::restoreItemState( QListViewItem *item )
00582 {
00583 while( item ) {
00584 KOTodoViewItem *todoItem = (KOTodoViewItem *)item;
00585 todoItem->setOpen( mDocPrefs->readBoolEntry( todoItem->todo()->uid() ) );
00586 if( item->childCount() > 0 ) restoreItemState( item->firstChild() );
00587 item = item->nextSibling();
00588 }
00589 }
00590
00591
00592 QMap<Todo *,KOTodoViewItem *>::ConstIterator
00593 KOTodoView::insertTodoItem(Todo *todo)
00594 {
00595
00596 Incidence *incidence = todo->relatedTo();
00597 if (incidence && incidence->type() == "Todo") {
00598
00599 Todo *relatedTodo = dynamic_cast<Todo *>(incidence);
00600
00601
00602 mTodoMap.insert(todo,0);
00603
00604
00605 QMap<Todo *,KOTodoViewItem *>::ConstIterator itemIterator;
00606 itemIterator = mTodoMap.find(relatedTodo);
00607 if (itemIterator == mTodoMap.end()) {
00608
00609 itemIterator = insertTodoItem (relatedTodo);
00610 }
00611
00612
00613 KOTodoViewItem *todoItem;
00614
00615
00616
00617 if ( *itemIterator == 0 ) {
00618 todo->setRelatedTo(0);
00619 todoItem = new KOTodoViewItem(mTodoListView,todo,this);
00620 }
00621 else
00622 todoItem = new KOTodoViewItem(*itemIterator,todo,this);
00623
00624 return mTodoMap.insert(todo,todoItem);
00625 } else {
00626
00627
00628 KOTodoViewItem *todoItem = new KOTodoViewItem(mTodoListView,todo,this);
00629 return mTodoMap.insert(todo,todoItem);
00630 }
00631 }
00632
00633 void KOTodoView::removeTodoItems()
00634 {
00635 KOTodoViewItem *item;
00636 for ( item = mItemsToDelete.first(); item; item = mItemsToDelete.next() ) {
00637 Todo *todo = item->todo();
00638 if ( todo && mTodoMap.contains( todo ) ) {
00639 mTodoMap.remove( todo );
00640 }
00641 delete item;
00642 }
00643 mItemsToDelete.clear();
00644 }
00645
00646
00647 bool KOTodoView::scheduleRemoveTodoItem( KOTodoViewItem *todoItem )
00648 {
00649 if ( todoItem ) {
00650 mItemsToDelete.append( todoItem );
00651 QTimer::singleShot( 0, this, SLOT( removeTodoItems() ) );
00652 return true;
00653 } else
00654 return false;
00655 }
00656
00657 void KOTodoView::updateConfig()
00658 {
00659 mTodoListView->repaintContents();
00660 }
00661
00662 Incidence::List KOTodoView::selectedIncidences()
00663 {
00664 Incidence::List selected;
00665
00666 KOTodoViewItem *item = (KOTodoViewItem *)(mTodoListView->selectedItem());
00667
00668 if (item) selected.append(item->todo());
00669
00670 return selected;
00671 }
00672
00673 Todo::List KOTodoView::selectedTodos()
00674 {
00675 Todo::List selected;
00676
00677 KOTodoViewItem *item = (KOTodoViewItem *)(mTodoListView->selectedItem());
00678
00679 if (item) selected.append(item->todo());
00680
00681 return selected;
00682 }
00683
00684 void KOTodoView::changeIncidenceDisplay(Incidence *incidence, int action)
00685 {
00686
00687 if ( incidence->type() != "Todo" )
00688 return;
00689 CalFilter *filter = calendar()->filter();
00690 bool isFiltered = filter && !filter->filterIncidence( incidence );
00691 Todo *todo = static_cast<Todo *>(incidence);
00692 if ( todo ) {
00693 KOTodoViewItem *todoItem = 0;
00694 if ( mTodoMap.contains( todo ) ) {
00695 todoItem = mTodoMap[todo];
00696 }
00697 switch ( action ) {
00698 case KOGlobals::INCIDENCEADDED:
00699 case KOGlobals::INCIDENCEEDITED:
00700
00701 if ( todoItem ) {
00702 if ( isFiltered ) {
00703 scheduleRemoveTodoItem( todoItem );
00704 } else {
00705
00706 Todo*parent = dynamic_cast<Todo*>( todo->relatedTo() );
00707 KOTodoViewItem*parentItem = 0;
00708 if ( parent && mTodoMap.contains(parent) ) {
00709 parentItem = mTodoMap[ parent ];
00710 }
00711 if ( todoItem->parent() != parentItem ) {
00712
00713 if ( parentItem ) {
00714 parentItem->insertItem( todoItem );
00715 } else {
00716 mTodoListView->insertItem( todoItem );
00717 }
00718 }
00719 todoItem->construct();
00720 }
00721 } else {
00722 if ( !isFiltered ) {
00723 insertTodoItem( todo );
00724 }
00725 }
00726 mTodoListView->sort();
00727 break;
00728 case KOGlobals::INCIDENCEDELETED:
00729 if ( todoItem ) {
00730 scheduleRemoveTodoItem( todoItem );
00731 }
00732 break;
00733 default:
00734 QTimer::singleShot( 0, this, SLOT( updateView() ) );
00735 }
00736 } else {
00737
00738
00739
00740 QTimer::singleShot(0,this,SLOT(updateView()));
00741 }
00742 }
00743
00744 void KOTodoView::showDates(const QDate &, const QDate &)
00745 {
00746 }
00747
00748 void KOTodoView::showIncidences( const Incidence::List &, const QDate & )
00749 {
00750 kdDebug(5850) << "KOTodoView::showIncidences( const Incidence::List & ): not yet implemented" << endl;
00751 }
00752
00753 CalPrinterBase::PrintType KOTodoView::printType()
00754 {
00755 if ( mTodoListView->selectedItem() ) {
00756 return CalPrinterBase::Incidence;
00757 } else {
00758 return CalPrinterBase::Todolist;
00759 }
00760 }
00761
00762 void KOTodoView::editItem( QListViewItem *item )
00763 {
00764 if (item)
00765 emit editIncidenceSignal( static_cast<KOTodoViewItem *>( item )->todo() );
00766 }
00767
00768 void KOTodoView::editItem( QListViewItem *item, const QPoint &, int )
00769 {
00770 editItem( item );
00771 }
00772
00773 void KOTodoView::showItem( QListViewItem *item )
00774 {
00775 if (item)
00776 emit showIncidenceSignal( static_cast<KOTodoViewItem *>( item )->todo() );
00777 }
00778
00779 void KOTodoView::showItem( QListViewItem *item, const QPoint &, int )
00780 {
00781 showItem( item );
00782 }
00783
00784 void KOTodoView::popupMenu( QListViewItem *item, const QPoint &, int column )
00785 {
00786 mActiveItem = static_cast<KOTodoViewItem *>( item );
00787 if ( mActiveItem && mActiveItem->todo() &&
00788 !mActiveItem->todo()->isReadOnly() ) {
00789 bool editable = !mActiveItem->todo()->isReadOnly();
00790 mItemPopupMenu->setItemEnabled( ePopupEdit, editable );
00791 mItemPopupMenu->setItemEnabled( ePopupDelete, editable );
00792 mItemPopupMenu->setItemEnabled( ePopupMoveTo, editable );
00793 mItemPopupMenu->setItemEnabled( ePopupCopyTo, editable );
00794 mItemPopupMenu->setItemEnabled( ePopupUnSubTodo, editable );
00795 mItemPopupMenu->setItemEnabled( ePopupUnAllSubTodo, editable );
00796
00797 if ( editable ) {
00798 QDate date = mActiveItem->todo()->dtDue().date();
00799 if ( mActiveItem->todo()->hasDueDate () ) {
00800 mMovePopupMenu->datePicker()->setDate( date );
00801 } else {
00802 mMovePopupMenu->datePicker()->setDate( QDate::currentDate() );
00803 }
00804 switch ( column ) {
00805 case ePriorityColumn:
00806 mPriorityPopupMenu->popup( QCursor::pos() );
00807 break;
00808 case ePercentColumn: {
00809 mPercentageCompletedPopupMenu->popup( QCursor::pos() );
00810 break;
00811 }
00812 case eDueDateColumn:
00813 mMovePopupMenu->popup( QCursor::pos() );
00814 break;
00815 case eCategoriesColumn:
00816 getCategoryPopupMenu( mActiveItem )->popup( QCursor::pos() );
00817 break;
00818 default:
00819 mCopyPopupMenu->datePicker()->setDate( date );
00820 mCopyPopupMenu->datePicker()->setDate( QDate::currentDate() );
00821 mItemPopupMenu->setItemEnabled( ePopupUnSubTodo,
00822 mActiveItem->todo()->relatedTo() );
00823 mItemPopupMenu->setItemEnabled( ePopupUnAllSubTodo,
00824 !mActiveItem->todo()->relations().isEmpty() );
00825 mItemPopupMenu->popup( QCursor::pos() );
00826 }
00827 } else {
00828 mItemPopupMenu->popup( QCursor::pos() );
00829 }
00830 } else mPopupMenu->popup( QCursor::pos() );
00831 }
00832
00833 void KOTodoView::newTodo()
00834 {
00835 kdDebug() << k_funcinfo << endl;
00836 emit newTodoSignal( 0, QString(),
00837 QDate::currentDate().addDays(7) );
00838 }
00839
00840 void KOTodoView::newSubTodo()
00841 {
00842 if (mActiveItem) {
00843 emit newSubTodoSignal(mActiveItem->todo());
00844 }
00845 }
00846
00847 void KOTodoView::editTodo()
00848 {
00849 editItem( mActiveItem );
00850 }
00851
00852 void KOTodoView::showTodo()
00853 {
00854 showItem( mActiveItem );
00855 }
00856
00857 void KOTodoView::printTodo()
00858 {
00859 #ifndef KORG_NOPRINTER
00860 KOCoreHelper helper;
00861 CalPrinter printer( this, BaseView::calendar(), &helper );
00862 connect( this, SIGNAL(configChanged()), &printer, SLOT(updateConfig()) );
00863
00864 Incidence::List selectedIncidences;
00865 selectedIncidences.append( mActiveItem->todo() );
00866
00867 printer.print( KOrg::CalPrinterBase::Incidence,
00868 QDate(), QDate(), selectedIncidences );
00869 #endif
00870 }
00871
00872 void KOTodoView::deleteTodo()
00873 {
00874 if (mActiveItem) {
00875 emit deleteIncidenceSignal( mActiveItem->todo() );
00876 }
00877 }
00878
00879 void KOTodoView::setNewPriority(int index)
00880 {
00881 if ( !mActiveItem || !mChanger ) return;
00882 Todo *todo = mActiveItem->todo();
00883 if ( !todo->isReadOnly () &&
00884 mChanger->beginChange( todo, 0, QString() ) ) {
00885 Todo *oldTodo = todo->clone();
00886 todo->setPriority(mPriority[index]);
00887 mActiveItem->construct();
00888
00889 mChanger->changeIncidence( oldTodo, todo, KOGlobals::PRIORITY_MODIFIED, this );
00890 mChanger->endChange( todo, 0, QString() );
00891 delete oldTodo;
00892 }
00893 }
00894
00895 void KOTodoView::setNewPercentage( KOTodoViewItem *item, int percentage )
00896 {
00897 kdDebug(5850) << "KOTodoView::setNewPercentage( " << percentage << "), item = " << item << endl;
00898 if ( !item || !mChanger ) return;
00899 Todo *todo = item->todo();
00900 if ( !todo ) return;
00901
00902 if ( !todo->isReadOnly () &&
00903 mChanger->beginChange( todo, 0, QString() ) ) {
00904 Todo *oldTodo = todo->clone();
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914 if ( percentage == 100 ) {
00915 todo->setCompleted( QDateTime::currentDateTime() );
00916
00917
00918 if ( !todo->isCompleted() ) item->setState( QCheckListItem::Off );
00919 else todo->setPercentComplete( percentage );
00920 } else {
00921 todo->setCompleted( false );
00922 todo->setPercentComplete( percentage );
00923 }
00924 item->construct();
00925 if ( todo->doesRecur() && percentage == 100 )
00926 mChanger->changeIncidence( oldTodo, todo,
00927 KOGlobals::COMPLETION_MODIFIED_WITH_RECURRENCE, this );
00928 else
00929 mChanger->changeIncidence( oldTodo, todo,
00930 KOGlobals::COMPLETION_MODIFIED, this );
00931 mChanger->endChange( todo, 0, QString() );
00932 delete oldTodo;
00933 } else {
00934 item->construct();
00935 kdDebug(5850) << "No active item, active item is read-only, or locking failed" << endl;
00936 }
00937 }
00938
00939 void KOTodoView::setNewPercentage( int index )
00940 {
00941 setNewPercentage( mActiveItem, mPercentage[index] );
00942 }
00943
00944 void KOTodoView::setNewDate( QDate date )
00945 {
00946 if ( !mActiveItem || !mChanger ) return;
00947 Todo *todo = mActiveItem->todo();
00948 if ( !todo ) return;
00949
00950 if ( !todo->isReadOnly() && mChanger->beginChange( todo, 0, QString() ) ) {
00951 Todo *oldTodo = todo->clone();
00952
00953 QDateTime dt;
00954 dt.setDate( date );
00955
00956 if ( !todo->doesFloat() )
00957 dt.setTime( todo->dtDue().time() );
00958
00959 if ( date.isNull() )
00960 todo->setHasDueDate( false );
00961 else if ( !todo->hasDueDate() )
00962 todo->setHasDueDate( true );
00963 todo->setDtDue( dt );
00964
00965 mActiveItem->construct();
00966 mChanger->changeIncidence( oldTodo, todo, KOGlobals::COMPLETION_MODIFIED, this );
00967 mChanger->endChange( todo, 0, QString() );
00968 delete oldTodo;
00969 } else {
00970 kdDebug(5850) << "No active item, active item is read-only, or locking failed" << endl;
00971 }
00972 }
00973
00974 void KOTodoView::copyTodoToDate( QDate date )
00975 {
00976 QDateTime dt( date );
00977
00978 if ( mActiveItem && mChanger ) {
00979 Todo *newTodo = mActiveItem->todo()->clone();
00980 newTodo->recreate();
00981
00982 newTodo->setHasDueDate( !date.isNull() );
00983 newTodo->setDtDue( dt );
00984 newTodo->setPercentComplete( 0 );
00985
00986
00987 if ( newTodo->doesRecur() )
00988 newTodo->recurrence()->unsetRecurs();
00989
00990 QPair<ResourceCalendar *, QString>p =
00991 CalHelper::incSubResourceCalendar( calendar(), mActiveItem->todo() );
00992
00993 mChanger->addIncidence( newTodo, p.first, p.second, this );
00994 }
00995 }
00996
00997 QPopupMenu *KOTodoView::getCategoryPopupMenu( KOTodoViewItem *todoItem )
00998 {
00999 QPopupMenu *tempMenu = new QPopupMenu( this );
01000 QStringList checkedCategories = todoItem->todo()->categories();
01001
01002 tempMenu->setCheckable( true );
01003 QStringList::Iterator it;
01004 for ( it = KOPrefs::instance()->mCustomCategories.begin();
01005 it != KOPrefs::instance()->mCustomCategories.end();
01006 ++it ) {
01007 int index = tempMenu->insertItem( *it );
01008 mCategory[ index ] = *it;
01009 if ( checkedCategories.find( *it ) != checkedCategories.end() )
01010 tempMenu->setItemChecked( index, true );
01011 }
01012
01013 connect ( tempMenu, SIGNAL( activated( int ) ),
01014 SLOT( changedCategories( int ) ) );
01015 return tempMenu;
01016 }
01017
01018 void KOTodoView::changedCategories(int index)
01019 {
01020 if ( !mActiveItem || !mChanger ) return;
01021 Todo *todo = mActiveItem->todo();
01022 if ( !todo ) return;
01023
01024 if ( !todo->isReadOnly() && mChanger->beginChange( todo, 0, QString() ) ) {
01025 Todo *oldTodo = todo->clone();
01026
01027 QStringList categories = todo->categories ();
01028 if ( categories.find( mCategory[index] ) != categories.end() )
01029 categories.remove( mCategory[index] );
01030 else
01031 categories.insert( categories.end(), mCategory[index] );
01032 categories.sort();
01033 todo->setCategories( categories );
01034 mActiveItem->construct();
01035 mChanger->changeIncidence( oldTodo, todo, KOGlobals::CATEGORY_MODIFIED, this );
01036 mChanger->endChange( todo, 0, QString() );
01037 delete oldTodo;
01038 } else {
01039 kdDebug(5850) << "No active item, active item is read-only, or locking failed" << endl;
01040 }
01041 }
01042
01043 void KOTodoView::setDocumentId( const QString &id )
01044 {
01045 kdDebug(5850) << "KOTodoView::setDocumentId()" << endl;
01046
01047 mDocPrefs->setDoc( id );
01048 }
01049
01050 void KOTodoView::itemStateChanged( QListViewItem *item )
01051 {
01052 if (!item) return;
01053
01054 KOTodoViewItem *todoItem = (KOTodoViewItem *)item;
01055
01056
01057
01058 if( mDocPrefs ) mDocPrefs->writeEntry( todoItem->todo()->uid(), todoItem->isOpen() );
01059 }
01060
01061 void KOTodoView::setNewPercentageDelayed( KOTodoViewItem *item, int percentage )
01062 {
01063 mPercentChangedMap.append( qMakePair( item, percentage ) );
01064
01065 QTimer::singleShot( 0, this, SLOT( processDelayedNewPercentage() ) );
01066 }
01067
01068 void KOTodoView::processDelayedNewPercentage()
01069 {
01070 QValueList< QPair< KOTodoViewItem *, int> >::Iterator it;
01071 for ( it = mPercentChangedMap.begin(); it != mPercentChangedMap.end(); ++it )
01072 setNewPercentage( (*it).first, (*it).second );
01073
01074 mPercentChangedMap.clear();
01075 }
01076
01077 void KOTodoView::saveLayout(KConfig *config, const QString &group) const
01078 {
01079 mTodoListView->saveLayout(config,group);
01080 }
01081
01082 void KOTodoView::restoreLayout(KConfig *config, const QString &group)
01083 {
01084 mTodoListView->restoreLayout(config,group);
01085 }
01086
01087 void KOTodoView::processSelectionChange()
01088 {
01089
01090
01091 KOTodoViewItem *item =
01092 static_cast<KOTodoViewItem *>( mTodoListView->selectedItem() );
01093
01094 if ( !item ) {
01095 emit incidenceSelected( 0, QDate() );
01096 } else {
01097 if ( selectedDates().isEmpty() ) {
01098 emit incidenceSelected( item->todo(), QDate() );
01099 } else {
01100 emit incidenceSelected( item->todo(), selectedDates().first() );
01101 }
01102 }
01103 }
01104
01105 void KOTodoView::clearSelection()
01106 {
01107 mTodoListView->selectAll( false );
01108 }
01109
01110 void KOTodoView::purgeCompleted()
01111 {
01112 emit purgeCompletedSignal();
01113 }
01114
01115 void KOTodoView::addQuickTodo()
01116 {
01117 if ( ! mQuickAdd->text().stripWhiteSpace().isEmpty() ) {
01118 Todo *todo = new Todo();
01119 todo->setSummary( mQuickAdd->text() );
01120 todo->setOrganizer( Person( KOPrefs::instance()->fullName(),
01121 KOPrefs::instance()->email() ) );
01122 if ( !mChanger->addIncidence( todo, 0, QString(), this ) ) {
01123 delete todo;
01124 return;
01125 }
01126 mQuickAdd->setText( QString::null );
01127 }
01128 }
01129
01130 void KOTodoView::setIncidenceChanger( IncidenceChangerBase *changer )
01131 {
01132 mChanger = changer;
01133 mTodoListView->setIncidenceChanger( changer );
01134 }