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