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