00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "datebookweek.h"
00032 #include "datebookweekheaderimpl.h"
00033 #include "datebooktypes.h"
00034
00035 #include <qpe/datebookdb.h>
00036 #include <qpe/qpeapplication.h>
00037 #include <qpe/calendar.h>
00038
00039 #include <qheader.h>
00040 #include <qlabel.h>
00041 #include <qlayout.h>
00042 #include <qtimer.h>
00043
00044
00045
00046
00047 DateBookWeekItem::DateBookWeekItem( const EffectiveEvent e )
00048 : ev( e )
00049 {
00050
00051 if ( ev.event().type() == Event::AllDay && !ev.event().hasAlarm() ) {
00052 c = Qt::green;
00053 } else {
00054 c = ev.event().hasAlarm() ? Qt::red : Qt::blue;
00055 }
00056 }
00057
00058 void DateBookWeekItem::setGeometry( int x, int y, int w, int h )
00059 {
00060 r.setRect( x, y, w, h );
00061 }
00062
00063
00064
00065
00066 DateBookWeekView::DateBookWeekView( bool ap, bool startOnMonday,
00067 QWidget *parent, const char *name )
00068 : QScrollView( parent, name ), ampm( ap ), bOnMonday( startOnMonday ),
00069 showingEvent( false )
00070 {
00071 items.setAutoDelete( true );
00072
00073 viewport()->setBackgroundMode( PaletteBase );
00074
00075 header = new QHeader( this );
00076 header->addLabel( "" );
00077
00078 header->setMovingEnabled( false );
00079 header->setResizeEnabled( false );
00080 header->setClickEnabled( false, 0 );
00081 initNames();
00082
00083
00084 connect( header, SIGNAL(clicked(int)), this, SIGNAL(showDay(int)) );
00085
00086 QObject::connect(qApp, SIGNAL(clockChanged(bool)),
00087 this, SLOT(slotChangeClock(bool)));
00088
00089 QFontMetrics fm( font() );
00090 rowHeight = fm.height()+2;
00091
00092 resizeContents( width(), 24*rowHeight );
00093 }
00094
00095 void DateBookWeekView::initNames()
00096 {
00097
00098 static bool bFirst = true;
00099 if ( bFirst ) {
00100 if ( bOnMonday ) {
00101 for ( int i = 1; i<=7; i++ ) {
00102 header->addLabel( Calendar::nameOfDay( i ) );
00103 }
00104
00105 } else {
00106 header->addLabel( Calendar::nameOfDay( 7 ) );
00107 for ( int i = 1; i<7; i++ ) {
00108 header->addLabel( Calendar::nameOfDay( i ) );
00109 }
00110 }
00111 bFirst = false;
00112 } else {
00113
00114 if ( bOnMonday ) {
00115 for ( int i = 1; i<=7; i++ ) {
00116 header->setLabel( i, Calendar::nameOfDay( i ) );
00117 }
00118
00119 } else {
00120 header->setLabel( 1, Calendar::nameOfDay( 7 ) );
00121 for ( int i = 1; i<7; i++ ) {
00122 header->setLabel( i+1, Calendar::nameOfDay( i ) );
00123 }
00124
00125 }
00126 }
00127 }
00128
00129
00130
00131 void DateBookWeekView::showEvents( QValueList<EffectiveEvent> &ev )
00132 {
00133 items.clear();
00134 QValueListIterator<EffectiveEvent> it;
00135 for ( it = ev.begin(); it != ev.end(); ++it ) {
00136 DateBookWeekItem *i = new DateBookWeekItem( *it );
00137 if(!((i->event().end().hour()==0) && (i->event().end().minute()==0) && (i->event().startDate()!=i->event().date()))) {
00138 positionItem( i );
00139 items.append( i );
00140 }
00141 }
00142 viewport()->update();
00143 }
00144
00145 void DateBookWeekView::moveToHour( int h )
00146 {
00147 int offset = h*rowHeight;
00148 setContentsPos( 0, offset );
00149 }
00150
00151 void DateBookWeekView::keyPressEvent( QKeyEvent *e )
00152 {
00153 e->ignore();
00154 }
00155
00156 void DateBookWeekView::slotChangeClock( bool c )
00157 {
00158 ampm = c;
00159 viewport()->update();
00160 }
00161
00162 static inline int db_round30min( int m )
00163 {
00164 if ( m < 15 )
00165 m = 0;
00166 else if ( m < 45 )
00167 m = 1;
00168 else
00169 m = 2;
00170
00171 return m;
00172 }
00173
00174 void DateBookWeekView::alterDay( int day )
00175 {
00176 if ( !bOnMonday ) {
00177 day--;
00178 }
00179 emit showDay( day );
00180 }
00181
00182 void DateBookWeekView::positionItem( DateBookWeekItem *i )
00183 {
00184 const int Width = 8;
00185 const EffectiveEvent ev = i->event();
00186
00187
00188 int y = ev.start().hour() * 2;
00189 y += db_round30min( ev.start().minute() );
00190 int y2 = ev.end().hour() * 2;
00191 y2 += db_round30min( ev.end().minute() );
00192 if ( y > 47 ) y = 47;
00193 if ( y2 > 48 ) y2 = 48;
00194 y = (y * rowHeight) / 2;
00195 y2 = (y2 * rowHeight) / 2;
00196
00197 int h;
00198 if ( ev.event().type() == Event::AllDay ) {
00199 h = (48 * rowHeight) / 2;
00200 y = 0;
00201 } else {
00202 h=y2-y;
00203 if ( h < (1*rowHeight)/2 ) h = (1*rowHeight)/2;
00204 }
00205
00206 int dow = ev.date().dayOfWeek();
00207 if ( !bOnMonday ) {
00208 if ( dow == 7 )
00209 dow = 1;
00210 else
00211 dow++;
00212 }
00213 int x = header->sectionPos( dow ) - 1;
00214 int xlim = header->sectionPos( dow ) + header->sectionSize( dow );
00215 DateBookWeekItem *isect = 0;
00216 do {
00217 i->setGeometry( x, y, Width, h );
00218 isect = intersects( i );
00219 x += Width - 1;
00220 } while ( isect && x < xlim );
00221 }
00222
00223 DateBookWeekItem *DateBookWeekView::intersects( const DateBookWeekItem *item )
00224 {
00225 QRect geom = item->geometry();
00226
00227
00228 geom.moveBy( 1, 1 );
00229 geom.setSize( geom.size()-QSize(2,2) );
00230
00231 QListIterator<DateBookWeekItem> it(items);
00232 for ( ; it.current(); ++it ) {
00233 DateBookWeekItem *i = it.current();
00234 if ( i != item ) {
00235 if ( i->geometry().intersects( geom ) ) {
00236 return i;
00237 }
00238 }
00239 }
00240
00241 return 0;
00242 }
00243
00244 void DateBookWeekView::contentsMousePressEvent( QMouseEvent *e )
00245 {
00246 QListIterator<DateBookWeekItem> it(items);
00247 for ( ; it.current(); ++it ) {
00248 DateBookWeekItem *i = it.current();
00249 if ( i->geometry().contains( e->pos() ) ) {
00250 showingEvent = true;
00251 emit signalShowEvent( i->event() );
00252 break;
00253 }
00254 }
00255 }
00256
00257 void DateBookWeekView::contentsMouseReleaseEvent( QMouseEvent *e )
00258 {
00259 if ( showingEvent ) {
00260 showingEvent = false;
00261 emit signalHideEvent();
00262 } else {
00263 int d = header->sectionAt( e->pos().x() );
00264 if ( d > 0 ) {
00265
00266
00267 emit showDay( d );
00268 }
00269 }
00270 }
00271
00272 void DateBookWeekView::drawContents( QPainter *p, int cx, int cy, int cw, int ch )
00273 {
00274 QRect ur( cx, cy, cw, ch );
00275 p->setPen( lightGray );
00276 for ( int i = 1; i <= 7; i++ )
00277 p->drawLine( header->sectionPos(i)-2, cy, header->sectionPos(i)-2, cy+ch );
00278
00279 p->setPen( black );
00280 for ( int t = 0; t < 24; t++ ) {
00281 int y = t*rowHeight;
00282 if ( QRect( 1, y, 20, rowHeight ).intersects( ur ) ) {
00283 QString s;
00284 if ( ampm ) {
00285 if ( t == 0 )
00286 s = QString::number( 12 );
00287 else if ( t == 12 )
00288 s = QString::number(12) + tr( "p" );
00289 else if ( t > 12 ) {
00290 if ( t - 12 < 10 )
00291 s = " ";
00292 else
00293 s = "";
00294 s += QString::number( t - 12 ) + tr("p");
00295 } else {
00296 if ( 12 - t < 3 )
00297 s = "";
00298 else
00299 s = " ";
00300 s += QString::number( t );
00301 }
00302 } else {
00303 s = QString::number( t );
00304 if ( s.length() == 1 )
00305 s.prepend( "0" );
00306 }
00307 p->drawText( 1, y+p->fontMetrics().ascent()+1, s );
00308 }
00309 }
00310
00311 QListIterator<DateBookWeekItem> it(items);
00312 for ( ; it.current(); ++it ) {
00313 DateBookWeekItem *i = it.current();
00314 if ( i->geometry().intersects( ur ) ) {
00315 p->setBrush( i->color() );
00316 p->drawRect( i->geometry() );
00317 }
00318 }
00319 }
00320
00321 void DateBookWeekView::resizeEvent( QResizeEvent *e )
00322 {
00323 const int hourWidth = 20;
00324 QScrollView::resizeEvent( e );
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335 int avail = width()-qApp->style().scrollBarExtent().width()-1;
00336 header->setGeometry( 0, 0, avail, header->sizeHint().height() );
00337 setMargins( 0, header->height(), 0, 0 );
00338
00339
00340 header->resizeSection( 0, hourWidth );
00341 int sw = (avail - hourWidth) / 7;
00342 for ( int i = 1; i < 7; i++ )
00343 header->resizeSection( i, sw );
00344 header->resizeSection( 7, avail - hourWidth - sw*6 );
00345 }
00346
00347 void DateBookWeekView::setStartOfWeek( bool bStartOnMonday )
00348 {
00349 bOnMonday = bStartOnMonday;
00350 initNames();
00351 }
00352
00353
00354
00355 DateBookWeek::DateBookWeek( bool ap, bool startOnMonday, DateBookDBHoliday *newDB,
00356 QWidget *parent, const char *name )
00357 : QWidget( parent, name ),
00358 db( newDB ),
00359 startTime( 0 ),
00360 ampm( ap ),
00361 bStartOnMonday( startOnMonday )
00362 {
00363 setFocusPolicy(StrongFocus);
00364 QVBoxLayout *vb = new QVBoxLayout( this );
00365 header = new DateBookWeekHeader( bStartOnMonday, this );
00366 view = new DateBookWeekView( ampm, startOnMonday, this );
00367 vb->addWidget( header );
00368 vb->addWidget( view );
00369
00370 lblDesc = new QLabel( this, "event label" );
00371 lblDesc->setFrameStyle( QFrame::Plain | QFrame::Box );
00372 lblDesc->setBackgroundColor( yellow );
00373 lblDesc->hide();
00374
00375 tHide = new QTimer( this );
00376
00377 connect( view, SIGNAL( showDay(int) ), this, SLOT( showDay(int) ) );
00378 connect( view, SIGNAL(signalShowEvent(const EffectiveEvent&)), this, SLOT(slotShowEvent(const EffectiveEvent&)) );
00379 connect( view, SIGNAL(signalHideEvent()), this, SLOT(slotHideEvent()) );
00380 connect( header, SIGNAL( dateChanged(QDate&) ), this, SLOT( dateChanged(QDate&) ) );
00381 connect( tHide, SIGNAL( timeout() ), lblDesc, SLOT( hide() ) );
00382 connect( qApp, SIGNAL(weekChanged(bool)), this, SLOT(slotWeekChanged(bool)) );
00383 connect( qApp, SIGNAL(clockChanged(bool)), this, SLOT(slotClockChanged(bool)));
00384 setDate(QDate::currentDate());
00385 }
00386
00387 void DateBookWeek::keyPressEvent(QKeyEvent *e)
00388 {
00389 switch(e->key()) {
00390 case Key_Up:
00391 view->scrollBy(0, -20);
00392 break;
00393 case Key_Down:
00394 view->scrollBy(0, 20);
00395 break;
00396 case Key_Left:
00397 setDate(date().addDays(-7));
00398 break;
00399 case Key_Right:
00400 setDate(date().addDays(7));
00401 break;
00402 default:
00403 e->ignore();
00404 }
00405 }
00406
00407 void DateBookWeek::showDay( int day )
00408 {
00409 QDate d=bdate;
00410
00411
00412 int dayoffset=d.dayOfWeek() % 7;
00413
00414 if(bStartOnMonday) dayoffset--;
00415
00416 day--;
00417 d=d.addDays(day-dayoffset);
00418 emit showDate( d.year(), d.month(), d.day() );
00419 }
00420
00421 void DateBookWeek::setDate( int y, int m, int d )
00422 {
00423 setDate(QDate(y, m, d));
00424 }
00425
00426 void DateBookWeek::setDate(QDate newdate)
00427 {
00428 bdate=newdate;
00429 dow = newdate.dayOfWeek();
00430 header->setDate( newdate );
00431 }
00432
00433 void DateBookWeek::dateChanged( QDate &newdate )
00434 {
00435 bdate=newdate;
00436 getEvents();
00437 }
00438
00439 QDate DateBookWeek::date() const
00440 {
00441 return bdate;
00442 }
00443
00444 void DateBookWeek::getEvents()
00445 {
00446 QDate startWeek = weekDate();
00447
00448 QDate endWeek = startWeek.addDays( 6 );
00449 QValueList<EffectiveEvent> eventList = db->getEffectiveEvents(startWeek, endWeek);
00450 view->showEvents( eventList );
00451 view->moveToHour( startTime );
00452 }
00453
00454 void DateBookWeek::generateAllDayTooltext( QString& text ) {
00455 text += "<b>" + tr("This is an all day event.") + "</b><br>";
00456 }
00457
00458 void DateBookWeek::generateNormalTooltext( QString& str, const EffectiveEvent &ev ) {
00459 str += "<b>" + QObject::tr("Start") + "</b>: ";
00460 str += TimeString::timeString( ev.event().start().time(), ampm, FALSE );
00461 if( ev.startDate()!=ev.endDate() ) {
00462 str += " <i>" + TimeString::longDateString( ev.startDate() )+"</i>";
00463 }
00464 str += "<br>";
00465 str += "<b>" + QObject::tr("End") + "</b>: ";
00466 str += TimeString::timeString( ev.event().end().time(), ampm, FALSE );
00467 if( ev.startDate()!=ev.endDate() ) {
00468 str += " <i>" + TimeString::longDateString( ev.endDate() ) + "</i>";
00469 }
00470 }
00471
00472 void DateBookWeek::slotShowEvent( const EffectiveEvent &ev )
00473 {
00474 if ( tHide->isActive() )
00475 tHide->stop();
00476
00477
00478
00479 QString strDesc = ev.description();
00480 int where = strDesc.find( "<" );
00481 while ( where != -1 ) {
00482 strDesc.remove( where, 1 );
00483 strDesc.insert( where, "<" );
00484 where = strDesc.find( "<", where );
00485 }
00486
00487 QString strCat;
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497 QString strLocation = ev.location();
00498 while ( where != -1 ) {
00499 strLocation.remove( where, 1 );
00500 strLocation.insert( where, "<" );
00501 where = strLocation.find( "<", where );
00502 }
00503
00504 QString strNote = ev.notes();
00505 where = strNote.find( "<" );
00506 while ( where != -1 ) {
00507 strNote.remove( where, 1 );
00508 strNote.insert( where, "<" );
00509 where = strNote.find( "<", where );
00510 }
00511
00512 QString str = "<b>" + strDesc + "</b><br>"
00513 + strLocation + "<br>"
00514 + "<i>" + strCat + "</i>"
00515 + "<br>" + TimeString::longDateString( ev.date() )
00516 + "<br>";
00517
00518 if (ev.event().type() == Event::Normal )
00519 generateNormalTooltext( str, ev );
00520 else
00521 generateAllDayTooltext( str );
00522
00523 str += "<br><br>" + strNote;
00524
00525 lblDesc->setText( str );
00526 lblDesc->resize( lblDesc->sizeHint() );
00527
00528 lblDesc->move( QMAX(0,(width() - lblDesc->width()) / 2), 0 );
00529 lblDesc->show();
00530 }
00531
00532 void DateBookWeek::slotHideEvent()
00533 {
00534 tHide->start( 2000, true );
00535 }
00536
00537 void DateBookWeek::setStartViewTime( int startHere )
00538 {
00539 startTime = startHere;
00540 view->moveToHour( startTime );
00541 }
00542
00543 int DateBookWeek::startViewTime() const
00544 {
00545 return startTime;
00546 }
00547
00548 void DateBookWeek::redraw()
00549 {
00550 getEvents();
00551 }
00552
00553 void DateBookWeek::slotYearChanged( int y )
00554 {
00555 int totWeek;
00556 QDate d( y, 12, 31 );
00557 int throwAway;
00558 calcWeek( d, totWeek, throwAway, bStartOnMonday );
00559 while ( totWeek == 1 ) {
00560 d = d.addDays( -1 );
00561 calcWeek( d, totWeek, throwAway, bStartOnMonday );
00562 }
00563 }
00564
00565 void DateBookWeek::slotWeekChanged( bool onMonday )
00566 {
00567 bStartOnMonday = onMonday;
00568 view->setStartOfWeek( bStartOnMonday );
00569 header->setStartOfWeek( bStartOnMonday );
00570 redraw();
00571 }
00572
00573 void DateBookWeek::slotClockChanged( bool ap )
00574 {
00575 ampm = ap;
00576 }
00577
00578
00579 QDate DateBookWeek::weekDate() const
00580 {
00581 QDate d=bdate;
00582
00583
00584 int dayoffset=d.dayOfWeek();
00585 if(bStartOnMonday) dayoffset--;
00586 else if( dayoffset == 7 )
00587 dayoffset = 0;
00588
00589 return d.addDays(-dayoffset);
00590 }
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614 bool calcWeek( const QDate &d, int &week, int &year,
00615 bool startOnMonday )
00616 {
00617 int weekNumber;
00618 int yearNumber;
00619
00620
00621 weekNumber = -1;
00622 int jan1WeekDay = QDate(d.year(), 1, 1).dayOfWeek();
00623 int dayOfWeek = d.dayOfWeek();
00624
00625 if ( !d.isValid() )
00626 return false;
00627
00628 if ( startOnMonday ) {
00629
00630 if ( d.dayOfYear() <= ( 8 - jan1WeekDay) && jan1WeekDay > 4 ) {
00631 yearNumber = d.year() - 1;
00632 if ( jan1WeekDay == 5 || ( jan1WeekDay == 6 && QDate::leapYear(yearNumber) ) )
00633 weekNumber = 53;
00634 else
00635 weekNumber = 52;
00636 } else
00637 yearNumber = d.year();
00638 if ( yearNumber == d.year() ) {
00639 int totalDays = 365;
00640 if ( QDate::leapYear(yearNumber) )
00641 totalDays++;
00642 if ( ((totalDays - d.dayOfYear()) < (4 - dayOfWeek) )
00643 || (jan1WeekDay == 7) && (totalDays - d.dayOfYear()) < 3) {
00644 yearNumber++;
00645 weekNumber = 1;
00646 }
00647 }
00648 if ( yearNumber == d.year() ) {
00649 int j = d.dayOfYear() + (7 - dayOfWeek) + ( jan1WeekDay - 1 );
00650 weekNumber = j / 7;
00651 if ( jan1WeekDay > 4 )
00652 weekNumber--;
00653 }
00654 } else {
00655
00656 if ( d.dayOfYear() <= (7 - jan1WeekDay) && jan1WeekDay > 4
00657 && jan1WeekDay != 7 ) {
00658 yearNumber = d.year() - 1;
00659 if ( jan1WeekDay == 6
00660 || (jan1WeekDay == 7 && QDate::leapYear(yearNumber) ) ) {
00661 weekNumber = 53;
00662 }else
00663 weekNumber = 52;
00664 } else
00665 yearNumber = d.year();
00666 if ( yearNumber == d.year() ) {
00667 int totalDays = 365;
00668 if ( QDate::leapYear( yearNumber ) )
00669 totalDays++;
00670 if ( ((totalDays - d.dayOfYear()) < (4 - dayOfWeek % 7)) ) {
00671 yearNumber++;
00672 weekNumber = 1;
00673 }
00674 }
00675 if ( yearNumber == d.year() ) {
00676 int j = d.dayOfYear() + (7 - dayOfWeek % 7) + ( jan1WeekDay - 1 );
00677 weekNumber = j / 7;
00678 if ( jan1WeekDay > 4 ) {
00679 weekNumber--;
00680 }
00681 }
00682 }
00683 year = yearNumber;
00684 week = weekNumber;
00685 return true;
00686 }
00687