-rw-r--r-- | korganizer/kotodoview.cpp | 1028 |
1 files changed, 1028 insertions, 0 deletions
diff --git a/korganizer/kotodoview.cpp b/korganizer/kotodoview.cpp new file mode 100644 index 0000000..0708a69 --- a/dev/null +++ b/korganizer/kotodoview.cpp | |||
@@ -0,0 +1,1028 @@ | |||
1 | /* | ||
2 | This file is part of KOrganizer. | ||
3 | Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | |||
19 | As a special exception, permission is given to link this program | ||
20 | with any edition of Qt, and distribute the resulting executable, | ||
21 | without including the source code for Qt in the source distribution. | ||
22 | */ | ||
23 | |||
24 | #include <qlayout.h> | ||
25 | #include <qheader.h> | ||
26 | #include <qcursor.h> | ||
27 | |||
28 | #include <qvbox.h> | ||
29 | #include <kdebug.h> | ||
30 | #include "koprefs.h" | ||
31 | #include <klocale.h> | ||
32 | #include <kglobal.h> | ||
33 | #include <kiconloader.h> | ||
34 | #include <kmessagebox.h> | ||
35 | |||
36 | #include <libkcal/icaldrag.h> | ||
37 | #include <libkcal/vcaldrag.h> | ||
38 | #include <libkcal/calfilter.h> | ||
39 | #include <libkcal/dndfactory.h> | ||
40 | #include <libkcal/calendarresources.h> | ||
41 | #include <libkcal/resourcecalendar.h> | ||
42 | #include <kresources/resourceselectdialog.h> | ||
43 | #ifndef DESKTOP_VERSION | ||
44 | #include <qpe/qpeapplication.h> | ||
45 | #else | ||
46 | #include <qapplication.h> | ||
47 | #endif | ||
48 | #ifndef KORG_NOPRINTER | ||
49 | #include "calprinter.h" | ||
50 | #endif | ||
51 | #include "docprefs.h" | ||
52 | |||
53 | #include "kotodoview.h" | ||
54 | using namespace KOrg; | ||
55 | #include "kotodoview.moc" | ||
56 | |||
57 | KOTodoListView::KOTodoListView(Calendar *calendar,QWidget *parent, | ||
58 | const char *name) : | ||
59 | KListView(parent,name) | ||
60 | { | ||
61 | mCalendar = calendar; | ||
62 | #ifndef DESKTOP_VERSION | ||
63 | QPEApplication::setStylusOperation(viewport(), QPEApplication::RightOnHold ); | ||
64 | #endif | ||
65 | mOldCurrent = 0; | ||
66 | mMousePressed = false; | ||
67 | |||
68 | setAcceptDrops(true); | ||
69 | viewport()->setAcceptDrops(true); | ||
70 | int size = 16; | ||
71 | if (qApp->desktop()->width() < 300 ) | ||
72 | size = 12; | ||
73 | setTreeStepSize( size + 6 ); | ||
74 | |||
75 | } | ||
76 | |||
77 | void KOTodoListView::contentsDragEnterEvent(QDragEnterEvent *e) | ||
78 | { | ||
79 | #ifndef KORG_NODND | ||
80 | // kdDebug() << "KOTodoListView::contentsDragEnterEvent" << endl; | ||
81 | if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) && | ||
82 | !QTextDrag::canDecode( e ) ) { | ||
83 | e->ignore(); | ||
84 | return; | ||
85 | } | ||
86 | |||
87 | mOldCurrent = currentItem(); | ||
88 | #endif | ||
89 | } | ||
90 | |||
91 | |||
92 | void KOTodoListView::contentsDragMoveEvent(QDragMoveEvent *e) | ||
93 | { | ||
94 | #ifndef KORG_NODND | ||
95 | // kdDebug() << "KOTodoListView::contentsDragMoveEvent" << endl; | ||
96 | |||
97 | if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) && | ||
98 | !QTextDrag::canDecode( e ) ) { | ||
99 | e->ignore(); | ||
100 | return; | ||
101 | } | ||
102 | |||
103 | e->accept(); | ||
104 | #endif | ||
105 | } | ||
106 | |||
107 | void KOTodoListView::contentsDragLeaveEvent(QDragLeaveEvent *) | ||
108 | { | ||
109 | #ifndef KORG_NODND | ||
110 | // kdDebug() << "KOTodoListView::contentsDragLeaveEvent" << endl; | ||
111 | |||
112 | setCurrentItem(mOldCurrent); | ||
113 | setSelected(mOldCurrent,true); | ||
114 | #endif | ||
115 | } | ||
116 | |||
117 | void KOTodoListView::contentsDropEvent(QDropEvent *e) | ||
118 | { | ||
119 | #ifndef KORG_NODND | ||
120 | // kdDebug() << "KOTodoListView::contentsDropEvent" << endl; | ||
121 | |||
122 | if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) && | ||
123 | !QTextDrag::canDecode( e ) ) { | ||
124 | e->ignore(); | ||
125 | return; | ||
126 | } | ||
127 | |||
128 | DndFactory factory( mCalendar ); | ||
129 | Todo *todo = factory.createDropTodo(e); | ||
130 | |||
131 | if (todo) { | ||
132 | e->acceptAction(); | ||
133 | |||
134 | KOTodoViewItem *destination = | ||
135 | (KOTodoViewItem *)itemAt(contentsToViewport(e->pos())); | ||
136 | Todo *destinationEvent = 0; | ||
137 | if (destination) destinationEvent = destination->todo(); | ||
138 | |||
139 | Todo *existingTodo = mCalendar->todo(todo->uid()); | ||
140 | |||
141 | if(existingTodo) { | ||
142 | // kdDebug() << "Drop existing Todo" << endl; | ||
143 | Incidence *to = destinationEvent; | ||
144 | while(to) { | ||
145 | if (to->uid() == todo->uid()) { | ||
146 | KMessageBox::sorry(this, | ||
147 | i18n("Cannot move To-Do to itself or a child of itself"), | ||
148 | i18n("Drop To-Do")); | ||
149 | delete todo; | ||
150 | return; | ||
151 | } | ||
152 | to = to->relatedTo(); | ||
153 | } | ||
154 | existingTodo->setRelatedTo(destinationEvent); | ||
155 | emit todoDropped(todo); | ||
156 | delete todo; | ||
157 | } else { | ||
158 | // kdDebug() << "Drop new Todo" << endl; | ||
159 | todo->setRelatedTo(destinationEvent); | ||
160 | mCalendar->addTodo(todo); | ||
161 | |||
162 | emit todoDropped(todo); | ||
163 | } | ||
164 | } | ||
165 | else { | ||
166 | QString text; | ||
167 | if (QTextDrag::decode(e,text)) { | ||
168 | //QListViewItem *qlvi = itemAt( contentsToViewport(e->pos()) ); | ||
169 | KOTodoViewItem *todoi = static_cast<KOTodoViewItem *>(itemAt( contentsToViewport(e->pos()) )); | ||
170 | kdDebug() << "Dropped : " << text << endl; | ||
171 | QStringList emails = QStringList::split(",",text); | ||
172 | for(QStringList::ConstIterator it = emails.begin();it!=emails.end();++it) { | ||
173 | kdDebug() << " Email: " << (*it) << endl; | ||
174 | int pos = (*it).find("<"); | ||
175 | QString name = (*it).left(pos); | ||
176 | QString email = (*it).mid(pos); | ||
177 | if (!email.isEmpty() && todoi) { | ||
178 | todoi->todo()->addAttendee(new Attendee(name,email)); | ||
179 | } | ||
180 | } | ||
181 | } | ||
182 | else { | ||
183 | kdDebug() << "KOTodoListView::contentsDropEvent(): Todo from drop not decodable" << endl; | ||
184 | e->ignore(); | ||
185 | } | ||
186 | } | ||
187 | #endif | ||
188 | } | ||
189 | |||
190 | void KOTodoListView::contentsMousePressEvent(QMouseEvent* e) | ||
191 | { | ||
192 | QListView::contentsMousePressEvent(e); | ||
193 | #ifndef KORG_NODND | ||
194 | QPoint p(contentsToViewport(e->pos())); | ||
195 | QListViewItem *i = itemAt(p); | ||
196 | if (i) { | ||
197 | // if the user clicked into the root decoration of the item, don't | ||
198 | // try to start a drag! | ||
199 | if (p.x() > header()->sectionPos(header()->mapToIndex(0)) + | ||
200 | treeStepSize() * (i->depth() + (rootIsDecorated() ? 1 : 0)) + | ||
201 | itemMargin() || | ||
202 | p.x() < header()->sectionPos(header()->mapToIndex(0))) { | ||
203 | if (e->button()==Qt::LeftButton) { | ||
204 | mPressPos = e->pos(); | ||
205 | mMousePressed = true; | ||
206 | } | ||
207 | } | ||
208 | } | ||
209 | #endif | ||
210 | } | ||
211 | |||
212 | void KOTodoListView::contentsMouseMoveEvent(QMouseEvent* e) | ||
213 | { | ||
214 | #ifndef KORG_NODND | ||
215 | // kdDebug() << "KOTodoListView::contentsMouseMoveEvent()" << endl; | ||
216 | QListView::contentsMouseMoveEvent(e); | ||
217 | if (mMousePressed && (mPressPos - e->pos()).manhattanLength() > | ||
218 | QApplication::startDragDistance()) { | ||
219 | mMousePressed = false; | ||
220 | QListViewItem *item = itemAt(contentsToViewport(mPressPos)); | ||
221 | if (item) { | ||
222 | // kdDebug() << "Start Drag for item " << item->text(0) << endl; | ||
223 | DndFactory factory( mCalendar ); | ||
224 | ICalDrag *vd = factory.createDragTodo( | ||
225 | ((KOTodoViewItem *)item)->todo(),viewport()); | ||
226 | if (vd->drag()) { | ||
227 | kdDebug() << "KOTodoListView::contentsMouseMoveEvent(): Delete drag source" << endl; | ||
228 | } | ||
229 | /* | ||
230 | QString source = fullPath(item); | ||
231 | if ( QFile::exists(source) ) { | ||
232 | QUriDrag* ud = new QUriDrag(viewport()); | ||
233 | ud->setFilenames( source ); | ||
234 | if ( ud->drag() ) | ||
235 | QMessageBox::information( this, "Drag source", | ||
236 | QString("Delete ")+source, "Not implemented" ); | ||
237 | */ | ||
238 | } | ||
239 | } | ||
240 | #endif | ||
241 | } | ||
242 | void KOTodoListView::keyPressEvent ( QKeyEvent * e ) | ||
243 | { | ||
244 | |||
245 | QListViewItem* cn; | ||
246 | if ( e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter ) { | ||
247 | cn = currentItem(); | ||
248 | if ( cn ) { | ||
249 | KOTodoViewItem* ci = (KOTodoViewItem*)( cn ); | ||
250 | if ( ci ){ | ||
251 | if ( e->state() == ShiftButton ) | ||
252 | ci->setOn( false ); | ||
253 | else | ||
254 | ci->setOn( true ); | ||
255 | cn = cn->nextSibling(); | ||
256 | if ( cn ) { | ||
257 | setCurrentItem ( cn ); | ||
258 | ensureItemVisible ( cn ); | ||
259 | } | ||
260 | |||
261 | } | ||
262 | } | ||
263 | |||
264 | return; | ||
265 | } | ||
266 | |||
267 | // qDebug("KOTodoListView::keyPressEvent "); | ||
268 | if ( e->state() == Qt::ControlButton || e->state() == Qt::ShiftButton || ( height() > 150 && width() > 200 ) ) { | ||
269 | switch ( e->key() ) { | ||
270 | case Qt::Key_Down: | ||
271 | case Qt::Key_Up: | ||
272 | QListView::keyPressEvent ( e ); | ||
273 | break; | ||
274 | default: | ||
275 | e->ignore(); | ||
276 | break; | ||
277 | } | ||
278 | return; | ||
279 | } | ||
280 | e->ignore(); | ||
281 | } | ||
282 | void KOTodoListView::contentsMouseReleaseEvent(QMouseEvent *e) | ||
283 | { | ||
284 | QListView::contentsMouseReleaseEvent(e); | ||
285 | mMousePressed = false; | ||
286 | } | ||
287 | |||
288 | void KOTodoListView::contentsMouseDoubleClickEvent(QMouseEvent *e) | ||
289 | { | ||
290 | if (!e) return; | ||
291 | |||
292 | QPoint vp = contentsToViewport(e->pos()); | ||
293 | |||
294 | QListViewItem *item = itemAt(vp); | ||
295 | |||
296 | emit double_Clicked(item); | ||
297 | if (!item) return; | ||
298 | |||
299 | emit doubleClicked(item,vp,0); | ||
300 | } | ||
301 | |||
302 | ///////////////////////////////////////////////////////////////////////////// | ||
303 | |||
304 | KOQuickTodo::KOQuickTodo(QWidget *parent) : | ||
305 | QLineEdit(parent) | ||
306 | { | ||
307 | setText(i18n("Click to add a new Todo")); | ||
308 | } | ||
309 | |||
310 | void KOQuickTodo::focusInEvent(QFocusEvent *ev) | ||
311 | { | ||
312 | if ( text()==i18n("Click to add a new Todo") ) | ||
313 | setText(""); | ||
314 | QLineEdit::focusInEvent(ev); | ||
315 | } | ||
316 | |||
317 | void KOQuickTodo::focusOutEvent(QFocusEvent *ev) | ||
318 | { | ||
319 | setText(i18n("Click to add a new Todo")); | ||
320 | QLineEdit::focusOutEvent(ev); | ||
321 | } | ||
322 | |||
323 | ///////////////////////////////////////////////////////////////////////////// | ||
324 | |||
325 | KOTodoView::KOTodoView(Calendar *calendar,QWidget* parent,const char* name) : | ||
326 | KOrg::BaseView(calendar,parent,name) | ||
327 | { | ||
328 | QBoxLayout *topLayout = new QVBoxLayout(this); | ||
329 | mName = QString ( name ); | ||
330 | mBlockUpdate = false; | ||
331 | mQuickAdd = new KOQuickTodo(this); | ||
332 | topLayout->addWidget(mQuickAdd); | ||
333 | |||
334 | if ( !KOPrefs::instance()->mEnableQuickTodo ) mQuickAdd->hide(); | ||
335 | |||
336 | mTodoListView = new KOTodoListView(calendar,this); | ||
337 | topLayout->addWidget(mTodoListView); | ||
338 | //mTodoListView->header()->setMaximumHeight(30); | ||
339 | mTodoListView->setRootIsDecorated(true); | ||
340 | mTodoListView->setAllColumnsShowFocus(true); | ||
341 | |||
342 | mTodoListView->setShowSortIndicator(true); | ||
343 | |||
344 | mTodoListView->addColumn(i18n("Todo")); | ||
345 | mTodoListView->addColumn(i18n("Prio")); | ||
346 | mTodoListView->setColumnAlignment(1,AlignHCenter); | ||
347 | mTodoListView->addColumn(i18n("Complete")); | ||
348 | mTodoListView->setColumnAlignment(2,AlignHCenter); | ||
349 | mTodoListView->addColumn(i18n("Due Date")); | ||
350 | mTodoListView->setColumnAlignment(3,AlignLeft); | ||
351 | mTodoListView->addColumn(i18n("Due Time")); | ||
352 | mTodoListView->setColumnAlignment(4,AlignHCenter); | ||
353 | mTodoListView->addColumn(i18n("Cancelled")); | ||
354 | mTodoListView->addColumn(i18n("Categories")); | ||
355 | #if 0 | ||
356 | mTodoListView->addColumn(i18n("Sort Id")); | ||
357 | mTodoListView->setColumnAlignment(4,AlignHCenter); | ||
358 | #endif | ||
359 | |||
360 | mTodoListView->setMinimumHeight( 60 ); | ||
361 | mTodoListView->setItemsRenameable( true ); | ||
362 | mTodoListView->setRenameable( 0 ); | ||
363 | mTodoListView->setColumnWidth( 0, 120 ); | ||
364 | mTodoListView->setColumnWidthMode(0, QListView::Manual); | ||
365 | mTodoListView->setColumnWidthMode(1, QListView::Manual); | ||
366 | mTodoListView->setColumnWidthMode(2, QListView::Manual); | ||
367 | mTodoListView->setColumnWidthMode(3, QListView::Manual); | ||
368 | mTodoListView->setColumnWidthMode(4, QListView::Manual); | ||
369 | mTodoListView->setColumnWidthMode(5, QListView::Manual); | ||
370 | mTodoListView->setColumnAlignment( 2, AlignCenter ); | ||
371 | #if 0 | ||
372 | mTodoListView->setColumnWidthMode(6, QListView::Manual); | ||
373 | #endif | ||
374 | |||
375 | mPriorityPopupMenu = new QPopupMenu(this); | ||
376 | for (int i = 1; i <= 5; i++) { | ||
377 | QString label = QString ("%1").arg (i); | ||
378 | mPriority[mPriorityPopupMenu->insertItem (label)] = i; | ||
379 | } | ||
380 | connect (mPriorityPopupMenu, SIGNAL(activated (int)), SLOT (setNewPriority(int))); | ||
381 | |||
382 | mPercentageCompletedPopupMenu = new QPopupMenu(this); | ||
383 | for (int i = 0; i <= 100; i+=20) { | ||
384 | QString label = QString ("%1 %").arg (i); | ||
385 | mPercentage[mPercentageCompletedPopupMenu->insertItem (label)] = i; | ||
386 | } | ||
387 | connect (mPercentageCompletedPopupMenu, SIGNAL (activated (int)), SLOT (setNewPercentage (int))); | ||
388 | |||
389 | |||
390 | |||
391 | mItemPopupMenu = new QPopupMenu(this); | ||
392 | mItemPopupMenu->insertItem(i18n("Show..."), this, | ||
393 | SLOT (showTodo())); | ||
394 | mItemPopupMenu->insertItem(i18n("Edit..."), this, | ||
395 | SLOT (editTodo())); | ||
396 | mItemPopupMenu->insertItem( i18n("Delete"), this, | ||
397 | SLOT (deleteTodo())); | ||
398 | mItemPopupMenu->insertItem( i18n("Clone..."), this, | ||
399 | SLOT (cloneTodo())); | ||
400 | mItemPopupMenu->insertItem( i18n("Move..."), this, | ||
401 | SLOT (moveTodo())); | ||
402 | mItemPopupMenu->insertItem( i18n("Beam..."), this, | ||
403 | SLOT (beamTodo())); | ||
404 | mItemPopupMenu->insertItem( i18n("Toggle Cancel"), this, | ||
405 | SLOT (cancelTodo())); | ||
406 | mItemPopupMenu->insertSeparator(); | ||
407 | |||
408 | mItemPopupMenu->insertItem( i18n("New Todo..."), this, | ||
409 | SLOT (newTodo())); | ||
410 | mItemPopupMenu->insertItem(i18n("New Sub-Todo..."), this, | ||
411 | SLOT (newSubTodo())); | ||
412 | mItemPopupMenu->insertItem(i18n("Unparent Todo"), this, | ||
413 | SLOT (unparentTodo())); | ||
414 | mItemPopupMenu->insertSeparator(); | ||
415 | mItemPopupMenu->insertItem(i18n("Delete completed To-Dos","Purge Completed"), | ||
416 | this, SLOT( purgeCompleted() ) ); | ||
417 | mItemPopupMenu->insertItem(i18n("toggle completed To-Dos","Show Completed"), | ||
418 | this, SLOT( toggleCompleted() ),0, 33 ); | ||
419 | mItemPopupMenu->insertItem(i18n("toggle quick todo","Show Quick Todo"), | ||
420 | this, SLOT( toggleQuickTodo() ),0, 34 ); | ||
421 | |||
422 | mPopupMenu = new QPopupMenu(this); | ||
423 | mPopupMenu->insertItem(SmallIconSet("todo"), i18n("New Todo..."), this, | ||
424 | SLOT (newTodo()),0,1); | ||
425 | mPopupMenu->insertItem(i18n("delete completed To-Dos","Purge Completed"), | ||
426 | this, SLOT(purgeCompleted()),0,2); | ||
427 | mPopupMenu->insertItem(i18n("Show Completed"), | ||
428 | this, SLOT( toggleCompleted() ),0,3 ); | ||
429 | mPopupMenu->insertItem(i18n("toggle quick todo","Show Quick Todo"), | ||
430 | this, SLOT( toggleQuickTodo() ),0,4 ); | ||
431 | mDocPrefs = new DocPrefs( name ); | ||
432 | |||
433 | mPopupMenu->setCheckable( true ); | ||
434 | mItemPopupMenu->setCheckable( true ); | ||
435 | // Double clicking conflicts with opening/closing the subtree | ||
436 | connect( mTodoListView, SIGNAL( doubleClicked( QListViewItem *) ), | ||
437 | SLOT( editItem( QListViewItem *) ) ); | ||
438 | connect( mTodoListView, SIGNAL( rightButtonClicked ( QListViewItem *, | ||
439 | const QPoint &,int ) ), | ||
440 | SLOT( popupMenu( QListViewItem *, const QPoint & ,int) ) ); | ||
441 | connect( mTodoListView, SIGNAL( clicked( QListViewItem * ) ), | ||
442 | SLOT( itemClicked( QListViewItem * ) ) ); | ||
443 | connect( mTodoListView, SIGNAL( double_Clicked( QListViewItem * ) ), | ||
444 | SLOT( itemDoubleClicked( QListViewItem * ) ) ); | ||
445 | connect( mTodoListView, SIGNAL( todoDropped( Todo * ) ), | ||
446 | SLOT( updateView() ) ); | ||
447 | connect( mTodoListView, SIGNAL( expanded( QListViewItem * ) ), | ||
448 | SLOT( itemStateChanged( QListViewItem * ) ) ); | ||
449 | connect( mTodoListView, SIGNAL( collapsed( QListViewItem * ) ), | ||
450 | SLOT( itemStateChanged( QListViewItem * ) ) ); | ||
451 | |||
452 | #if 0 | ||
453 | connect(mTodoListView,SIGNAL(selectionChanged(QListViewItem *)), | ||
454 | SLOT(selectionChanged(QListViewItem *))); | ||
455 | connect(mTodoListView,SIGNAL(clicked(QListViewItem *)), | ||
456 | SLOT(selectionChanged(QListViewItem *))); | ||
457 | connect(mTodoListView,SIGNAL(pressed(QListViewItem *)), | ||
458 | SLOT(selectionChanged(QListViewItem *))); | ||
459 | #endif | ||
460 | connect( mTodoListView, SIGNAL(selectionChanged() ), | ||
461 | SLOT( processSelectionChange() ) ); | ||
462 | connect( mQuickAdd, SIGNAL( returnPressed () ), | ||
463 | SLOT( addQuickTodo() ) ); | ||
464 | // if ( QApplication::desktop()->width() < 480 ) { | ||
465 | // setNarrow(); | ||
466 | // mTodoListView->setColumnWidth( 0, 100 ); | ||
467 | |||
468 | // } | ||
469 | |||
470 | } | ||
471 | |||
472 | KOTodoView::~KOTodoView() | ||
473 | { | ||
474 | delete mDocPrefs; | ||
475 | } | ||
476 | |||
477 | void KOTodoView::jumpToDate () | ||
478 | { | ||
479 | // if (mActiveItem) { | ||
480 | // mActiveItem->todo()); | ||
481 | // if ( mActiveItem->todo()->hasDueDate() ) | ||
482 | // emit mActiveItem->todo()jumpToTime( mTodo->dtDue().date() ); | ||
483 | } | ||
484 | |||
485 | void KOTodoView::setNarrow() | ||
486 | { | ||
487 | //mTodoListView->setColumnWidth( 0, 120 ); | ||
488 | mTodoListView->setColumnWidth( 1, 35 ); | ||
489 | mTodoListView->setColumnWidth( 2, 40 ); | ||
490 | mTodoListView->setColumnWidth( 3, 80 ); | ||
491 | mTodoListView->setColumnWidth( 4, 40 ); | ||
492 | mTodoListView->setColumnWidth( 5, 90 ); | ||
493 | |||
494 | } | ||
495 | void KOTodoView::updateView() | ||
496 | { | ||
497 | // kdDebug() << "KOTodoView::updateView()" << endl; | ||
498 | QFont fo = KOPrefs::instance()->mTodoViewFont; | ||
499 | mTodoListView->clear(); | ||
500 | if ( mName == "todolistsmall" ) { | ||
501 | if ( KOPrefs::instance()->mTodoViewUsesSmallFont ) { | ||
502 | int ps = fo.pointSize() -2; | ||
503 | if ( ps > 12 ) | ||
504 | ps -= 2; | ||
505 | fo.setPointSize( ps ); | ||
506 | } | ||
507 | } | ||
508 | |||
509 | mTodoListView->setFont( fo ); | ||
510 | // QFontMetrics fm ( KOPrefs::instance()->mTodoViewFont ); | ||
511 | //mTodoListView->header()->setMaximumHeight(fm.height()); | ||
512 | QPtrList<Todo> todoList = calendar()->todos(); | ||
513 | |||
514 | /* | ||
515 | kdDebug() << "KOTodoView::updateView(): Todo List:" << endl; | ||
516 | Event *t; | ||
517 | for(t = todoList.first(); t; t = todoList.next()) { | ||
518 | kdDebug() << " " << t->getSummary() << endl; | ||
519 | |||
520 | if (t->getRelatedTo()) { | ||
521 | kdDebug() << " (related to " << t->getRelatedTo()->getSummary() << ")" << endl; | ||
522 | } | ||
523 | |||
524 | QPtrList<Event> l = t->getRelations(); | ||
525 | Event *c; | ||
526 | for(c=l.first();c;c=l.next()) { | ||
527 | kdDebug() << " - relation: " << c->getSummary() << endl; | ||
528 | } | ||
529 | } | ||
530 | */ | ||
531 | |||
532 | // Put for each Event a KOTodoViewItem in the list view. Don't rely on a | ||
533 | // specific order of events. That means that we have to generate parent items | ||
534 | // recursively for proper hierarchical display of Todos. | ||
535 | mTodoMap.clear(); | ||
536 | Todo *todo; | ||
537 | todo = todoList.first();// todo; todo = todoList.next()) { | ||
538 | while ( todo ) { | ||
539 | bool next = true; | ||
540 | // qDebug("todo %s ", todo->summary().latin1()); | ||
541 | Incidence *incidence = todo->relatedTo(); | ||
542 | while ( incidence ) { | ||
543 | if ( incidence->type() == "Todo") { | ||
544 | //qDebug("related %s ",incidence->summary().latin1() ); | ||
545 | if ( !(todoList.contains ( ((Todo* )incidence ) ) )) { | ||
546 | //qDebug("related not found "); | ||
547 | todoList.remove( ); | ||
548 | todo = todoList.current(); | ||
549 | next = false; | ||
550 | incidence = 0; | ||
551 | |||
552 | } else { | ||
553 | //qDebug("related found "); | ||
554 | incidence = incidence->relatedTo(); | ||
555 | } | ||
556 | } else | ||
557 | incidence = 0; | ||
558 | } | ||
559 | if ( next ) | ||
560 | todo = todoList.next(); | ||
561 | } | ||
562 | // qDebug("again .... "); | ||
563 | // for(todo = todoList.first(); todo; todo = todoList.next()) { | ||
564 | |||
565 | // qDebug("yytodo %s ", todo->summary().latin1()); | ||
566 | // } | ||
567 | //qDebug("for "); | ||
568 | for(todo = todoList.first(); todo; todo = todoList.next()) { | ||
569 | if (!mTodoMap.contains(todo) && ( KOPrefs::instance()->mShowCompletedTodo || !todo->isCompleted() ) ) | ||
570 | { | ||
571 | insertTodoItem(todo); | ||
572 | } | ||
573 | } | ||
574 | //qDebug("for end "); | ||
575 | // Restore opened/closed state | ||
576 | mTodoListView->blockSignals( true ); | ||
577 | if( mDocPrefs ) restoreItemState( mTodoListView->firstChild() ); | ||
578 | mTodoListView->blockSignals( false ); | ||
579 | mTodoListView->setFocus(); | ||
580 | processSelectionChange(); | ||
581 | } | ||
582 | |||
583 | void KOTodoView::restoreItemState( QListViewItem *item ) | ||
584 | { | ||
585 | while( item ) { | ||
586 | KOTodoViewItem *todoItem = (KOTodoViewItem *)item; | ||
587 | todoItem->setOpen( mDocPrefs->readBoolEntry( todoItem->todo()->uid() ) ); | ||
588 | if( item->childCount() > 0 ) restoreItemState( item->firstChild() ); | ||
589 | item = item->nextSibling(); | ||
590 | } | ||
591 | } | ||
592 | |||
593 | |||
594 | QMap<Todo *,KOTodoViewItem *>::ConstIterator | ||
595 | KOTodoView::insertTodoItem(Todo *todo) | ||
596 | { | ||
597 | // kdDebug() << "KOTodoView::insertTodoItem(): " << todo->getSummary() << endl; | ||
598 | // TODO: Check, if dynmaic cast is necessary | ||
599 | |||
600 | |||
601 | Incidence *incidence = todo->relatedTo(); | ||
602 | if (incidence && incidence->type() == "Todo") { | ||
603 | Todo *relatedTodo = static_cast<Todo *>(incidence); | ||
604 | |||
605 | // kdDebug() << " has Related" << endl; | ||
606 | QMap<Todo *,KOTodoViewItem *>::ConstIterator itemIterator; | ||
607 | itemIterator = mTodoMap.find(relatedTodo); | ||
608 | if (itemIterator == mTodoMap.end()) { | ||
609 | // kdDebug() << " related not yet in list" << endl; | ||
610 | itemIterator = insertTodoItem (relatedTodo); | ||
611 | } | ||
612 | // isn't this pretty stupid? We give one Todo to the KOTodoViewItem | ||
613 | // and one into the map. Sure finding is more easy but why? -zecke | ||
614 | KOTodoViewItem *todoItem = new KOTodoViewItem(*itemIterator,todo,this); | ||
615 | return mTodoMap.insert(todo,todoItem); | ||
616 | } else { | ||
617 | // kdDebug() << " no Related" << endl; | ||
618 | // see above -zecke | ||
619 | KOTodoViewItem *todoItem = new KOTodoViewItem(mTodoListView,todo,this); | ||
620 | return mTodoMap.insert(todo,todoItem); | ||
621 | } | ||
622 | } | ||
623 | |||
624 | |||
625 | void KOTodoView::updateConfig() | ||
626 | { | ||
627 | updateView(); | ||
628 | mTodoListView->repaintContents(); | ||
629 | } | ||
630 | |||
631 | QPtrList<Incidence> KOTodoView::selectedIncidences() | ||
632 | { | ||
633 | QPtrList<Incidence> selected; | ||
634 | |||
635 | KOTodoViewItem *item = (KOTodoViewItem *)(mTodoListView->selectedItem()); | ||
636 | // if (!item) item = mActiveItem; | ||
637 | if (item) selected.append(item->todo()); | ||
638 | |||
639 | return selected; | ||
640 | } | ||
641 | |||
642 | QPtrList<Todo> KOTodoView::selectedTodos() | ||
643 | { | ||
644 | QPtrList<Todo> selected; | ||
645 | |||
646 | KOTodoViewItem *item = (KOTodoViewItem *)(mTodoListView->selectedItem()); | ||
647 | // if (!item) item = mActiveItem; | ||
648 | if (item) selected.append(item->todo()); | ||
649 | |||
650 | return selected; | ||
651 | } | ||
652 | |||
653 | void KOTodoView::changeEventDisplay(Event *, int) | ||
654 | { | ||
655 | updateView(); | ||
656 | } | ||
657 | |||
658 | void KOTodoView::showDates(const QDate &, const QDate &) | ||
659 | { | ||
660 | } | ||
661 | |||
662 | void KOTodoView::showEvents(QPtrList<Event>) | ||
663 | { | ||
664 | kdDebug() << "KOTodoView::selectEvents(): not yet implemented" << endl; | ||
665 | } | ||
666 | |||
667 | void KOTodoView::printPreview(CalPrinter *calPrinter, const QDate &fd, | ||
668 | const QDate &td) | ||
669 | { | ||
670 | #ifndef KORG_NOPRINTER | ||
671 | calPrinter->preview(CalPrinter::Todolist, fd, td); | ||
672 | #endif | ||
673 | } | ||
674 | |||
675 | void KOTodoView::editItem(QListViewItem *item ) | ||
676 | { | ||
677 | // qDebug("editItem(QListViewItem *item ) "); | ||
678 | emit editTodoSignal(((KOTodoViewItem *)item)->todo()); | ||
679 | } | ||
680 | |||
681 | void KOTodoView::showItem(QListViewItem *item,const QPoint &,int) | ||
682 | { | ||
683 | emit showTodoSignal(((KOTodoViewItem *)item)->todo()); | ||
684 | } | ||
685 | |||
686 | void KOTodoView::popupMenu(QListViewItem *item,const QPoint &,int column) | ||
687 | { | ||
688 | |||
689 | mActiveItem = (KOTodoViewItem *)item; | ||
690 | if (item) { | ||
691 | switch (column){ | ||
692 | case 1: | ||
693 | mPriorityPopupMenu->popup(QCursor::pos ()); break; | ||
694 | case 2: | ||
695 | mPercentageCompletedPopupMenu->popup(QCursor::pos ()); break; | ||
696 | case 3: | ||
697 | moveTodo(); | ||
698 | break; | ||
699 | case 6: | ||
700 | getCategoryPopupMenu((KOTodoViewItem *)item)->popup(QCursor::pos ()); break; | ||
701 | default: | ||
702 | mItemPopupMenu->popup(QCursor::pos()); | ||
703 | } | ||
704 | } else mPopupMenu->popup(QCursor::pos()); | ||
705 | } | ||
706 | void KOTodoView::newTodo() | ||
707 | { | ||
708 | emit newTodoSignal(); | ||
709 | } | ||
710 | |||
711 | void KOTodoView::newSubTodo() | ||
712 | { | ||
713 | if (mActiveItem) { | ||
714 | emit newSubTodoSignal(mActiveItem->todo()); | ||
715 | } | ||
716 | } | ||
717 | void KOTodoView::unparentTodo() | ||
718 | { | ||
719 | if (mActiveItem) { | ||
720 | emit unparentTodoSignal(mActiveItem->todo()); | ||
721 | } | ||
722 | } | ||
723 | void KOTodoView::editTodo() | ||
724 | { | ||
725 | if (mActiveItem) { | ||
726 | emit editTodoSignal(mActiveItem->todo()); | ||
727 | } | ||
728 | } | ||
729 | void KOTodoView::cloneTodo() | ||
730 | { | ||
731 | if (mActiveItem) { | ||
732 | emit cloneTodoSignal((Incidence*)mActiveItem->todo()); | ||
733 | } | ||
734 | } | ||
735 | void KOTodoView::cancelTodo() | ||
736 | { | ||
737 | if (mActiveItem) { | ||
738 | emit cancelTodoSignal((Incidence*)mActiveItem->todo()); | ||
739 | } | ||
740 | } | ||
741 | void KOTodoView::moveTodo() | ||
742 | { | ||
743 | if (mActiveItem) { | ||
744 | emit moveTodoSignal((Incidence*)mActiveItem->todo()); | ||
745 | } | ||
746 | } | ||
747 | void KOTodoView::beamTodo() | ||
748 | { | ||
749 | if (mActiveItem) { | ||
750 | emit beamTodoSignal((Incidence*)mActiveItem->todo()); | ||
751 | } | ||
752 | } | ||
753 | |||
754 | |||
755 | void KOTodoView::showTodo() | ||
756 | { | ||
757 | if (mActiveItem) { | ||
758 | emit showTodoSignal(mActiveItem->todo()); | ||
759 | } | ||
760 | } | ||
761 | |||
762 | void KOTodoView::deleteTodo() | ||
763 | { | ||
764 | if (mActiveItem) { | ||
765 | if (mActiveItem->childCount()) { | ||
766 | KMessageBox::sorry(this,i18n("Cannot delete To-Do which has children."), | ||
767 | i18n("Delete To-Do")); | ||
768 | } else { | ||
769 | emit deleteTodoSignal(mActiveItem->todo()); | ||
770 | } | ||
771 | } | ||
772 | } | ||
773 | |||
774 | void KOTodoView::setNewPriority(int index) | ||
775 | { | ||
776 | if (mActiveItem && !mActiveItem->todo()->isReadOnly ()) { | ||
777 | mActiveItem->todo()->setPriority(mPriority[index]); | ||
778 | mActiveItem->construct(); | ||
779 | todoModified (mActiveItem->todo(), KOGlobals::PRIORITY_MODIFIED); | ||
780 | mActiveItem->todo()->setRevision( mActiveItem->todo()->revision()+1 ); | ||
781 | } | ||
782 | } | ||
783 | |||
784 | void KOTodoView::setNewPercentage(int index) | ||
785 | { | ||
786 | if (mActiveItem && !mActiveItem->todo()->isReadOnly ()) { | ||
787 | if (mPercentage[index] == 100) { | ||
788 | mActiveItem->todo()->setCompleted(QDateTime::currentDateTime()); | ||
789 | } else { | ||
790 | mActiveItem->todo()->setCompleted(false); | ||
791 | } | ||
792 | mActiveItem->todo()->setPercentComplete(mPercentage[index]); | ||
793 | mActiveItem->construct(); | ||
794 | todoModified (mActiveItem->todo (), KOGlobals::COMPLETION_MODIFIED); | ||
795 | mActiveItem->todo()->setRevision( mActiveItem->todo()->revision()+1 ); | ||
796 | } | ||
797 | } | ||
798 | |||
799 | |||
800 | QPopupMenu * KOTodoView::getCategoryPopupMenu (KOTodoViewItem *todoItem) | ||
801 | { | ||
802 | QPopupMenu* tempMenu = new QPopupMenu (this); | ||
803 | QStringList checkedCategories = todoItem->todo()->categories (); | ||
804 | |||
805 | tempMenu->setCheckable (true); | ||
806 | for (QStringList::Iterator it = KOPrefs::instance()->mCustomCategories.begin (); | ||
807 | it != KOPrefs::instance()->mCustomCategories.end (); | ||
808 | ++it) { | ||
809 | int index = tempMenu->insertItem (*it); | ||
810 | mCategory[index] = *it; | ||
811 | if (checkedCategories.find (*it) != checkedCategories.end ()) tempMenu->setItemChecked (index, true); | ||
812 | } | ||
813 | |||
814 | connect (tempMenu, SIGNAL (activated (int)), SLOT (changedCategories (int))); | ||
815 | return tempMenu; | ||
816 | |||
817 | |||
818 | } | ||
819 | void KOTodoView::changedCategories(int index) | ||
820 | { | ||
821 | if (mActiveItem && !mActiveItem->todo()->isReadOnly ()) { | ||
822 | QStringList categories = mActiveItem->todo()->categories (); | ||
823 | if (categories.find (mCategory[index]) != categories.end ()) | ||
824 | categories.remove (mCategory[index]); | ||
825 | else | ||
826 | categories.insert (categories.end(), mCategory[index]); | ||
827 | categories.sort (); | ||
828 | mActiveItem->todo()->setCategories (categories); | ||
829 | mActiveItem->construct(); | ||
830 | mActiveItem->todo()->setRevision( mActiveItem->todo()->revision()+1 ); | ||
831 | todoModified (mActiveItem->todo (), KOGlobals::CATEGORY_MODIFIED); | ||
832 | } | ||
833 | } | ||
834 | void KOTodoView::itemDoubleClicked(QListViewItem *item) | ||
835 | { | ||
836 | if (!item) { | ||
837 | newTodo(); | ||
838 | return; | ||
839 | } | ||
840 | if ( KOPrefs::instance()->mEditOnDoubleClick ) | ||
841 | editItem( item ); | ||
842 | else | ||
843 | showItem( item , QPoint(), 0 ); | ||
844 | } | ||
845 | void KOTodoView::itemClicked(QListViewItem *item) | ||
846 | { | ||
847 | if (!item) { | ||
848 | return; | ||
849 | } | ||
850 | |||
851 | KOTodoViewItem *todoItem = (KOTodoViewItem *)item; | ||
852 | int completed = todoItem->todo()->isCompleted(); // Completed or not? | ||
853 | |||
854 | if (todoItem->isOn()) { | ||
855 | if (!completed) { | ||
856 | todoItem->todo()->setCompleted(QDateTime::currentDateTime()); | ||
857 | } | ||
858 | } else { | ||
859 | if (completed) { | ||
860 | todoItem->todo()->setCompleted(false); | ||
861 | } | ||
862 | } | ||
863 | } | ||
864 | |||
865 | void KOTodoView::setDocumentId( const QString &id ) | ||
866 | { | ||
867 | kdDebug() << "KOTodoView::setDocumentId()" << endl; | ||
868 | |||
869 | mDocPrefs->setDoc( id ); | ||
870 | } | ||
871 | |||
872 | void KOTodoView::itemStateChanged( QListViewItem *item ) | ||
873 | { | ||
874 | if (!item) return; | ||
875 | |||
876 | KOTodoViewItem *todoItem = (KOTodoViewItem *)item; | ||
877 | |||
878 | // kdDebug() << "KOTodoView::itemStateChanged(): " << todoItem->todo()->summary() << endl; | ||
879 | |||
880 | if( mDocPrefs ) mDocPrefs->writeEntry( todoItem->todo()->uid(), todoItem->isOpen() ); | ||
881 | } | ||
882 | |||
883 | void KOTodoView::saveLayout(KConfig *config, const QString &group) const | ||
884 | { | ||
885 | mTodoListView->saveLayout(config,group); | ||
886 | } | ||
887 | |||
888 | void KOTodoView::restoreLayout(KConfig *config, const QString &group) | ||
889 | { | ||
890 | mTodoListView->restoreLayout(config,group); | ||
891 | } | ||
892 | |||
893 | void KOTodoView::processSelectionChange() | ||
894 | { | ||
895 | // kdDebug() << "KOTodoView::processSelectionChange()" << endl; | ||
896 | |||
897 | KOTodoViewItem *item = | ||
898 | static_cast<KOTodoViewItem *>( mTodoListView->selectedItem() ); | ||
899 | |||
900 | if ( !item ) { | ||
901 | emit incidenceSelected( 0 ); | ||
902 | } else { | ||
903 | emit incidenceSelected( item->todo() ); | ||
904 | } | ||
905 | } | ||
906 | |||
907 | void KOTodoView::modified(bool b) | ||
908 | { | ||
909 | emit isModified(b); | ||
910 | } | ||
911 | void KOTodoView::setTodoModified( Todo* todo ) | ||
912 | { | ||
913 | todoModified( todo, KOGlobals::UNKNOWN_MODIFIED ); | ||
914 | } | ||
915 | void KOTodoView::clearSelection() | ||
916 | { | ||
917 | mTodoListView->selectAll( false ); | ||
918 | } | ||
919 | |||
920 | void KOTodoView::purgeCompleted() | ||
921 | { | ||
922 | emit purgeCompletedSignal(); | ||
923 | } | ||
924 | void KOTodoView::toggleQuickTodo() | ||
925 | { | ||
926 | if ( mQuickAdd->isVisible() ) { | ||
927 | mQuickAdd->hide(); | ||
928 | KOPrefs::instance()->mEnableQuickTodo = false; | ||
929 | } | ||
930 | else { | ||
931 | mQuickAdd->show(); | ||
932 | KOPrefs::instance()->mEnableQuickTodo = true; | ||
933 | } | ||
934 | mPopupMenu->setItemChecked(4,KOPrefs::instance()->mEnableQuickTodo); | ||
935 | mItemPopupMenu->setItemChecked( 34 , KOPrefs::instance()->mEnableQuickTodo ); | ||
936 | } | ||
937 | void KOTodoView::toggleCompleted() | ||
938 | { | ||
939 | KOPrefs::instance()->mShowCompletedTodo = !KOPrefs::instance()->mShowCompletedTodo; | ||
940 | mPopupMenu->setItemChecked( 3,KOPrefs::instance()->mShowCompletedTodo ); | ||
941 | mItemPopupMenu->setItemChecked( 33 , KOPrefs::instance()->mShowCompletedTodo ); | ||
942 | updateView(); | ||
943 | } | ||
944 | |||
945 | void KOTodoView::addQuickTodo() | ||
946 | { | ||
947 | Todo *todo = new Todo(); | ||
948 | todo->setSummary(mQuickAdd->text()); | ||
949 | todo->setOrganizer(KOPrefs::instance()->email()); | ||
950 | CalFilter * cf = mCalendar->filter(); | ||
951 | if ( cf ) { | ||
952 | if ( cf->isEnabled()&& cf->showCategories()) { | ||
953 | todo->setCategories(cf->categoryList()); | ||
954 | } | ||
955 | if ( cf->isEnabled() ) | ||
956 | todo->setSecrecy( cf->getSecrecy()); | ||
957 | } | ||
958 | mCalendar->addTodo(todo); | ||
959 | mQuickAdd->setText(""); | ||
960 | todoModified (todo, KOGlobals::EVENTADDED ); | ||
961 | updateView(); | ||
962 | } | ||
963 | void KOTodoView::keyPressEvent ( QKeyEvent * e ) | ||
964 | { | ||
965 | // e->ignore(); | ||
966 | //return; | ||
967 | switch ( e->key() ) { | ||
968 | case Qt::Key_Down: | ||
969 | QWidget::keyPressEvent ( e ); | ||
970 | break; | ||
971 | |||
972 | case Qt::Key_Up: | ||
973 | QWidget::keyPressEvent ( e ); | ||
974 | break; | ||
975 | case Qt::Key_Q: | ||
976 | toggleQuickTodo(); | ||
977 | break; | ||
978 | |||
979 | default: | ||
980 | e->ignore(); | ||
981 | } | ||
982 | |||
983 | if ( e->state() == Qt::ControlButton || e->state() == Qt::ShiftButton || ( height() > 150 && width() > 200 ) ) { | ||
984 | if ( e->key() == Qt::Key_I ) { | ||
985 | KOTodoViewItem*cn = (KOTodoViewItem*)mTodoListView->currentItem(); | ||
986 | if ( cn ) { | ||
987 | mActiveItem = cn; | ||
988 | KOTodoViewItem* ci = (KOTodoViewItem*)( cn ); | ||
989 | if ( ci ){ | ||
990 | showTodo(); | ||
991 | cn = (KOTodoViewItem*)cn->itemBelow(); | ||
992 | if ( cn ) { | ||
993 | mTodoListView->setCurrentItem ( cn ); | ||
994 | mTodoListView->ensureItemVisible ( cn ); | ||
995 | } | ||
996 | |||
997 | } | ||
998 | } | ||
999 | e->accept(); | ||
1000 | |||
1001 | } | ||
1002 | |||
1003 | } | ||
1004 | |||
1005 | } | ||
1006 | void KOTodoView::updateTodo( Todo * t, int type ) | ||
1007 | { | ||
1008 | if ( mBlockUpdate) | ||
1009 | return; | ||
1010 | |||
1011 | QMap<Todo *,KOTodoViewItem *>::ConstIterator itemIterator; | ||
1012 | itemIterator = mTodoMap.find(t); | ||
1013 | if (itemIterator != mTodoMap.end()) { | ||
1014 | (*itemIterator)->construct(); | ||
1015 | } else { | ||
1016 | if ( type == KOGlobals::EVENTADDED ) { | ||
1017 | insertTodoItem( t ); | ||
1018 | } | ||
1019 | } | ||
1020 | |||
1021 | } | ||
1022 | |||
1023 | void KOTodoView::todoModified(Todo * t , int p ) | ||
1024 | { | ||
1025 | mBlockUpdate = true; | ||
1026 | emit todoModifiedSignal ( t, p ); | ||
1027 | mBlockUpdate = false; | ||
1028 | } | ||