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