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