-rw-r--r-- | core/pim/todo/todotable.cpp | 949 |
1 files changed, 0 insertions, 949 deletions
diff --git a/core/pim/todo/todotable.cpp b/core/pim/todo/todotable.cpp deleted file mode 100644 index 15f733b..0000000 --- a/core/pim/todo/todotable.cpp +++ b/dev/null | |||
@@ -1,949 +0,0 @@ | |||
1 | /********************************************************************** | ||
2 | ** Copyright (C) 2000 Trolltech AS. All rights reserved. | ||
3 | ** | ||
4 | ** This file is part of Qtopia Environment. | ||
5 | ** | ||
6 | ** This file may be distributed and/or modified under the terms of the | ||
7 | ** GNU General Public License version 2 as published by the Free Software | ||
8 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
9 | ** packaging of this file. | ||
10 | ** | ||
11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
13 | ** | ||
14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
15 | ** | ||
16 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
17 | ** not clear to you. | ||
18 | ** | ||
19 | **********************************************************************/ | ||
20 | /* Show Deadline was added by Stefan Eilers (se, eilers.stefan@epost.de) | ||
21 | */ | ||
22 | #include "todotable.h" | ||
23 | |||
24 | #include <opie/tododb.h> | ||
25 | #include <opie/xmltree.h> | ||
26 | |||
27 | #include <qpe/categoryselect.h> | ||
28 | #include <qpe/xmlreader.h> | ||
29 | |||
30 | #include <qasciidict.h> | ||
31 | #include <qcombobox.h> | ||
32 | #include <qfile.h> | ||
33 | #include <qpainter.h> | ||
34 | #include <qtextcodec.h> | ||
35 | #include <qtimer.h> | ||
36 | #include <qdatetime.h> | ||
37 | #include <qtextstream.h> | ||
38 | |||
39 | #include <qcursor.h> | ||
40 | #include <qregexp.h> | ||
41 | |||
42 | #include <errno.h> | ||
43 | #include <stdlib.h> | ||
44 | |||
45 | #include <stdio.h> | ||
46 | |||
47 | using namespace Opie; | ||
48 | |||
49 | namespace { | ||
50 | |||
51 | static bool taskCompare( const ToDoEvent &task, const QRegExp &r, int category ); | ||
52 | static QString journalFileName(); | ||
53 | static ToDoEvent xmlToEvent( XMLElement *ev ); | ||
54 | } | ||
55 | CheckItem::CheckItem( QTable *t, const QString &key ) | ||
56 | : QTableItem( t, Never, "" ), checked( FALSE ), sortKey( key ) | ||
57 | { | ||
58 | } | ||
59 | |||
60 | QString CheckItem::key() const | ||
61 | { | ||
62 | return sortKey; | ||
63 | } | ||
64 | |||
65 | void CheckItem::setChecked( bool b ) | ||
66 | { | ||
67 | checked = b; | ||
68 | table()->updateCell( row(), col() ); | ||
69 | } | ||
70 | |||
71 | void CheckItem::toggle() | ||
72 | { | ||
73 | TodoTable *parent = static_cast<TodoTable*>(table()); | ||
74 | ToDoEvent newTodo = parent->currentEntry(); | ||
75 | checked = !checked; | ||
76 | newTodo.setCompleted( checked ); | ||
77 | table()->updateCell( row(), col() ); | ||
78 | parent->replaceCurrentEntry( newTodo, true ); | ||
79 | } | ||
80 | |||
81 | bool CheckItem::isChecked() const | ||
82 | { | ||
83 | return checked; | ||
84 | } | ||
85 | |||
86 | static const int BoxSize = 10; | ||
87 | |||
88 | void CheckItem::paint( QPainter *p, const QColorGroup &cg, const QRect &cr, | ||
89 | bool ) | ||
90 | { | ||
91 | p->fillRect( 0, 0, cr.width(), cr.height(), cg.brush( QColorGroup::Base ) ); | ||
92 | |||
93 | int marg = ( cr.width() - BoxSize ) / 2; | ||
94 | int x = 0; | ||
95 | int y = ( cr.height() - BoxSize ) / 2; | ||
96 | p->setPen( QPen( cg.text() ) ); | ||
97 | p->drawRect( x + marg, y, BoxSize, BoxSize ); | ||
98 | p->drawRect( x + marg+1, y+1, BoxSize-2, BoxSize-2 ); | ||
99 | p->setPen( darkGreen ); | ||
100 | x += 1; | ||
101 | y += 1; | ||
102 | if ( checked ) { | ||
103 | QPointArray a( 7*2 ); | ||
104 | int i, xx, yy; | ||
105 | xx = x+1+marg; | ||
106 | yy = y+2; | ||
107 | for ( i=0; i<3; i++ ) { | ||
108 | a.setPoint( 2*i, xx, yy ); | ||
109 | a.setPoint( 2*i+1, xx, yy+2 ); | ||
110 | xx++; yy++; | ||
111 | } | ||
112 | yy -= 2; | ||
113 | for ( i=3; i<7; i++ ) { | ||
114 | a.setPoint( 2*i, xx, yy ); | ||
115 | a.setPoint( 2*i+1, xx, yy+2 ); | ||
116 | xx++; yy--; | ||
117 | } | ||
118 | p->drawLineSegments( a ); | ||
119 | } | ||
120 | } | ||
121 | |||
122 | |||
123 | ComboItem::ComboItem( QTable *t, EditType et ) | ||
124 | : QTableItem( t, et, "3" ), cb( 0 ) | ||
125 | { | ||
126 | setReplaceable( FALSE ); | ||
127 | } | ||
128 | |||
129 | QWidget *ComboItem::createEditor() const | ||
130 | { | ||
131 | QString txt = text(); | ||
132 | ( (ComboItem*)this )->cb = new QComboBox( table()->viewport() ); | ||
133 | cb->insertItem( "1" ); | ||
134 | cb->insertItem( "2" ); | ||
135 | cb->insertItem( "3" ); | ||
136 | cb->insertItem( "4" ); | ||
137 | cb->insertItem( "5" ); | ||
138 | cb->setCurrentItem( txt.toInt() - 1 ); | ||
139 | return cb; | ||
140 | } | ||
141 | |||
142 | void ComboItem::setContentFromEditor( QWidget *w ) | ||
143 | { | ||
144 | TodoTable *parent = static_cast<TodoTable*>(table()); | ||
145 | ToDoEvent newTodo = parent->currentEntry(); | ||
146 | |||
147 | if ( w->inherits( "QComboBox" ) ) | ||
148 | setText( ( (QComboBox*)w )->currentText() ); | ||
149 | else | ||
150 | QTableItem::setContentFromEditor( w ); | ||
151 | newTodo.setPriority( text().toInt() ); | ||
152 | parent->replaceCurrentEntry( newTodo, true ); | ||
153 | } | ||
154 | |||
155 | void ComboItem::setText( const QString &s ) | ||
156 | { | ||
157 | if ( cb ) | ||
158 | cb->setCurrentItem( s.toInt() - 1 ); | ||
159 | QTableItem::setText( s ); | ||
160 | } | ||
161 | |||
162 | QString ComboItem::text() const | ||
163 | { | ||
164 | if ( cb ) | ||
165 | return cb->currentText(); | ||
166 | return QTableItem::text(); | ||
167 | } | ||
168 | DueTextItem::DueTextItem( QTable *t, ToDoEvent *ev ) | ||
169 | : QTableItem(t, Never, QString::null ) | ||
170 | { | ||
171 | setToDoEvent( ev ); | ||
172 | } | ||
173 | QString DueTextItem::key() const | ||
174 | { | ||
175 | QString key; | ||
176 | if( m_hasDate ){ | ||
177 | if(m_off == 0 ){ | ||
178 | key.append("b"); | ||
179 | }else if( m_off > 0 ){ | ||
180 | key.append("c"); | ||
181 | }else if( m_off < 0 ){ | ||
182 | key.append("a"); | ||
183 | } | ||
184 | key.append(QString::number(m_off ) ); | ||
185 | }else{ | ||
186 | key.append("d"); | ||
187 | } | ||
188 | return key; | ||
189 | } | ||
190 | void DueTextItem::setToDoEvent( const ToDoEvent *ev ) | ||
191 | { | ||
192 | m_hasDate = ev->hasDate(); | ||
193 | m_completed = ev->isCompleted(); | ||
194 | if( ev->hasDate() ){ | ||
195 | QDate today = QDate::currentDate(); | ||
196 | m_off = today.daysTo(ev->date() ); | ||
197 | //qWarning("DueText m_off=%d", m_off ); | ||
198 | setText( QString::number(m_off) + " day(s) " ); | ||
199 | }else{ | ||
200 | setText("n.d." ); | ||
201 | m_off = 0; | ||
202 | } | ||
203 | //qWarning("m_off=%d", m_off ); | ||
204 | } | ||
205 | void DueTextItem::paint( QPainter *p, const QColorGroup &cg, const QRect &cr, bool selected ) | ||
206 | { | ||
207 | //qWarning ("paint m_off=%d", m_off ); | ||
208 | QColorGroup cg2(cg); | ||
209 | QColor text = cg.text(); | ||
210 | if( m_hasDate && !m_completed ){ | ||
211 | if( m_off < 0 ){ | ||
212 | cg2.setColor(QColorGroup::Text, QColor(red ) ); | ||
213 | }else if( m_off == 0 ){ | ||
214 | cg2.setColor(QColorGroup::Text, QColor(yellow) ); // orange isn't predefined | ||
215 | }else if( m_off > 0){ | ||
216 | cg2.setColor(QColorGroup::Text, QColor(green ) ); | ||
217 | } | ||
218 | } | ||
219 | QTableItem::paint(p, cg2, cr, selected ); | ||
220 | cg2.setColor(QColorGroup::Text, text ); | ||
221 | } | ||
222 | TodoTable::TodoTable( QWidget *parent, const char *name ) | ||
223 | // #ifdef QT_QTABLE_NOHEADER_CONSTRUCTOR | ||
224 | // : QTable( 0, 3, parent, name, TRUE ), | ||
225 | // #else | ||
226 | : QTable( 0, 4, parent, name ), | ||
227 | // #endif | ||
228 | showComp( true ), | ||
229 | enablePainting( true ), | ||
230 | mCat( 0 ), | ||
231 | currFindRow( -2 ), | ||
232 | showDeadl( true) | ||
233 | { | ||
234 | setNumRows(0); | ||
235 | mCat.load( categoryFileName() ); | ||
236 | setSorting( TRUE ); | ||
237 | setSelectionMode( NoSelection ); | ||
238 | setColumnStretchable( 2, TRUE ); | ||
239 | setColumnWidth( 0, 20 ); | ||
240 | setColumnWidth( 1, 35 ); | ||
241 | |||
242 | setLeftMargin( 0 ); | ||
243 | verticalHeader()->hide(); | ||
244 | horizontalHeader()->setLabel( 0, tr( "C." ) ); | ||
245 | horizontalHeader()->setLabel( 1, tr( "Prior." ) ); | ||
246 | horizontalHeader()->setLabel( 2, tr( "Description" ) ); | ||
247 | |||
248 | setColumnStretchable( 3, FALSE ); | ||
249 | setColumnWidth( 3, 20 ); | ||
250 | horizontalHeader()->setLabel( 3, tr( "Deadline" ) ); | ||
251 | |||
252 | if (showDeadl){ | ||
253 | showColumn (3); | ||
254 | }else{ | ||
255 | hideColumn (3); | ||
256 | } | ||
257 | |||
258 | connect( this, SIGNAL( clicked( int, int, int, const QPoint & ) ), | ||
259 | this, SLOT( slotClicked( int, int, int, const QPoint & ) ) ); | ||
260 | connect( this, SIGNAL( pressed( int, int, int, const QPoint & ) ), | ||
261 | this, SLOT( slotPressed( int, int, int, const QPoint & ) ) ); | ||
262 | connect( this, SIGNAL( valueChanged( int, int ) ), | ||
263 | this, SLOT( slotCheckPriority( int, int ) ) ); | ||
264 | connect( this, SIGNAL( currentChanged( int, int ) ), | ||
265 | this, SLOT( slotCurrentChanged( int, int ) ) ); | ||
266 | |||
267 | menuTimer = new QTimer( this ); | ||
268 | connect( menuTimer, SIGNAL(timeout()), this, SLOT(slotShowMenu()) ); | ||
269 | |||
270 | mDayTimer = new QTimer( this ); | ||
271 | connect( mDayTimer, SIGNAL(timeout()), this, SLOT(slotCheckDay() ) ); | ||
272 | mDay = QDate::currentDate(); | ||
273 | } | ||
274 | |||
275 | void TodoTable::addEntry( const ToDoEvent &todo ) | ||
276 | { | ||
277 | int row = numRows(); | ||
278 | setNumRows( row + 1 ); | ||
279 | updateJournal( todo, ACTION_ADD ); | ||
280 | insertIntoTable( new ToDoEvent(todo), row ); | ||
281 | setCurrentCell(row, currentColumn()); | ||
282 | updateVisible(); | ||
283 | } | ||
284 | |||
285 | void TodoTable::slotClicked( int row, int col, int, const QPoint &pos ) | ||
286 | { | ||
287 | if ( !cellGeometry( row, col ).contains(pos) ) | ||
288 | return; | ||
289 | // let's switch on the column number... | ||
290 | switch ( col ) | ||
291 | { | ||
292 | case 0: { | ||
293 | CheckItem *i = static_cast<CheckItem*>(item( row, col )); | ||
294 | if ( i ) { | ||
295 | int x = pos.x() - columnPos( col ); | ||
296 | int y = pos.y() - rowPos( row ); | ||
297 | int w = columnWidth( col ); | ||
298 | int h = rowHeight( row ); | ||
299 | if ( i && x >= ( w - BoxSize ) / 2 && x <= ( w - BoxSize ) / 2 + BoxSize && | ||
300 | y >= ( h - BoxSize ) / 2 && y <= ( h - BoxSize ) / 2 + BoxSize ) { | ||
301 | i->toggle(); | ||
302 | } | ||
303 | emit signalDoneChanged( i->isChecked() ); | ||
304 | } | ||
305 | } | ||
306 | break; | ||
307 | case 1: | ||
308 | break; | ||
309 | case 2: | ||
310 | // Show detailed view of the selected entry | ||
311 | { | ||
312 | menuTimer->stop(); | ||
313 | ToDoEvent *todo = todoList[static_cast<CheckItem*>(item(row, 0))]; | ||
314 | emit showDetails( *todo ); | ||
315 | } | ||
316 | break; | ||
317 | case 3: | ||
318 | // may as well edit it... | ||
319 | menuTimer->stop(); | ||
320 | emit signalEdit(); | ||
321 | break; | ||
322 | } | ||
323 | } | ||
324 | |||
325 | void TodoTable::slotPressed( int row, int col, int, const QPoint &pos ) | ||
326 | { | ||
327 | if ( col == 2 && cellGeometry( row, col ).contains(pos) ) | ||
328 | menuTimer->start( 750, TRUE ); | ||
329 | } | ||
330 | |||
331 | void TodoTable::slotShowMenu() | ||
332 | { | ||
333 | emit signalShowMenu( QCursor::pos() ); | ||
334 | } | ||
335 | |||
336 | void TodoTable::slotCurrentChanged( int, int ) | ||
337 | { | ||
338 | menuTimer->stop(); | ||
339 | } | ||
340 | |||
341 | void TodoTable::internalAddEntries( QList<ToDoEvent> &list ) | ||
342 | { | ||
343 | setNumRows( list.count() ); | ||
344 | int row = 0; | ||
345 | ToDoEvent *it; | ||
346 | for ( it = list.first(); it; it = list.next() ) | ||
347 | insertIntoTable( it, row++ ); | ||
348 | } | ||
349 | |||
350 | |||
351 | ToDoEvent TodoTable::currentEntry() const | ||
352 | { | ||
353 | //qWarning ("in currentEntry\n"); | ||
354 | |||
355 | QTableItem *i = item( currentRow(), 0 ); | ||
356 | if ( !i || rowHeight( currentRow() ) <= 0 ) | ||
357 | return ToDoEvent(); | ||
358 | ToDoEvent *todo = todoList[(CheckItem*)i]; | ||
359 | todo->setCompleted( ( (CheckItem*)item( currentRow(), 0 ) )->isChecked() ); | ||
360 | todo->setPriority( ( (ComboItem*)item( currentRow(), 1 ) )->text().toInt() ); | ||
361 | return *todo; | ||
362 | } | ||
363 | |||
364 | void TodoTable::replaceCurrentEntry( const ToDoEvent &todo, bool fromTableItem ) | ||
365 | { | ||
366 | int row = currentRow(); | ||
367 | updateJournal( todo, ACTION_REPLACE); | ||
368 | |||
369 | if ( !fromTableItem ) { | ||
370 | journalFreeReplaceEntry( todo, row ); | ||
371 | updateVisible(); | ||
372 | } | ||
373 | } | ||
374 | |||
375 | void TodoTable::removeCurrentEntry() | ||
376 | { | ||
377 | ToDoEvent *oldTodo; | ||
378 | int row = currentRow(); | ||
379 | CheckItem *chk; | ||
380 | |||
381 | chk = static_cast<CheckItem*>(item(row, 0 )); | ||
382 | if ( !chk ) | ||
383 | return; | ||
384 | oldTodo = todoList[chk]; | ||
385 | todoList.remove( chk ); | ||
386 | oldTodo->setCompleted( chk->isChecked() ); | ||
387 | oldTodo->setPriority( static_cast<ComboItem*>(item(row, 1))->text().toInt() ); | ||
388 | realignTable( row ); | ||
389 | updateVisible(); | ||
390 | updateJournal( *oldTodo, ACTION_REMOVE); | ||
391 | delete oldTodo; | ||
392 | } | ||
393 | |||
394 | |||
395 | bool TodoTable::save( const QString &fn ) | ||
396 | { | ||
397 | QString strNewFile = fn + ".new"; | ||
398 | QFile::remove( strNewFile ); // just to be sure | ||
399 | ToDoDB todoDB( strNewFile ); | ||
400 | for ( QMap<CheckItem*, ToDoEvent *>::Iterator it = todoList.begin(); | ||
401 | it != todoList.end(); ++it ) { | ||
402 | if ( !item( it.key()->row(), 0 ) ) | ||
403 | continue; | ||
404 | ToDoEvent *todo = *it; | ||
405 | // sync item with table | ||
406 | todo->setCompleted( ((CheckItem*)item(it.key()->row(), 0))->isChecked() ); | ||
407 | todo->setPriority( ((ComboItem*)item( it.key()->row(), 1))->text().toInt() ); | ||
408 | todoDB.addEvent( *todo ); | ||
409 | } | ||
410 | if(!todoDB.save() ){ | ||
411 | QFile::remove( strNewFile ); | ||
412 | return false; | ||
413 | }; | ||
414 | // now do the rename | ||
415 | if ( ::rename( strNewFile, fn ) < 0 ) | ||
416 | qWarning( "problem renaming file %s to %s errno %d", | ||
417 | strNewFile.latin1(), fn.latin1(), errno ); | ||
418 | |||
419 | // remove the journal | ||
420 | QFile::remove( journalFileName() ); | ||
421 | return true; | ||
422 | } | ||
423 | |||
424 | void TodoTable::load( const QString &fn ) | ||
425 | { | ||
426 | if ( QFile::exists(journalFileName()) ) { | ||
427 | applyJournal(); | ||
428 | QFile::remove(journalFileName() ); | ||
429 | } | ||
430 | loadFile( fn ); | ||
431 | // QTable::sortColumn(2,TRUE,TRUE); | ||
432 | // QTable::sortColumn(1,TRUE,TRUE); | ||
433 | QTable::sortColumn(0,TRUE,TRUE); | ||
434 | setCurrentCell( 0, 2 ); | ||
435 | setSorting(true ); | ||
436 | mDayTimer->start( 60 * 1000 ); // gone in 60 seconds? | ||
437 | } | ||
438 | void TodoTable::updateVisible() | ||
439 | { | ||
440 | if ( !isUpdatesEnabled() ) | ||
441 | return; | ||
442 | |||
443 | if (showDeadl){ | ||
444 | showColumn (3); | ||
445 | adjustColumn(3); | ||
446 | }else{ | ||
447 | hideColumn (3); | ||
448 | adjustColumn(2); | ||
449 | } | ||
450 | |||
451 | int visible = 0; | ||
452 | int id = mCat.id( "Todo List", showCat ); | ||
453 | for ( int row = 0; row < numRows(); row++ ) { | ||
454 | CheckItem *ci = (CheckItem *)item( row, 0 ); | ||
455 | ToDoEvent *t = todoList[ci]; | ||
456 | if (!t) | ||
457 | continue; | ||
458 | |||
459 | QArray<int> vlCats = t->categories(); | ||
460 | bool hide = false; | ||
461 | if ( !showComp && ci->isChecked() ) | ||
462 | hide = true; | ||
463 | if ( !showCat.isEmpty() ) { | ||
464 | if ( showCat == tr( "Unfiled" ) ) { | ||
465 | if ( vlCats.count() > 0 ) | ||
466 | hide = true; | ||
467 | } else { | ||
468 | // do some comparing, we have to reverse our idea here... which idea? - zecke | ||
469 | if ( !hide ) { | ||
470 | hide = true; | ||
471 | for ( uint it = 0; it < vlCats.count(); ++it ) { | ||
472 | if ( vlCats[it] == id ) { | ||
473 | hide = false; | ||
474 | break; | ||
475 | } | ||
476 | } | ||
477 | } | ||
478 | } | ||
479 | } | ||
480 | if ( hide ) { | ||
481 | if ( currentRow() == row ) | ||
482 | setCurrentCell( -1, 0 ); | ||
483 | if ( rowHeight( row ) > 0 ) | ||
484 | hideRow( row ); | ||
485 | } else { | ||
486 | if ( rowHeight( row ) == 0 ) { | ||
487 | showRow( row ); | ||
488 | adjustRow( row ); | ||
489 | } | ||
490 | visible++; | ||
491 | } | ||
492 | } | ||
493 | if ( !visible ) | ||
494 | setCurrentCell( -1, 0 ); | ||
495 | } | ||
496 | |||
497 | void TodoTable::viewportPaintEvent( QPaintEvent *pe ) | ||
498 | { | ||
499 | if ( enablePainting ) | ||
500 | QTable::viewportPaintEvent( pe ); | ||
501 | } | ||
502 | |||
503 | void TodoTable::setPaintingEnabled( bool e ) | ||
504 | { | ||
505 | if ( e != enablePainting ) { | ||
506 | if ( !enablePainting ) { | ||
507 | enablePainting = true; | ||
508 | rowHeightChanged( 0 ); | ||
509 | viewport()->update(); | ||
510 | } else { | ||
511 | enablePainting = false; | ||
512 | } | ||
513 | } | ||
514 | } | ||
515 | |||
516 | void TodoTable::clear() | ||
517 | { | ||
518 | for ( QMap<CheckItem*, ToDoEvent *>::Iterator it = todoList.begin(); | ||
519 | it != todoList.end(); ++it ) { | ||
520 | ToDoEvent *todo = it.data(); | ||
521 | updateJournal( *todo, ACTION_REMOVE ); | ||
522 | delete todo; | ||
523 | } | ||
524 | todoList.clear(); | ||
525 | for ( int r = 0; r < numRows(); ++r ) { | ||
526 | for ( int c = 0; c < numCols(); ++c ) { | ||
527 | if ( cellWidget( r, c ) ) | ||
528 | clearCellWidget( r, c ); | ||
529 | clearCell( r, c ); | ||
530 | } | ||
531 | } | ||
532 | setNumRows( 0 ); | ||
533 | } | ||
534 | |||
535 | void TodoTable::sortColumn( int col, bool ascending, bool /*wholeRows*/ ) | ||
536 | { | ||
537 | // The default for wholeRows is false, however | ||
538 | // for this todo table we want to exchange complete | ||
539 | // rows when sorting. Also, we always want ascending, since | ||
540 | // the values have a logical order. | ||
541 | QTable::sortColumn( col, ascending, TRUE ); | ||
542 | updateVisible(); | ||
543 | } | ||
544 | |||
545 | void TodoTable::slotCheckPriority(int row, int col ) | ||
546 | { | ||
547 | // kludgey work around to make forward along the updated priority... | ||
548 | if ( col == 1 ) { | ||
549 | // let everyone know!! | ||
550 | ComboItem* i = static_cast<ComboItem*>( item( row, col ) ); | ||
551 | emit signalPriorityChanged( i->text().toInt() ); | ||
552 | } | ||
553 | } | ||
554 | |||
555 | |||
556 | void TodoTable::updateJournal( const ToDoEvent &todo, journal_action action ) | ||
557 | { | ||
558 | QFile f( journalFileName() ); | ||
559 | if ( !f.open(IO_WriteOnly|IO_Append) ) | ||
560 | return; | ||
561 | QString buf; | ||
562 | QCString str; | ||
563 | buf = "<Task"; | ||
564 | // todo.save( buf ); | ||
565 | buf += " Action=\"" + QString::number( int(action) ) + "\""; | ||
566 | buf += " Uid=\"" + QString::number( todo.uid() ) + "\""; // better write the id | ||
567 | buf += " Completed=\""+ QString::number((int)todo.isCompleted() ) + "\""; | ||
568 | buf += " HasDate=\""+ QString::number((int)todo.hasDate() ) +"\""; | ||
569 | buf += " Priority=\"" + QString::number( todo.priority() ) + "\""; | ||
570 | QArray<int> arrat = todo.categories(); | ||
571 | QString attr; | ||
572 | for(uint i=0; i < arrat.count(); i++ ){ | ||
573 | attr.append(QString::number(arrat[i])+";" ); | ||
574 | } | ||
575 | if(!attr.isEmpty() ) // remove the last ; | ||
576 | attr.remove(attr.length()-1, 1 ); | ||
577 | buf += " Categories=\"" + attr + "\""; | ||
578 | buf += " Description=\"" + todo.description() + "\""; | ||
579 | buf += " Summary=\"" + todo.summary() + "\""; | ||
580 | if(todo.hasDate() ) { | ||
581 | buf += " DateYear=\""+QString::number( todo.date().year() ) + "\""; | ||
582 | buf += " DateMonth=\"" + QString::number( todo.date().month() ) + "\""; | ||
583 | buf += " DateDay=\"" + QString::number( todo.date().day() ) + "\""; | ||
584 | } | ||
585 | buf += "/>\n"; | ||
586 | str = buf.utf8(); | ||
587 | f.writeBlock( str.data(), str.length() ); | ||
588 | f.close(); | ||
589 | } | ||
590 | |||
591 | void TodoTable::rowHeightChanged( int row ) | ||
592 | { | ||
593 | if ( enablePainting ) | ||
594 | QTable::rowHeightChanged( row ); | ||
595 | } | ||
596 | |||
597 | void TodoTable::loadFile( const QString &/*we use the standard*/ ) | ||
598 | { | ||
599 | |||
600 | QList<ToDoEvent> list; | ||
601 | ToDoDB todoDB; | ||
602 | QValueList<ToDoEvent> vaList = todoDB.rawToDos(); | ||
603 | for(QValueList<ToDoEvent>::ConstIterator it = vaList.begin(); it != vaList.end(); ++it ){ | ||
604 | ToDoEvent *event = new ToDoEvent( (*it) ); | ||
605 | list.append( event ); | ||
606 | } | ||
607 | vaList.clear(); | ||
608 | // qDebug("parsing done=%d", t.elapsed() ); | ||
609 | if ( list.count() > 0 ) { | ||
610 | internalAddEntries( list ); | ||
611 | list.clear(); | ||
612 | } | ||
613 | // qDebug("loading done: t=%d", t.elapsed() ); | ||
614 | } | ||
615 | |||
616 | void TodoTable::journalFreeReplaceEntry( const ToDoEvent &todo, int row ) | ||
617 | { | ||
618 | QString strTodo = todo.summary(); | ||
619 | if( strTodo.isEmpty() ){ | ||
620 | strTodo = todo.description().left(40).simplifyWhiteSpace(); | ||
621 | //todo.setSummary(strTodo ); | ||
622 | } | ||
623 | if ( row == -1 ) { | ||
624 | QMapIterator<CheckItem*, ToDoEvent *> it; | ||
625 | for ( it = todoList.begin(); it != todoList.end(); ++it ) { | ||
626 | if ( *(*it) == todo ) { | ||
627 | row = it.key()->row(); | ||
628 | it.key()->setChecked( todo.isCompleted() ); | ||
629 | static_cast<ComboItem*>(item(row, 1))->setText( QString::number(todo.priority()) ); | ||
630 | item( row, 2 )->setText( strTodo ); | ||
631 | |||
632 | if (showDeadl){ | ||
633 | static_cast<DueTextItem*>(item(row,3))->setToDoEvent(&todo ); | ||
634 | } | ||
635 | |||
636 | *(*it) = todo; | ||
637 | } | ||
638 | } | ||
639 | } else { | ||
640 | ToDoEvent *t = todoList[static_cast<CheckItem*>(item(row, 0))]; | ||
641 | todoList.remove( static_cast<CheckItem*>(item(row, 0)) ); | ||
642 | delete t; | ||
643 | static_cast<CheckItem*>(item(row, 0))->setChecked( todo.isCompleted() ); | ||
644 | static_cast<ComboItem*>(item(row, 1))->setText( QString::number(todo.priority()) ); | ||
645 | item( row, 2 )->setText( strTodo ); | ||
646 | |||
647 | if (showDeadl){ | ||
648 | static_cast<DueTextItem*>(item(row,3))->setToDoEvent(&todo ); | ||
649 | } | ||
650 | todoList.insert( static_cast<CheckItem*>(item(row,0)), new ToDoEvent(todo) ); | ||
651 | } | ||
652 | } | ||
653 | |||
654 | void TodoTable::journalFreeRemoveEntry( int row ) | ||
655 | { | ||
656 | CheckItem *chk; | ||
657 | chk = static_cast<CheckItem*>(item(row, 0 )); | ||
658 | if ( !chk ) | ||
659 | return; | ||
660 | todoList.remove( chk ); | ||
661 | |||
662 | realignTable( row ); | ||
663 | } | ||
664 | |||
665 | void TodoTable::keyPressEvent( QKeyEvent *e ) | ||
666 | { | ||
667 | if ( e->key() == Key_Space || e->key() == Key_Return ) { | ||
668 | switch ( currentColumn() ) { | ||
669 | case 0: { | ||
670 | CheckItem *i = static_cast<CheckItem*>(item(currentRow(), | ||
671 | currentColumn())); | ||
672 | if ( i ) | ||
673 | i->toggle(); | ||
674 | break; | ||
675 | } | ||
676 | case 1: | ||
677 | break; | ||
678 | case 2:{ | ||
679 | ToDoEvent *todo = todoList[static_cast<CheckItem*>(item(currentRow(), 0))]; | ||
680 | emit showDetails(*todo); | ||
681 | break; | ||
682 | } | ||
683 | case 3: | ||
684 | // Future: Let us change the dueDate directly... | ||
685 | emit signalEdit(); | ||
686 | default: | ||
687 | break; | ||
688 | } | ||
689 | } else | ||
690 | QTable::keyPressEvent( e ); | ||
691 | } | ||
692 | |||
693 | |||
694 | QStringList TodoTable::categories() | ||
695 | { | ||
696 | // This is called seldom, so calling a load in here | ||
697 | // should be fine. | ||
698 | mCat.load( categoryFileName() ); | ||
699 | QStringList categoryList = mCat.labels( "Todo List" ); | ||
700 | return categoryList; | ||
701 | } | ||
702 | |||
703 | void TodoTable::slotDoFind( const QString &findString, bool caseSensitive, | ||
704 | bool backwards, int category ) | ||
705 | { | ||
706 | // we have to iterate through the table, this gives the illusion that | ||
707 | // sorting is actually being used. | ||
708 | if ( currFindRow < -1 ) | ||
709 | currFindRow = currentRow() - 1; | ||
710 | clearSelection( TRUE ); | ||
711 | int rows, | ||
712 | row; | ||
713 | CheckItem *chk; | ||
714 | QRegExp r( findString ); | ||
715 | |||
716 | r.setCaseSensitive( caseSensitive ); | ||
717 | rows = numRows(); | ||
718 | static bool wrapAround = true; | ||
719 | |||
720 | if ( !backwards ) { | ||
721 | for ( row = currFindRow + 1; row < rows; row++ ) { | ||
722 | chk = static_cast<CheckItem*>( item(row, 0) ); | ||
723 | if ( taskCompare(*(todoList[chk]), r, category) ) | ||
724 | break; | ||
725 | } | ||
726 | } else { | ||
727 | for ( row = currFindRow - 1; row > -1; row-- ) { | ||
728 | chk = static_cast<CheckItem*>( item(row, 0) ); | ||
729 | if ( taskCompare(*(todoList[chk]), r, category) ) | ||
730 | break; | ||
731 | } | ||
732 | } | ||
733 | if ( row >= rows || row < 0 ) { | ||
734 | if ( row < 0 ) | ||
735 | currFindRow = rows; | ||
736 | else | ||
737 | currFindRow = -1; | ||
738 | if ( wrapAround ) | ||
739 | emit signalWrapAround(); | ||
740 | else | ||
741 | emit signalNotFound(); | ||
742 | wrapAround = !wrapAround; | ||
743 | } else { | ||
744 | currFindRow = row; | ||
745 | QTableSelection foundSelection; | ||
746 | foundSelection.init( currFindRow, 0 ); | ||
747 | foundSelection.expandTo( currFindRow, numCols() - 1 ); | ||
748 | addSelection( foundSelection ); | ||
749 | setCurrentCell( currFindRow, numCols() - 1 ); | ||
750 | // we should always be able to wrap around and find this again, | ||
751 | // so don't give confusing not found message... | ||
752 | wrapAround = true; | ||
753 | } | ||
754 | } | ||
755 | |||
756 | int TodoTable::showCategoryId() const | ||
757 | { | ||
758 | int id; | ||
759 | id = -1; | ||
760 | // if allcategories are selected, you get unfiled... | ||
761 | if ( showCat != tr( "Unfiled" ) && showCat != tr( "All" ) ) | ||
762 | id = mCat.id( "Todo List", showCat ); | ||
763 | return id; | ||
764 | } | ||
765 | void TodoTable::applyJournal() | ||
766 | { | ||
767 | // we need to hack | ||
768 | QFile file( journalFileName() ); | ||
769 | if( file.open(IO_ReadOnly ) ) { | ||
770 | QByteArray ar = file.readAll(); | ||
771 | file.close(); | ||
772 | QFile file2( journalFileName() + "_new" ); | ||
773 | if( file2.open(IO_WriteOnly ) ){ | ||
774 | QTextStream str(&file2 ); | ||
775 | str << QString::fromLatin1("<Tasks>") << endl; | ||
776 | str << ar.data(); | ||
777 | str << QString::fromLatin1("</Tasks>") << endl; | ||
778 | file2.close(); | ||
779 | } | ||
780 | XMLElement *root = XMLElement::load(journalFileName()+ "_new"); | ||
781 | XMLElement *el = root->firstChild(); | ||
782 | el = el->firstChild(); | ||
783 | ToDoDB tododb; // allready loaded ;) | ||
784 | bool ok; | ||
785 | int action; | ||
786 | QString dummy; | ||
787 | while( el ){ | ||
788 | dummy = el->attribute("Action" ); | ||
789 | action = dummy.toInt(&ok ); | ||
790 | ToDoEvent ev = xmlToEvent( el ); | ||
791 | if(ok ){ | ||
792 | switch( action){ | ||
793 | case ACTION_ADD: | ||
794 | tododb.addEvent(ev ); | ||
795 | break; | ||
796 | case ACTION_REMOVE: | ||
797 | tododb.removeEvent( ev ); | ||
798 | break; | ||
799 | case ACTION_REPLACE: | ||
800 | tododb.replaceEvent( ev ); | ||
801 | break; | ||
802 | } | ||
803 | } | ||
804 | el = el->nextChild(); | ||
805 | } | ||
806 | QFile::remove(journalFileName()+ "_new" ); | ||
807 | tododb.save(); | ||
808 | } | ||
809 | } | ||
810 | void TodoTable::slotCheckDay() | ||
811 | { | ||
812 | QDate date = QDate::currentDate(); | ||
813 | if( mDay.daysTo(date )!= 0 ){ | ||
814 | setPaintingEnabled( FALSE ); | ||
815 | for(int i=0; i < numRows(); i++ ){ | ||
816 | ToDoEvent *t = todoList[static_cast<CheckItem*>(item(i, 0))]; | ||
817 | static_cast<DueTextItem*>(item(i, 3) )->setToDoEvent( t ); | ||
818 | |||
819 | } | ||
820 | setPaintingEnabled( TRUE ); | ||
821 | mDay = date; | ||
822 | } | ||
823 | mDayTimer->start( 60 * 1000 ); // 60 seconds | ||
824 | } | ||
825 | // check Action and decide | ||
826 | /* | ||
827 | void TodoTable::doApply(XMLElement *el ) | ||
828 | { | ||
829 | QString dummy; | ||
830 | bool ok; | ||
831 | int action; | ||
832 | dummy = el->attribute("Action" ); | ||
833 | action = dummy.toInt(&ok ); | ||
834 | ToDoEvent ev = xmlToEvent( el ); | ||
835 | if( ok ){ | ||
836 | switch( action ){ | ||
837 | case ACTION_ADD: | ||
838 | addEntry( ev ); | ||
839 | break; | ||
840 | case ACTION_REMOVE:{ // find an entry with the same uid and remove it then | ||
841 | break; | ||
842 | } | ||
843 | case ACTION_REPLACE: | ||
844 | break; | ||
845 | } | ||
846 | } | ||
847 | } | ||
848 | */ | ||
849 | namespace { | ||
850 | static bool taskCompare( const ToDoEvent &task, const QRegExp &r, int category ) | ||
851 | { | ||
852 | bool returnMe; | ||
853 | QArray<int> cats; | ||
854 | cats = task.categories(); | ||
855 | |||
856 | returnMe = false; | ||
857 | if ( (category == -1 && cats.count() == 0) || category == -2 ) | ||
858 | returnMe = task.match( r ); | ||
859 | else { | ||
860 | int i; | ||
861 | for ( i = 0; i < int(cats.count()); i++ ) { | ||
862 | if ( cats[i] == category ) { | ||
863 | returnMe = task.match( r ); | ||
864 | break; | ||
865 | } | ||
866 | } | ||
867 | } | ||
868 | return returnMe; | ||
869 | } | ||
870 | |||
871 | static QString journalFileName() | ||
872 | { | ||
873 | QString str; | ||
874 | str = getenv( "HOME" ); | ||
875 | str += "/.opie_todojournal"; | ||
876 | return str; | ||
877 | } | ||
878 | static ToDoEvent xmlToEvent( XMLElement *element ) | ||
879 | { | ||
880 | QString dummy; | ||
881 | ToDoEvent event; | ||
882 | bool ok; | ||
883 | int dumInt; | ||
884 | // completed | ||
885 | dummy = element->attribute("Completed" ); | ||
886 | dumInt = dummy.toInt(&ok ); | ||
887 | if(ok ) event.setCompleted( dumInt == 0 ? false : true ); | ||
888 | // hasDate | ||
889 | dummy = element->attribute("HasDate" ); | ||
890 | dumInt = dummy.toInt(&ok ); | ||
891 | if(ok ) event.setHasDate( dumInt == 0 ? false: true ); | ||
892 | // set the date | ||
893 | bool hasDa = dumInt; | ||
894 | if ( hasDa ) { //parse the date | ||
895 | int year, day, month = 0; | ||
896 | year = day = month; | ||
897 | // year | ||
898 | dummy = element->attribute("DateYear" ); | ||
899 | dumInt = dummy.toInt(&ok ); | ||
900 | if( ok ) year = dumInt; | ||
901 | // month | ||
902 | dummy = element->attribute("DateMonth" ); | ||
903 | dumInt = dummy.toInt(&ok ); | ||
904 | if(ok ) month = dumInt; | ||
905 | dummy = element->attribute("DateDay" ); | ||
906 | dumInt = dummy.toInt(&ok ); | ||
907 | if(ok ) day = dumInt; | ||
908 | // set the date | ||
909 | QDate date( year, month, day ); | ||
910 | event.setDate( date); | ||
911 | } | ||
912 | dummy = element->attribute("Priority" ); | ||
913 | dumInt = dummy.toInt(&ok ); | ||
914 | if(!ok ) dumInt = ToDoEvent::NORMAL; | ||
915 | event.setPriority( dumInt ); | ||
916 | //description | ||
917 | dummy = element->attribute("Description" ); | ||
918 | event.setDescription( dummy ); | ||
919 | // summary | ||
920 | dummy = element->attribute("Summary" ); | ||
921 | event.setSummary( dummy ); | ||
922 | // category | ||
923 | dummy = element->attribute("Categories" ); | ||
924 | QStringList ids = QStringList::split(";", dummy ); | ||
925 | event.setCategories( ids ); | ||
926 | |||
927 | //uid | ||
928 | dummy = element->attribute("Uid" ); | ||
929 | dumInt = dummy.toInt(&ok ); | ||
930 | if(ok ) event.setUid( dumInt ); | ||
931 | return event; | ||
932 | } | ||
933 | |||
934 | } | ||
935 | // int TodoTable::rowHeight( int ) const | ||
936 | // { | ||
937 | // return 18; | ||
938 | // } | ||
939 | |||
940 | // int TodoTable::rowPos( int row ) const | ||
941 | // { | ||
942 | // return 18*row; | ||
943 | // } | ||
944 | |||
945 | // int TodoTable::rowAt( int pos ) const | ||
946 | // { | ||
947 | // return QMIN( pos/18, numRows()-1 ); | ||
948 | // } | ||
949 | |||