summaryrefslogtreecommitdiff
path: root/core/pim/datebook/datebookweek.cpp
Unidiff
Diffstat (limited to 'core/pim/datebook/datebookweek.cpp') (more/less context) (show whitespace changes)
-rw-r--r--core/pim/datebook/datebookweek.cpp687
1 files changed, 687 insertions, 0 deletions
diff --git a/core/pim/datebook/datebookweek.cpp b/core/pim/datebook/datebookweek.cpp
new file mode 100644
index 0000000..e9fcc39
--- a/dev/null
+++ b/core/pim/datebook/datebookweek.cpp
@@ -0,0 +1,687 @@
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#include "datebookweek.h"
21#include "datebookweekheaderimpl.h"
22
23#include <qpe/calendar.h>
24#include <qpe/datebookdb.h>
25#include <qpe/event.h>
26#include <qpe/qpeapplication.h>
27#include <qpe/timestring.h>
28
29#include <qdatetime.h>
30#include <qheader.h>
31#include <qlabel.h>
32#include <qlayout.h>
33#include <qpainter.h>
34#include <qpopupmenu.h>
35#include <qtimer.h>
36#include <qspinbox.h>
37#include <qstyle.h>
38
39//-----------------------------------------------------------------
40
41
42DateBookWeekItem::DateBookWeekItem( const EffectiveEvent e )
43 : ev( e )
44{
45 // with the current implementation change the color for all day events
46 if ( ev.event().type() == Event::AllDay && !ev.event().hasAlarm() ) {
47 c = Qt::green;
48 } else {
49 c = ev.event().hasAlarm() ? Qt::red : Qt::blue;
50 }
51}
52
53void DateBookWeekItem::setGeometry( int x, int y, int w, int h )
54{
55 r.setRect( x, y, w, h );
56}
57
58
59//------------------=---------------------------------------------
60
61DateBookWeekView::DateBookWeekView( bool ap, bool startOnMonday,
62 QWidget *parent, const char *name )
63 : QScrollView( parent, name ), ampm( ap ), bOnMonday( startOnMonday ),
64 showingEvent( false )
65{
66 items.setAutoDelete( true );
67
68 viewport()->setBackgroundMode( PaletteBase );
69
70 header = new QHeader( this );
71 header->addLabel( "" );
72
73 header->setMovingEnabled( false );
74 header->setResizeEnabled( false );
75 header->setClickEnabled( false, 0 );
76 initNames();
77
78
79 connect( header, SIGNAL(clicked(int)), this, SIGNAL(showDay(int)) );
80
81 QObject::connect(qApp, SIGNAL(clockChanged(bool)),
82 this, SLOT(slotChangeClock(bool)));
83
84 QFontMetrics fm( font() );
85 rowHeight = fm.height()+2;
86
87 resizeContents( width(), 24*rowHeight );
88}
89
90void DateBookWeekView::initNames()
91{
92 static bool bFirst = true;
93 if ( bFirst ) {
94 if ( bOnMonday ) {
95 header->addLabel( tr("M", "Monday" ) );
96 header->addLabel( tr("T", "Tuesday") );
97 header->addLabel( tr("W", "Wednesday" ) );
98 header->addLabel( tr("T", "Thursday" ) );
99 header->addLabel( tr("F", "Friday" ) );
100 header->addLabel( tr("S", "Saturday" ) );
101 header->addLabel( tr("S", "Sunday" ) );
102 } else {
103 header->addLabel( tr("S", "Sunday" ) );
104 header->addLabel( tr("M", "Monday") );
105 header->addLabel( tr("T", "Tuesday") );
106 header->addLabel( tr("W", "Wednesday" ) );
107 header->addLabel( tr("T", "Thursday" ) );
108 header->addLabel( tr("F", "Friday" ) );
109 header->addLabel( tr("S", "Saturday" ) );
110 }
111 bFirst = false;
112 } else {
113 // we are change things...
114 if ( bOnMonday ) {
115 header->setLabel( 1, tr("M", "Monday") );
116 header->setLabel( 2, tr("T", "Tuesday") );
117 header->setLabel( 3, tr("W", "Wednesday" ) );
118 header->setLabel( 4, tr("T", "Thursday" ) );
119 header->setLabel( 5, tr("F", "Friday" ) );
120 header->setLabel( 6, tr("S", "Saturday" ) );
121 header->setLabel( 7, tr("S", "Sunday" ) );
122 } else {
123 header->setLabel( 1, tr("S", "Sunday" ) );
124 header->setLabel( 2, tr("M", "Monday") );
125 header->setLabel( 3, tr("T", "Tuesday") );
126 header->setLabel( 4, tr("W", "Wednesday" ) );
127 header->setLabel( 5, tr("T", "Thursday" ) );
128 header->setLabel( 6, tr("F", "Friday" ) );
129 header->setLabel( 7, tr("S", "Saturday" ) );
130 }
131 }
132}
133
134
135
136void DateBookWeekView::showEvents( QValueList<EffectiveEvent> &ev )
137{
138 items.clear();
139 QValueListIterator<EffectiveEvent> it;
140 for ( it = ev.begin(); it != ev.end(); ++it ) {
141 DateBookWeekItem *i = new DateBookWeekItem( *it );
142 positionItem( i );
143 items.append( i );
144 }
145 viewport()->update();
146}
147
148void DateBookWeekView::moveToHour( int h )
149{
150 int offset = h*rowHeight;
151 setContentsPos( 0, offset );
152}
153
154void DateBookWeekView::keyPressEvent( QKeyEvent *e )
155{
156 e->ignore();
157}
158
159void DateBookWeekView::slotChangeClock( bool c )
160{
161 ampm = c;
162 viewport()->update();
163}
164
165static inline int db_round30min( int m )
166{
167 if ( m < 15 )
168 m = 0;
169 else if ( m < 45 )
170 m = 1;
171 else
172 m = 2;
173
174 return m;
175}
176
177void DateBookWeekView::alterDay( int day )
178{
179 if ( !bOnMonday ) {
180 day--;
181 }
182 emit showDay( day );
183}
184
185void DateBookWeekView::positionItem( DateBookWeekItem *i )
186{
187 const int Width = 8;
188 const EffectiveEvent ev = i->event();
189
190 // 30 minute intervals
191 int y = ev.start().hour() * 2;
192 y += db_round30min( ev.start().minute() );
193 if ( y > 47 )
194 y = 47;
195 y = y * rowHeight / 2;
196
197 int h;
198 if ( ev.event().type() == Event::AllDay ) {
199 h = 48;
200 y = 0;
201 } else {
202 h = ( ev.end().hour() - ev.start().hour() ) * 2;
203 h += db_round30min( ev.end().minute() - ev.start().minute() );
204 if ( h < 1 ) h = 1;
205 }
206 h = h * rowHeight / 2;
207
208 int dow = ev.date().dayOfWeek();
209 if ( !bOnMonday ) {
210 if ( dow == 7 )
211 dow = 1;
212 else
213 dow++;
214 }
215 int x = header->sectionPos( dow ) - 1;
216 int xlim = header->sectionPos( dow ) + header->sectionSize( dow );
217 DateBookWeekItem *isect = 0;
218 do {
219 i->setGeometry( x, y, Width, h );
220 isect = intersects( i );
221 x += Width - 1;
222 } while ( isect && x < xlim );
223}
224
225DateBookWeekItem *DateBookWeekView::intersects( const DateBookWeekItem *item )
226{
227 QRect geom = item->geometry();
228
229 // We allow the edges to overlap
230 geom.moveBy( 1, 1 );
231 geom.setSize( geom.size()-QSize(2,2) );
232
233 QListIterator<DateBookWeekItem> it(items);
234 for ( ; it.current(); ++it ) {
235 DateBookWeekItem *i = it.current();
236 if ( i != item ) {
237 if ( i->geometry().intersects( geom ) ) {
238 return i;
239 }
240 }
241 }
242
243 return 0;
244}
245
246void DateBookWeekView::contentsMousePressEvent( QMouseEvent *e )
247{
248 QListIterator<DateBookWeekItem> it(items);
249 for ( ; it.current(); ++it ) {
250 DateBookWeekItem *i = it.current();
251 if ( i->geometry().contains( e->pos() ) ) {
252 showingEvent = true;
253 emit signalShowEvent( i->event() );
254 break;
255 }
256 }
257}
258
259void DateBookWeekView::contentsMouseReleaseEvent( QMouseEvent *e )
260{
261 if ( showingEvent ) {
262 showingEvent = false;
263 emit signalHideEvent();
264 } else {
265 int d = header->sectionAt( e->pos().x() );
266 if ( d > 0 ) {
267 // if ( !bOnMonday )
268 // d--;
269 emit showDay( d );
270 }
271 }
272}
273
274void DateBookWeekView::drawContents( QPainter *p, int cx, int cy, int cw, int ch )
275{
276 QRect ur( cx, cy, cw, ch );
277 p->setPen( lightGray );
278 for ( int i = 1; i <= 7; i++ )
279 p->drawLine( header->sectionPos(i)-2, cy, header->sectionPos(i)-2, cy+ch );
280
281 p->setPen( black );
282 for ( int t = 0; t < 24; t++ ) {
283 int y = t*rowHeight;
284 if ( QRect( 1, y, 20, rowHeight ).intersects( ur ) ) {
285 QString s;
286 if ( ampm ) {
287 if ( t == 0 )
288 s = QString::number( 12 );
289 else if ( t == 12 )
290 s = QString::number(12) + tr( "p" );
291 else if ( t > 12 ) {
292 if ( t - 12 < 10 )
293 s = " ";
294 else
295 s = "";
296 s += QString::number( t - 12 ) + tr("p");
297 } else {
298 if ( 12 - t < 3 )
299 s = "";
300 else
301 s = " ";
302 s += QString::number( t );
303 }
304 } else {
305 s = QString::number( t );
306 if ( s.length() == 1 )
307 s.prepend( "0" );
308 }
309 p->drawText( 1, y+p->fontMetrics().ascent()+1, s );
310 }
311 }
312
313 QListIterator<DateBookWeekItem> it(items);
314 for ( ; it.current(); ++it ) {
315 DateBookWeekItem *i = it.current();
316 if ( i->geometry().intersects( ur ) ) {
317 p->setBrush( i->color() );
318 p->drawRect( i->geometry() );
319 }
320 }
321}
322
323void DateBookWeekView::resizeEvent( QResizeEvent *e )
324{
325 const int hourWidth = 20;
326 QScrollView::resizeEvent( e );
327 int avail = width()-qApp->style().scrollBarExtent().width()-1;
328 header->setGeometry( 0, 0, avail, header->sizeHint().height() );
329 setMargins( 0, header->height(), 0, 0 );
330 header->resizeSection( 0, hourWidth );
331 int sw = (avail - hourWidth) / 7;
332 for ( int i = 1; i < 7; i++ )
333 header->resizeSection( i, sw );
334 header->resizeSection( 7, avail - hourWidth - sw*6 );
335}
336
337void DateBookWeekView::setStartOfWeek( bool bStartOnMonday )
338{
339 bOnMonday = bStartOnMonday;
340 initNames();
341}
342
343//-------------------------------------------------------------------
344
345DateBookWeek::DateBookWeek( bool ap, bool startOnMonday, DateBookDB *newDB,
346 QWidget *parent, const char *name )
347 : QWidget( parent, name ),
348 db( newDB ),
349 startTime( 0 ),
350 ampm( ap ),
351 bStartOnMonday( startOnMonday )
352{
353 setFocusPolicy(StrongFocus);
354 QVBoxLayout *vb = new QVBoxLayout( this );
355 header = new DateBookWeekHeader( bStartOnMonday, this );
356 view = new DateBookWeekView( ampm, startOnMonday, this );
357 vb->addWidget( header );
358 vb->addWidget( view );
359
360 lblDesc = new QLabel( this, "event label" );
361 lblDesc->setFrameStyle( QFrame::Plain | QFrame::Box );
362 lblDesc->setBackgroundColor( yellow );
363 lblDesc->hide();
364
365 tHide = new QTimer( this );
366
367 connect( view, SIGNAL( showDay( int ) ),
368 this, SLOT( showDay( int ) ) );
369 connect( view, SIGNAL(signalShowEvent(const EffectiveEvent&)),
370 this, SLOT(slotShowEvent(const EffectiveEvent&)) );
371 connect( view, SIGNAL(signalHideEvent()),
372 this, SLOT(slotHideEvent()) );
373 connect( header, SIGNAL( dateChanged( int, int ) ),
374 this, SLOT( dateChanged( int, int ) ) );
375 connect( tHide, SIGNAL( timeout() ),
376 lblDesc, SLOT( hide() ) );
377 connect( header->spinYear, SIGNAL(valueChanged(int)),
378 this, SLOT(slotYearChanged(int)) );
379 connect( qApp, SIGNAL(weekChanged(bool)),
380 this, SLOT(slotWeekChanged(bool)) );
381 connect( qApp, SIGNAL(clockChanged(bool)),
382 this, SLOT(slotClockChanged(bool)));
383 setDate(QDate::currentDate());
384
385}
386
387void DateBookWeek::keyPressEvent(QKeyEvent *e)
388{
389 switch(e->key()) {
390 case Key_Up:
391 view->scrollBy(0, -20);
392 break;
393 case Key_Down:
394 view->scrollBy(0, 20);
395 break;
396 case Key_Left:
397 setDate(date().addDays(-7));
398 break;
399 case Key_Right:
400 setDate(date().addDays(7));
401 break;
402 default:
403 e->ignore();
404 }
405}
406
407void DateBookWeek::showDay( int day )
408{
409 QDate d;
410 d = dateFromWeek( _week, year, bStartOnMonday );
411 day--;
412 d = d.addDays( day );
413 emit showDate( d.year(), d.month(), d.day() );
414}
415
416void DateBookWeek::setDate( int y, int m, int d )
417{
418 QDate date;
419 date.setYMD( y, m, d );
420 setDate(QDate(y, m, d));
421}
422
423void DateBookWeek::setDate(QDate date)
424{
425 dow = date.dayOfWeek();
426 int w, y;
427 calcWeek( date, w, y, bStartOnMonday );
428 header->setDate( y, w );
429}
430
431void DateBookWeek::dateChanged( int y, int w )
432{
433 year = y;
434 _week = w;
435 getEvents();
436}
437
438QDate DateBookWeek::date() const
439{
440 QDate d;
441 d = dateFromWeek( _week - 1, year, bStartOnMonday );
442 if ( bStartOnMonday )
443 d = d.addDays( 7 + dow - 1 );
444 else {
445 if ( dow == 7 )
446 d = d.addDays( dow );
447 else
448 d = d.addDays( 7 + dow );
449 }
450 return d;
451}
452
453void DateBookWeek::getEvents()
454{
455 QDate startWeek = weekDate();
456
457 QDate endWeek = startWeek.addDays( 6 );
458 QValueList<EffectiveEvent> eventList = db->getEffectiveEvents(startWeek,
459 endWeek);
460 view->showEvents( eventList );
461 view->moveToHour( startTime );
462}
463
464void DateBookWeek::slotShowEvent( const EffectiveEvent &ev )
465{
466 if ( tHide->isActive() )
467 tHide->stop();
468
469 // why would someone use "<"? Oh well, fix it up...
470 // I wonder what other things may be messed up...
471 QString strDesc = ev.description();
472 int where = strDesc.find( "<" );
473 while ( where != -1 ) {
474 strDesc.remove( where, 1 );
475 strDesc.insert( where, "&#60;" );
476 where = strDesc.find( "<", where );
477 }
478
479 QString strCat;
480 // ### FIX later...
481// QString strCat = ev.category();
482// where = strCat.find( "<" );
483// while ( where != -1 ) {
484 // strCat.remove( where, 1 );
485 // strCat.insert( where, "&#60;" );
486 // where = strCat.find( "<", where );
487// }
488
489 QString strNote = ev.notes();
490 where = strNote.find( "<" );
491 while ( where != -1 ) {
492 strNote.remove( where, 1 );
493 strNote.insert( where, "&#60;" );
494 where = strNote.find( "<", where );
495 }
496
497 QString str = "<b>" + strDesc + "</b><br>" + "<i>"
498 + strCat + "</i>"
499 + "<br>" + TimeString::longDateString( ev.date() )
500 + "<br><b>" + QObject::tr("Start") + "</b>: ";
501
502 if ( ev.startDate() != ev.date() ) {
503 // multi-day event. Show start date
504 str += TimeString::longDateString( ev.startDate() );
505 } else {
506 // Show start time.
507 str += TimeString::timeString(ev.start(), ampm, FALSE );
508 }
509
510 str += "<br><b>" + QObject::tr("End") + "</b>: ";
511 if ( ev.endDate() != ev.date() ) {
512 // multi-day event. Show end date
513 str += TimeString::longDateString( ev.endDate() );
514 } else {
515 // Show end time.
516 str += TimeString::timeString( ev.end(), ampm, FALSE );
517 }
518 str += "<br><br>" + strNote;
519
520 lblDesc->setText( str );
521 lblDesc->resize( lblDesc->sizeHint() );
522 // move the label so it is "centerd" horizontally...
523 lblDesc->move( QMAX(0,(width() - lblDesc->width()) / 2), 0 );
524 lblDesc->show();
525}
526
527void DateBookWeek::slotHideEvent()
528{
529 tHide->start( 2000, true );
530}
531
532void DateBookWeek::setStartViewTime( int startHere )
533{
534 startTime = startHere;
535 view->moveToHour( startTime );
536}
537
538int DateBookWeek::startViewTime() const
539{
540 return startTime;
541}
542
543void DateBookWeek::redraw()
544{
545 getEvents();
546}
547
548void DateBookWeek::slotYearChanged( int y )
549{
550 int totWeek;
551 QDate d( y, 12, 31 );
552 int throwAway;
553 calcWeek( d, totWeek, throwAway, bStartOnMonday );
554 while ( totWeek == 1 ) {
555 d = d.addDays( -1 );
556 calcWeek( d, totWeek, throwAway, bStartOnMonday );
557 }
558 if ( totWeek != totalWeeks() )
559 setTotalWeeks( totWeek );
560}
561
562
563void DateBookWeek::setTotalWeeks( int numWeeks )
564{
565 header->spinWeek->setMaxValue( numWeeks );
566}
567
568int DateBookWeek::totalWeeks() const
569{
570 return header->spinWeek->maxValue();
571}
572
573void DateBookWeek::slotWeekChanged( bool onMonday )
574{
575 bStartOnMonday = onMonday;
576 view->setStartOfWeek( bStartOnMonday );
577 header->setStartOfWeek( bStartOnMonday );
578 redraw();
579}
580
581void DateBookWeek::slotClockChanged( bool ap )
582{
583 ampm = ap;
584}
585
586// return the date at the beginning of the week...
587QDate DateBookWeek::weekDate() const
588{
589 return dateFromWeek( _week, year, bStartOnMonday );
590}
591
592// this used to only be needed by datebook.cpp, but now we need it inside
593// week view since
594// we need to be able to figure out our total number of weeks on the fly...
595// this is probably the best place to put it..
596
597// For Weeks that start on Monday... (EASY!)
598// At the moment we will use ISO 8601 method for computing
599// the week. Granted, other countries use other methods,
600// bet we aren't doing any Locale stuff at the moment. So,
601// this should pass. This Algorithim is public domain and
602// available at:
603// http://personal.ecu.edu/mccartyr/ISOwdALG.txt
604// the week number is return, and the year number is returned in year
605// for Instance 2001/12/31 is actually the first week in 2002.
606// There is a more mathematical definition, but I will implement it when
607// we are pass our deadline.
608
609// For Weeks that start on Sunday... (ahh... home rolled)
610// okay, if Jan 1 is on Friday or Saturday,
611// it will go to the pervious
612// week...
613
614bool calcWeek( const QDate &d, int &week, int &year,
615 bool startOnMonday = false )
616{
617 int weekNumber;
618 int yearNumber;
619
620 // remove a pesky warning, (Optimizations on g++)
621 weekNumber = -1;
622 int jan1WeekDay = QDate(d.year(), 1, 1).dayOfWeek();
623 int dayOfWeek = d.dayOfWeek();
624
625 if ( !d.isValid() )
626 return false;
627
628 if ( startOnMonday ) {
629 // find the Jan1Weekday;
630 if ( d.dayOfYear() <= ( 8 - jan1WeekDay) && jan1WeekDay > 4 ) {
631 yearNumber = d.year() - 1;
632 if ( jan1WeekDay == 5 || ( jan1WeekDay == 6 && QDate::leapYear(yearNumber) ) )
633 weekNumber = 53;
634 else
635 weekNumber = 52;
636 } else
637 yearNumber = d.year();
638 if ( yearNumber == d.year() ) {
639 int totalDays = 365;
640 if ( QDate::leapYear(yearNumber) )
641 totalDays++;
642 if ( ((totalDays - d.dayOfYear()) < (4 - dayOfWeek) )
643 || (jan1WeekDay == 7) && (totalDays - d.dayOfYear()) < 3) {
644 yearNumber++;
645 weekNumber = 1;
646 }
647 }
648 if ( yearNumber == d.year() ) {
649 int j = d.dayOfYear() + (7 - dayOfWeek) + ( jan1WeekDay - 1 );
650 weekNumber = j / 7;
651 if ( jan1WeekDay > 4 )
652 weekNumber--;
653 }
654 } else {
655 // it's better to keep these cases separate...
656 if ( d.dayOfYear() <= (7 - jan1WeekDay) && jan1WeekDay > 4
657 && jan1WeekDay != 7 ) {
658 yearNumber = d.year() - 1;
659 if ( jan1WeekDay == 6
660 || (jan1WeekDay == 7 && QDate::leapYear(yearNumber) ) ) {
661 weekNumber = 53;
662 }else
663 weekNumber = 52;
664 } else
665 yearNumber = d.year();
666 if ( yearNumber == d.year() ) {
667 int totalDays = 365;
668 if ( QDate::leapYear( yearNumber ) )
669 totalDays++;
670 if ( ((totalDays - d.dayOfYear()) < (4 - dayOfWeek % 7)) ) {
671 yearNumber++;
672 weekNumber = 1;
673 }
674 }
675 if ( yearNumber == d.year() ) {
676 int j = d.dayOfYear() + (7 - dayOfWeek % 7) + ( jan1WeekDay - 1 );
677 weekNumber = j / 7;
678 if ( jan1WeekDay > 4 ) {
679 weekNumber--;
680 }
681 }
682 }
683 year = yearNumber;
684 week = weekNumber;
685 return true;
686}
687