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