korganizer Library API Documentation

kodaymatrix.cpp

00001 /*
00002     This file is part of KOrganizer.
00003     Copyright (c) 2001 Eitzenberger Thomas <thomas.eitzenberger@siemens.at>
00004     Parts of the source code have been copied from kdpdatebutton.cpp
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019 
00020     As a special exception, permission is given to link this program
00021     with any edition of Qt, and distribute the resulting executable,
00022     without including the source code for Qt in the source distribution.
00023 */
00024 
00025 #include <qevent.h>
00026 #include <qpainter.h>
00027 #include <qptrlist.h>
00028 
00029 #include <kglobal.h>
00030 #include <kdebug.h>
00031 #include <klocale.h>
00032 
00033 #include <libkcal/vcaldrag.h>
00034 #include <libkcal/icaldrag.h>
00035 #include <libkcal/dndfactory.h>
00036 
00037 #include "koprefs.h"
00038 #include "kodaymatrix.h"
00039 #include "kodaymatrix.moc"
00040 
00041 #ifndef KORG_NOPLUGINS
00042 #include "kocore.h"
00043 #endif
00044 
00045 
00046 // ============================================================================
00047 //  D Y N A M I C   T I P
00048 // ============================================================================
00049 
00050 DynamicTip::DynamicTip( QWidget * parent )
00051     : QToolTip( parent )
00052 {
00053     matrix = (KODayMatrix*)parent;
00054 }
00055 
00056 
00057 void DynamicTip::maybeTip( const QPoint &pos )
00058 {
00059   //calculate which cell of the matrix the mouse is in
00060   QRect sz = matrix->frameRect();
00061   int dheight = sz.height()*7 / 42;
00062   int dwidth = sz.width() / 7;
00063   int row = pos.y()/dheight;
00064   int col = pos.x()/dwidth;
00065 
00066   QRect rct(col*dwidth, row*dheight, dwidth, dheight);
00067 
00068 //  kdDebug() << "DynamicTip::maybeTip matrix cell index [" <<
00069 //                col << "][" << row << "] => " <<(col+row*7) << endl;
00070 
00071   //show holiday names only
00072   QString str = matrix->getHolidayLabel(col+row*7);
00073   if (str.isEmpty()) return;
00074   tip(rct, str);
00075 }
00076 
00077 
00078 // ============================================================================
00079 //  K O D A Y M A T R I X
00080 // ============================================================================
00081 
00082 const int KODayMatrix::NOSELECTION = -1000;
00083 const int KODayMatrix::NUMDAYS = 42;
00084 
00085 KODayMatrix::KODayMatrix(QWidget *parent, Calendar* calendar, QDate date, const char *name) :
00086   QFrame(parent, name)
00087 {
00088   mCalendar = calendar;
00089 
00090   // initialize dynamic arrays
00091   days = new QDate[NUMDAYS];
00092   daylbls = new QString[NUMDAYS];
00093   events = new int[NUMDAYS];
00094   mToolTip = new DynamicTip(this);
00095 
00096   // set default values used for drawing the matrix
00097   mDefaultBackColor = palette().active().base();
00098   mDefaultTextColor = palette().active().foreground();
00099   mDefaultTextColorShaded = getShadedColor(mDefaultTextColor);
00100   mHolidayColorShaded = getShadedColor(KOPrefs::instance()->mHolidayColor);
00101   mSelectedDaysColor = QColor("white");
00102   mTodayMarginWidth = 2;
00103   mSelEnd = mSelStart = NOSELECTION;
00104 
00105   setAcceptDrops(true);
00106 
00107   updateView(date);
00108 }
00109 
00110 QColor KODayMatrix::getShadedColor(QColor color)
00111 {
00112   QColor shaded;
00113   int h=0;
00114   int s=0;
00115   int v=0;
00116   color.hsv(&h,&s,&v);
00117   s = s/4;
00118   v = 192+v/4;
00119   shaded.setHsv(h,s,v);
00120 
00121   return shaded;
00122 }
00123 
00124 KODayMatrix::~KODayMatrix()
00125 {
00126   delete [] days;
00127   delete [] daylbls;
00128   delete [] events;
00129   delete mToolTip;
00130 }
00131 
00132 /*
00133 void KODayMatrix::setStartDate(QDate start)
00134 {
00135   updateView(start);
00136 }
00137 */
00138 
00139 void KODayMatrix::addSelectedDaysTo(DateList& selDays)
00140 {
00141   kdDebug() << "KODayMatrix::addSelectedDaysTo() - " << "mSelStart:" << mSelStart << endl;
00142 
00143   if (mSelStart == NOSELECTION) {
00144     return;
00145   }
00146 
00147   //cope with selection being out of matrix limits at top (< 0)
00148   int i0 = mSelStart;
00149   if (i0 < 0) {
00150     for (int i = i0; i < 0; i++) {
00151       selDays.append(days[0].addDays(i));
00152     }
00153     i0 = 0;
00154   }
00155 
00156   //cope with selection being out of matrix limits at bottom (> NUMDAYS-1)
00157   if (mSelEnd > NUMDAYS-1) {
00158     for (int i = i0; i <= NUMDAYS-1; i++) {
00159       selDays.append(days[i]);
00160     }
00161     for (int i = NUMDAYS; i < mSelEnd; i++) {
00162       selDays.append(days[0].addDays(i));
00163     }
00164 
00165   // apply normal routine to selection being entirely within matrix limits
00166   } else {
00167     for (int i = i0; i <= mSelEnd; i++) {
00168       selDays.append(days[i]);
00169     }
00170   }
00171 }
00172 
00173 void KODayMatrix::setSelectedDaysFrom(const QDate& start, const QDate& end)
00174 {
00175   mSelStart = startdate.daysTo(start);
00176   mSelEnd = startdate.daysTo(end);
00177 }
00178 
00179 
00180 void KODayMatrix::recalculateToday()
00181 {
00182     today = -1;
00183     for (int i=0; i<NUMDAYS; i++) {
00184       days[i] = startdate.addDays(i);
00185       daylbls[i] = QString::number( KOCore::self()->calendarSystem()->day( days[i] ));
00186       
00187       // if today is in the currently displayed month, hilight today
00188       if (days[i].year() == QDate::currentDate().year() &&
00189           days[i].month() == QDate::currentDate().month() &&
00190           days[i].day() == QDate::currentDate().day()) {
00191         today = i;
00192       }
00193     }
00194     // qDebug(QString("Today is visible at %1.").arg(today));
00195 }
00196 
00197 /* slot */ void KODayMatrix::updateView()
00198 {
00199   updateView(startdate);
00200 }
00201 
00202 void KODayMatrix::updateView(QDate actdate)
00203 {
00204 //  kdDebug() << "KODayMatrix::updateView() " << actdate.toString() << endl;
00205 
00206   //flag to indicate if the starting day of the matrix has changed by this call
00207   bool daychanged = false;
00208 
00209   // if a new startdate is to be set then apply Cornelius's calculation
00210   // of the first day to be shown
00211   if (actdate != startdate) {
00212     // reset index of selection according to shift of starting date from startdate to actdate
00213     if (mSelStart != NOSELECTION) {
00214       int tmp = actdate.daysTo(startdate);
00215       //kdDebug() << "Shift of Selection1: " << mSelStart << " - " << mSelEnd << " -> " << tmp << "(" << offset << ")" << endl;
00216       // shift selection if new one would be visible at least partly !
00217 
00218         if (mSelStart+tmp < NUMDAYS && mSelEnd+tmp >= 0) {
00219                 // nested if is required for next X display pushed from a different month - correction required
00220                 // otherwise, for month forward and backward, it must be avoided
00221                 if( mSelStart > NUMDAYS || mSelStart < 0 )
00222                    mSelStart = mSelStart + tmp;
00223                 if( mSelEnd > NUMDAYS || mSelEnd < 0 )
00224                         mSelEnd = mSelEnd + tmp;
00225       } 
00226     }
00227 
00228     startdate = actdate;
00229     daychanged = true;
00230   }
00231 
00232   if (daychanged) {
00233     recalculateToday();
00234   }
00235 
00236     for(int i = 0; i < NUMDAYS; i++) {
00237 
00238     // if events are set for the day then remember to draw it bold
00239     QPtrList<Event> eventlist = mCalendar->events(days[i]);
00240     Event *event;
00241     int numEvents = eventlist.count();
00242 
00243     for(event=eventlist.first();event != 0;event=eventlist.next()) {
00244       ushort recurType = event->recurrence()->doesRecur();
00245 
00246       if ((recurType == Recurrence::rDaily && !KOPrefs::instance()->mDailyRecur) ||
00247           (recurType == Recurrence::rWeekly && !KOPrefs::instance()->mWeeklyRecur)) {
00248         numEvents--;
00249       }
00250     }
00251     events[i] = numEvents;
00252 
00253     //if it is a holy day then draw it red. Sundays are consider holidays, too
00254 #ifndef KORG_NOPLUGINS
00255     QString holiStr = KOCore::self()->holiday(days[i]);
00256 #else
00257     QString holiStr = QString::null;
00258 #endif
00259    if ( (KOCore::self()->calendarSystem()->dayOfTheWeek(days[i]) == KOCore::self()->calendarSystem()->weekDayOfPray()) ||
00260         !holiStr.isEmpty()) {
00261       if (holiStr.isNull()) holiStr = "";
00262       mHolidays[i] = holiStr;
00263 
00264     } else {
00265       mHolidays[i] = QString::null;
00266     }
00267   }
00268 }
00269 
00270 const QDate& KODayMatrix::getDate(int offset)
00271 {
00272   if (offset < 0 || offset > NUMDAYS-1) {
00273     kdDebug() << "Wrong offset (" << offset << ") in KODayMatrix::getDate(int)" << endl;
00274     return days[0];
00275   }
00276   return days[offset];
00277 }
00278 
00279 QString KODayMatrix::getHolidayLabel(int offset)
00280 {
00281   if (offset < 0 || offset > NUMDAYS-1) {
00282     kdDebug() << "Wrong offset (" << offset << ") in KODayMatrix::getHolidayLabel(int)" << endl;
00283     return 0;
00284   }
00285   return mHolidays[offset];
00286 }
00287 
00288 int KODayMatrix::getDayIndexFrom(int x, int y)
00289 {
00290   return 7*(y/daysize.height()) + (QApplication::reverseLayout() ? 
00291             6 - x/daysize.width() : x/daysize.width());
00292 }
00293 
00294 // ----------------------------------------------------------------------------
00295 //  M O U S E   E V E N T   H A N D L I N G
00296 // ----------------------------------------------------------------------------
00297 
00298 void KODayMatrix::mousePressEvent (QMouseEvent* e)
00299 {
00300   mSelStart = getDayIndexFrom(e->x(), e->y());
00301   if (mSelStart > NUMDAYS-1) mSelStart=NUMDAYS-1;
00302   mSelInit = mSelStart;
00303 }
00304 
00305 void KODayMatrix::mouseReleaseEvent (QMouseEvent* e)
00306 {
00307   int tmp = getDayIndexFrom(e->x(), e->y());
00308   if (tmp > NUMDAYS-1) tmp=NUMDAYS-1;
00309 
00310   if (mSelInit > tmp) {
00311     mSelEnd = mSelInit;
00312     if (tmp != mSelStart) {
00313       mSelStart = tmp;
00314       repaint();
00315     }
00316   } else {
00317     mSelStart = mSelInit;
00318 
00319     //repaint only if selection has changed
00320     if (tmp != mSelEnd) {
00321       mSelEnd = tmp;
00322       repaint();
00323     }
00324   }
00325 
00326   DateList daylist;
00327   for (int i = mSelStart; i <= mSelEnd; i++) {
00328     daylist.append(days[i]);
00329   }
00330   emit selected((const DateList)daylist);
00331 }
00332 
00333 void KODayMatrix::mouseMoveEvent (QMouseEvent* e)
00334 {
00335   int tmp = getDayIndexFrom(e->x(), e->y());
00336   if (tmp > NUMDAYS-1) tmp=NUMDAYS-1;
00337 
00338   if (mSelInit > tmp) {
00339     mSelEnd = mSelInit;
00340     if (tmp != mSelStart) {
00341       mSelStart = tmp;
00342       repaint();
00343     }
00344   } else {
00345     mSelStart = mSelInit;
00346 
00347     //repaint only if selection has changed
00348     if (tmp != mSelEnd) {
00349       mSelEnd = tmp;
00350       repaint();
00351     }
00352   }
00353 }
00354 
00355 // ----------------------------------------------------------------------------
00356 //  D R A G ' N   D R O P   H A N D L I N G
00357 // ----------------------------------------------------------------------------
00358 
00359 void KODayMatrix::dragEnterEvent(QDragEnterEvent *e)
00360 {
00361 #ifndef KORG_NODND
00362   if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) {
00363     e->ignore();
00364     return;
00365   }
00366 
00367   // some visual feedback
00368 //  oldPalette = palette();
00369 //  setPalette(my_HilitePalette);
00370 //  update();
00371 #endif
00372 }
00373 
00374 void KODayMatrix::dragMoveEvent(QDragMoveEvent *e)
00375 {
00376 #ifndef KORG_NODND
00377   if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) {
00378     e->ignore();
00379     return;
00380   }
00381 
00382   e->accept();
00383 #endif
00384 }
00385 
00386 void KODayMatrix::dragLeaveEvent(QDragLeaveEvent */*dl*/)
00387 {
00388 #ifndef KORG_NODND
00389 //  setPalette(oldPalette);
00390 //  update();
00391 #endif
00392 }
00393 
00394 void KODayMatrix::dropEvent(QDropEvent *e)
00395 {
00396 #ifndef KORG_NODND
00397 //  kdDebug() << "KODayMatrix::dropEvent(e) begin" << endl;
00398 
00399   if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) {
00400     e->ignore();
00401     return;
00402   }
00403 
00404   DndFactory factory( mCalendar );
00405   Event *event = factory.createDrop(e);
00406 
00407   if (event) {
00408     e->acceptAction();
00409 
00410     Event *existingEvent = mCalendar->event(event->uid());
00411 
00412     if(existingEvent) {
00413       // uniquify event
00414       event->recreate();
00415 /*
00416       KMessageBox::sorry(this,
00417               i18n("Event already exists in this calendar."),
00418               i18n("Drop Event"));
00419       delete event;
00420       return;
00421 */
00422     }
00423 //      kdDebug() << "Drop new Event" << endl;
00424     // Adjust date
00425     QDateTime start = event->dtStart();
00426     QDateTime end = event->dtEnd();
00427     int duration = start.daysTo(end);
00428     int idx = getDayIndexFrom(e->pos().x(), e->pos().y());
00429 
00430     start.setDate(days[idx]);
00431     end.setDate(days[idx].addDays(duration));
00432 
00433     event->setDtStart(start);
00434     event->setDtEnd(end);
00435     mCalendar->addEvent(event);
00436 
00437     emit eventDropped(event);
00438   } else {
00439 //    kdDebug() << "KODayMatrix::dropEvent(): Event from drop not decodable" << endl;
00440     e->ignore();
00441   }
00442 #endif
00443 }
00444 
00445 // ----------------------------------------------------------------------------
00446 //  P A I N T   E V E N T   H A N D L I N G
00447 // ----------------------------------------------------------------------------
00448 
00449 void KODayMatrix::paintEvent(QPaintEvent * pevent)
00450 {
00451 //kdDebug() << "KODayMatrix::paintEvent() BEGIN" << endl;
00452 
00453   QPainter p(this);
00454 
00455   QRect sz = frameRect();
00456   int dheight = daysize.height();
00457   int dwidth = daysize.width();
00458   int row,col;
00459   int selw, selh;
00460   bool isRTL = QApplication::reverseLayout();
00461 
00462   // draw background and topleft frame
00463   p.fillRect(pevent->rect(), mDefaultBackColor);
00464   p.setPen(mDefaultTextColor);
00465   p.drawRect(0, 0, sz.width()+1, sz.height()+1);
00466 
00467   // draw selected days with highlighted background color
00468   if (mSelStart != NOSELECTION) {
00469 
00470     row = mSelStart/7;
00471     col = mSelStart -row*7;
00472     QColor selcol = KOPrefs::instance()->mHighlightColor;
00473 
00474     if (row == mSelEnd/7) {
00475       // Single row selection
00476       p.fillRect(isRTL ? (7 - (mSelEnd-mSelStart+1) - col)*dwidth : col*dwidth,
00477                   row*dheight, (mSelEnd-mSelStart+1)*dwidth, dheight, selcol);
00478     } else {
00479       // draw first row to the right
00480       p.fillRect(isRTL ? 0 : col*dwidth, row*dheight, (7-col)*dwidth,
00481                  dheight, selcol);
00482       // draw full block till last line
00483       selh = mSelEnd/7-row;
00484       if (selh > 1) {
00485         p.fillRect(0, (row+1)*dheight, 7*dwidth, (selh-1)*dheight,selcol);
00486       }
00487       // draw last block from left to mSelEnd
00488       selw = mSelEnd-7*(mSelEnd/7)+1;
00489       p.fillRect(isRTL ? (7-selw)*dwidth : 0, (row+selh)*dheight,
00490                  selw*dwidth, dheight, selcol);
00491     }
00492   }
00493 
00494   // iterate over all days in the matrix and draw the day label in appropriate colors
00495   QColor actcol = mDefaultTextColorShaded;
00496   p.setPen(actcol);
00497   QPen tmppen;
00498   for(int i = 0; i < NUMDAYS; i++) {
00499     row = i/7;
00500     col = isRTL ? 6-(i-row*7) : i-row*7;
00501 
00502     // if it is the first day of a month switch color from normal to shaded and vice versa
00503     if ( KOCore::self()->calendarSystem()->day( days[i] ) == 1) {
00504       if (actcol == mDefaultTextColorShaded) {
00505         actcol = mDefaultTextColor;
00506       } else {
00507         actcol = mDefaultTextColorShaded;
00508       }
00509       p.setPen(actcol);
00510     }
00511 
00512     //Reset pen color after selected days block
00513     if (i == mSelEnd+1) {
00514       p.setPen(actcol);
00515     }
00516 
00517     // if today then draw rectangle around day
00518     if (today == i) {
00519       tmppen = p.pen();
00520       QPen mTodayPen(p.pen());
00521 
00522       mTodayPen.setWidth(mTodayMarginWidth);
00523       //draw red rectangle for holidays
00524       if (!mHolidays[i].isNull()) {
00525         if (actcol == mDefaultTextColor) {
00526           mTodayPen.setColor(KOPrefs::instance()->mHolidayColor);
00527         } else {
00528           mTodayPen.setColor(mHolidayColorShaded);
00529         }
00530       }
00531       //draw gray rectangle for today if in selection
00532       if (i >= mSelStart && i <= mSelEnd) {
00533         QColor grey("grey");
00534         mTodayPen.setColor(grey);
00535       }
00536       p.setPen(mTodayPen);
00537       p.drawRect(col*dwidth, row*dheight, dwidth, dheight);
00538       p.setPen(tmppen);
00539     }
00540 
00541     // if any events are on that day then draw it using a bold font
00542     if (events[i] > 0) {
00543       QFont myFont = font();
00544       myFont.setBold(true);
00545       p.setFont(myFont);
00546     }
00547 
00548     // if it is a holiday then use the default holiday color
00549     if (!mHolidays[i].isNull()) {
00550       if (actcol == mDefaultTextColor) {
00551         p.setPen(KOPrefs::instance()->mHolidayColor);
00552       } else {
00553         p.setPen(mHolidayColorShaded);
00554       }
00555     }
00556 
00557     // draw selected days with special color
00558     // DO NOT specially highlight holidays in selection !
00559     if (i >= mSelStart && i <= mSelEnd) {
00560       p.setPen(mSelectedDaysColor);
00561     }
00562 
00563     p.drawText(col*dwidth, row*dheight, dwidth, dheight,
00564               Qt::AlignHCenter | Qt::AlignVCenter,  daylbls[i]);
00565 
00566     // reset color to actual color
00567     if (!mHolidays[i].isNull()) {
00568       p.setPen(actcol);
00569     }
00570     // reset bold font to plain font
00571     if (events[i] > 0) {
00572       QFont myFont = font();
00573       myFont.setBold(false);
00574       p.setFont(myFont);
00575     }
00576   }
00577 }
00578 
00579 // ----------------------------------------------------------------------------
00580 //  R E SI Z E   E V E N T   H A N D L I N G
00581 // ----------------------------------------------------------------------------
00582 
00583 void KODayMatrix::resizeEvent(QResizeEvent *)
00584 {
00585   QRect sz = frameRect();
00586   daysize.setHeight(sz.height()*7 / NUMDAYS);
00587   daysize.setWidth(sz.width() / 7);
00588 }
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 15 11:41:09 2004 by doxygen 1.3.5 written by Dimitri van Heesch, © 1997-2001