-rw-r--r-- | korganizer/kodaymatrix.cpp | 597 |
1 files changed, 597 insertions, 0 deletions
diff --git a/korganizer/kodaymatrix.cpp b/korganizer/kodaymatrix.cpp new file mode 100644 index 0000000..779d67c --- a/dev/null +++ b/korganizer/kodaymatrix.cpp @@ -0,0 +1,597 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Eitzenberger Thomas <thomas.eitzenberger@siemens.at> + Parts of the source code have been copied from kdpdatebutton.cpp + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qevent.h> +#include <qpainter.h> +#include <qptrlist.h> + +#include <kglobal.h> +#include <kdebug.h> +#include <klocale.h> + +#include <libkcal/vcaldrag.h> +#include <libkcal/icaldrag.h> +#include <libkcal/dndfactory.h> +#include <libkcal/calendarresources.h> +#include <libkcal/resourcecalendar.h> +#include <kresources/resourceselectdialog.h> + +#include <kcalendarsystem.h> + +#ifndef KORG_NOPLUGINS +#include "kocore.h" +#endif +#include "koprefs.h" +#include "koglobals.h" + +#include "kodaymatrix.h" +#include "kodaymatrix.moc" + +// ============================================================================ +// D Y N A M I C T I P +// ============================================================================ + +DynamicTip::DynamicTip( QWidget * parent ) + : QToolTip( parent ) +{ + matrix = (KODayMatrix*)parent; +} + + +void DynamicTip::maybeTip( const QPoint &pos ) +{ + //calculate which cell of the matrix the mouse is in + QRect sz = matrix->frameRect(); + int dheight = sz.height()*7 / 42; + int dwidth = sz.width() / 7; + int row = pos.y()/dheight; + int col = pos.x()/dwidth; + + QRect rct(col*dwidth, row*dheight, dwidth, dheight); + +// kdDebug() << "DynamicTip::maybeTip matrix cell index [" << +// col << "][" << row << "] => " <<(col+row*7) << endl; + + //show holiday names only + QString str = matrix->getHolidayLabel(col+row*7); + if (str.isEmpty()) return; + tip(rct, str); +} + + +// ============================================================================ +// K O D A Y M A T R I X +// ============================================================================ + +const int KODayMatrix::NOSELECTION = -1000; +const int KODayMatrix::NUMDAYS = 42; + +KODayMatrix::KODayMatrix(QWidget *parent, Calendar* calendar, QDate date, const char *name) : + QFrame(parent, name) +{ + mCalendar = calendar; + + // initialize dynamic arrays + days = new QDate[NUMDAYS]; + daylbls = new QString[NUMDAYS]; + events = new int[NUMDAYS]; + mToolTip = new DynamicTip(this); + + // set default values used for drawing the matrix + mDefaultBackColor = palette().active().base(); + mDefaultTextColor = palette().active().foreground(); + mDefaultTextColorShaded = getShadedColor(mDefaultTextColor); + mHolidayColorShaded = getShadedColor(KOPrefs::instance()->mHolidayColor); + mSelectedDaysColor = QColor("white"); + mTodayMarginWidth = 2; + mSelEnd = mSelStart = NOSELECTION; + + setAcceptDrops(true); + //setFont( QFont("Arial", 10) ); + updateView(date); +} + +QColor KODayMatrix::getShadedColor(QColor color) +{ + QColor shaded; + int h=0; + int s=0; + int v=0; + color.hsv(&h,&s,&v); + s = s/4; + v = 192+v/4; + shaded.setHsv(h,s,v); + + return shaded; +} + +KODayMatrix::~KODayMatrix() +{ + delete [] days; + delete [] daylbls; + delete [] events; + delete mToolTip; +} + +/* +void KODayMatrix::setStartDate(QDate start) +{ + updateView(start); +} +*/ + +void KODayMatrix::addSelectedDaysTo(DateList& selDays) +{ + kdDebug() << "KODayMatrix::addSelectedDaysTo() - " << "mSelStart:" << mSelStart << endl; + + if (mSelStart == NOSELECTION) { + return; + } + + //cope with selection being out of matrix limits at top (< 0) + int i0 = mSelStart; + if (i0 < 0) { + for (int i = i0; i < 0; i++) { + selDays.append(days[0].addDays(i)); + } + i0 = 0; + } + + //cope with selection being out of matrix limits at bottom (> NUMDAYS-1) + if (mSelEnd > NUMDAYS-1) { + for (int i = i0; i <= NUMDAYS-1; i++) { + selDays.append(days[i]); + } + for (int i = NUMDAYS; i < mSelEnd; i++) { + selDays.append(days[0].addDays(i)); + } + + // apply normal routine to selection being entirely within matrix limits + } else { + for (int i = i0; i <= mSelEnd; i++) { + selDays.append(days[i]); + } + } +} + +void KODayMatrix::setSelectedDaysFrom(const QDate& start, const QDate& end) +{ + mSelStart = startdate.daysTo(start); + mSelEnd = startdate.daysTo(end); +} + + +void KODayMatrix::recalculateToday() +{ + today = -1; + for (int i=0; i<NUMDAYS; i++) { + days[i] = startdate.addDays(i); + daylbls[i] = QString::number( KOGlobals::self()->calendarSystem()->day( days[i] )); + + // if today is in the currently displayed month, hilight today + if (days[i].year() == QDate::currentDate().year() && + days[i].month() == QDate::currentDate().month() && + days[i].day() == QDate::currentDate().day()) { + today = i; + } + } + // qDebug(QString("Today is visible at %1.").arg(today)); +} + +void KODayMatrix::updateView() +{ + updateView(startdate); +} + +void KODayMatrix::updateView(QDate actdate) +{ + +// kdDebug() << "KODayMatrix::updateView() " << actdate.toString() << endl; + + //flag to indicate if the starting day of the matrix has changed by this call + bool daychanged = false; + // if a new startdate is to be set then apply Cornelius's calculation + // of the first day to be shown + if (actdate != startdate) { + // reset index of selection according to shift of starting date from startdate to actdate + if (mSelStart != NOSELECTION) { + int tmp = actdate.daysTo(startdate); + //kdDebug() << "Shift of Selection1: " << mSelStart << " - " << mSelEnd << " -> " << tmp << "(" << offset << ")" << endl; + // shift selection if new one would be visible at least partly ! + + if (mSelStart+tmp < NUMDAYS && mSelEnd+tmp >= 0) { + // nested if is required for next X display pushed from a different month - correction required + // otherwise, for month forward and backward, it must be avoided + if( mSelStart > NUMDAYS || mSelStart < 0 ) + mSelStart = mSelStart + tmp; + if( mSelEnd > NUMDAYS || mSelEnd < 0 ) + mSelEnd = mSelEnd + tmp; + } + } + + startdate = actdate; + daychanged = true; + } + + if (daychanged) { + recalculateToday(); + } + + for(int i = 0; i < NUMDAYS; i++) { + + // if events are set for the day then remember to draw it bold + QPtrList<Event> eventlist = mCalendar->events(days[i]); + Event *event; + int numEvents = eventlist.count(); + + for(event=eventlist.first();event != 0;event=eventlist.next()) { + ushort recurType = event->recurrence()->doesRecur(); + + if ((recurType == Recurrence::rDaily && !KOPrefs::instance()->mDailyRecur) || + (recurType == Recurrence::rWeekly && !KOPrefs::instance()->mWeeklyRecur)) { + numEvents--; + } + } + events[i] = numEvents; + + //if it is a holy day then draw it red. Sundays are consider holidays, too +#ifndef KORG_NOPLUGINS + QString holiStr = KOCore::self()->holiday(days[i]); +#else + QString holiStr = QString::null; +#endif + if ( (KOGlobals::self()->calendarSystem()->dayOfWeek(days[i]) == KOGlobals::self()->calendarSystem()->weekDayOfPray()) || + !holiStr.isEmpty()) { + if (holiStr.isNull()) holiStr = ""; + mHolidays[i] = holiStr; + + } else { + mHolidays[i] = QString::null; + } + } +} + +const QDate& KODayMatrix::getDate(int offset) +{ + if (offset < 0 || offset > NUMDAYS-1) { + kdDebug() << "Wrong offset (" << offset << ") in KODayMatrix::getDate(int)" << endl; + return days[0]; + } + return days[offset]; +} + +QString KODayMatrix::getHolidayLabel(int offset) +{ + if (offset < 0 || offset > NUMDAYS-1) { + kdDebug() << "Wrong offset (" << offset << ") in KODayMatrix::getHolidayLabel(int)" << endl; + return 0; + } + return mHolidays[offset]; +} + +int KODayMatrix::getDayIndexFrom(int x, int y) +{ + return 7*(y/daysize.height()) + (KOGlobals::self()->reverseLayout() ? + 6 - x/daysize.width() : x/daysize.width()); +} + +// ---------------------------------------------------------------------------- +// M O U S E E V E N T H A N D L I N G +// ---------------------------------------------------------------------------- + +void KODayMatrix::mousePressEvent (QMouseEvent* e) +{ + mSelStart = getDayIndexFrom(e->x(), e->y()); + if (mSelStart > NUMDAYS-1) mSelStart=NUMDAYS-1; + mSelInit = mSelStart; +} + +void KODayMatrix::mouseReleaseEvent (QMouseEvent* e) +{ + + int tmp = getDayIndexFrom(e->x(), e->y()); + if (tmp > NUMDAYS-1) tmp=NUMDAYS-1; + + if (mSelInit > tmp) { + mSelEnd = mSelInit; + if (tmp != mSelStart) { + mSelStart = tmp; + repaint(); + } + } else { + mSelStart = mSelInit; + + //repaint only if selection has changed + if (tmp != mSelEnd) { + mSelEnd = tmp; + repaint(); + } + } + + DateList daylist; + if ( mSelStart < 0 ) + mSelStart = 0; + for (int i = mSelStart; i <= mSelEnd; i++) { + daylist.append(days[i]); + } + emit selected((const DateList)daylist); + +} + +void KODayMatrix::mouseMoveEvent (QMouseEvent* e) +{ + int tmp = getDayIndexFrom(e->x(), e->y()); + if (tmp > NUMDAYS-1) tmp=NUMDAYS-1; + + if (mSelInit > tmp) { + mSelEnd = mSelInit; + if (tmp != mSelStart) { + mSelStart = tmp; + repaint(); + } + } else { + mSelStart = mSelInit; + + //repaint only if selection has changed + if (tmp != mSelEnd) { + mSelEnd = tmp; + repaint(); + } + } +} + +// ---------------------------------------------------------------------------- +// D R A G ' N D R O P H A N D L I N G +// ---------------------------------------------------------------------------- + +void KODayMatrix::dragEnterEvent(QDragEnterEvent *e) +{ +#ifndef KORG_NODND + if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) { + e->ignore(); + return; + } + + // some visual feedback +// oldPalette = palette(); +// setPalette(my_HilitePalette); +// update(); +#endif +} + +void KODayMatrix::dragMoveEvent(QDragMoveEvent *e) +{ +#ifndef KORG_NODND + if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) { + e->ignore(); + return; + } + + e->accept(); +#endif +} + +void KODayMatrix::dragLeaveEvent(QDragLeaveEvent */*dl*/) +{ +#ifndef KORG_NODND +// setPalette(oldPalette); +// update(); +#endif +} + +void KODayMatrix::dropEvent(QDropEvent *e) +{ +#ifndef KORG_NODND +// kdDebug() << "KODayMatrix::dropEvent(e) begin" << endl; + + if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) { + e->ignore(); + return; + } + + DndFactory factory( mCalendar ); + Event *event = factory.createDrop(e); + + if (event) { + e->acceptAction(); + + Event *existingEvent = mCalendar->event(event->uid()); + + if(existingEvent) { + // uniquify event + event->recreate(); +/* + KMessageBox::sorry(this, + i18n("Event already exists in this calendar."), + i18n("Drop Event")); + delete event; + return; +*/ + } +// kdDebug() << "Drop new Event" << endl; + // Adjust date + QDateTime start = event->dtStart(); + QDateTime end = event->dtEnd(); + int duration = start.daysTo(end); + int idx = getDayIndexFrom(e->pos().x(), e->pos().y()); + + start.setDate(days[idx]); + end.setDate(days[idx].addDays(duration)); + + event->setDtStart(start); + event->setDtEnd(end); + mCalendar->addEvent(event); + + emit eventDropped(event); + } else { +// kdDebug() << "KODayMatrix::dropEvent(): Event from drop not decodable" << endl; + e->ignore(); + } +#endif +} + +// ---------------------------------------------------------------------------- +// P A I N T E V E N T H A N D L I N G +// ---------------------------------------------------------------------------- + +void KODayMatrix::paintEvent(QPaintEvent * pevent) +{ +//kdDebug() << "KODayMatrix::paintEvent() BEGIN" << endl; + + QPainter p(this); + + QRect sz = frameRect(); + int dheight = daysize.height(); + int dwidth = daysize.width(); + int row,col; + int selw, selh; + bool isRTL = KOGlobals::self()->reverseLayout(); + + // draw background and topleft frame + p.fillRect(pevent->rect(), mDefaultBackColor); + p.setPen(mDefaultTextColor); + p.drawRect(0, 0, sz.width()+1, sz.height()+1); + + // draw selected days with highlighted background color + if (mSelStart != NOSELECTION) { + + row = mSelStart/7; + col = mSelStart -row*7; + QColor selcol = KOPrefs::instance()->mHighlightColor; + + if (row == mSelEnd/7) { + // Single row selection + p.fillRect(isRTL ? (7 - (mSelEnd-mSelStart+1) - col)*dwidth : col*dwidth, + row*dheight, (mSelEnd-mSelStart+1)*dwidth, dheight, selcol); + } else { + // draw first row to the right + p.fillRect(isRTL ? 0 : col*dwidth, row*dheight, (7-col)*dwidth, + dheight, selcol); + // draw full block till last line + selh = mSelEnd/7-row; + if (selh > 1) { + p.fillRect(0, (row+1)*dheight, 7*dwidth, (selh-1)*dheight,selcol); + } + // draw last block from left to mSelEnd + selw = mSelEnd-7*(mSelEnd/7)+1; + p.fillRect(isRTL ? (7-selw)*dwidth : 0, (row+selh)*dheight, + selw*dwidth, dheight, selcol); + } + } + + // iterate over all days in the matrix and draw the day label in appropriate colors + QColor actcol = mDefaultTextColorShaded; + p.setPen(actcol); + QPen tmppen; + for(int i = 0; i < NUMDAYS; i++) { + row = i/7; + col = isRTL ? 6-(i-row*7) : i-row*7; + + // if it is the first day of a month switch color from normal to shaded and vice versa + if ( KOGlobals::self()->calendarSystem()->day( days[i] ) == 1) { + if (actcol == mDefaultTextColorShaded) { + actcol = mDefaultTextColor; + } else { + actcol = mDefaultTextColorShaded; + } + p.setPen(actcol); + } + + //Reset pen color after selected days block + if (i == mSelEnd+1) { + p.setPen(actcol); + } + + // if today then draw rectangle around day + if (today == i) { + tmppen = p.pen(); + QPen mTodayPen(p.pen()); + + mTodayPen.setWidth(mTodayMarginWidth); + //draw red rectangle for holidays + if (!mHolidays[i].isNull()) { + if (actcol == mDefaultTextColor) { + mTodayPen.setColor(KOPrefs::instance()->mHolidayColor); + } else { + mTodayPen.setColor(mHolidayColorShaded); + } + } + //draw gray rectangle for today if in selection + if (i >= mSelStart && i <= mSelEnd) { + QColor grey("grey"); + mTodayPen.setColor(grey); + } + p.setPen(mTodayPen); + p.drawRect(col*dwidth, row*dheight, dwidth, dheight); + p.setPen(tmppen); + } + + // if any events are on that day then draw it using a bold font + if (events[i] > 0) { + QFont myFont = font(); + myFont.setBold(true); + p.setFont(myFont); + } + + // if it is a holiday then use the default holiday color + if (!mHolidays[i].isNull()) { + if (actcol == mDefaultTextColor) { + p.setPen(KOPrefs::instance()->mHolidayColor); + } else { + p.setPen(mHolidayColorShaded); + } + } + + // draw selected days with special color + // DO NOT specially highlight holidays in selection ! + if (i >= mSelStart && i <= mSelEnd) { + p.setPen(mSelectedDaysColor); + } + + p.drawText(col*dwidth, row*dheight, dwidth, dheight, + Qt::AlignHCenter | Qt::AlignVCenter, daylbls[i]); + + // reset color to actual color + if (!mHolidays[i].isNull()) { + p.setPen(actcol); + } + // reset bold font to plain font + if (events[i] > 0) { + QFont myFont = font(); + myFont.setBold(false); + p.setFont(myFont); + } + } +} + +// ---------------------------------------------------------------------------- +// R E SI Z E E V E N T H A N D L I N G +// ---------------------------------------------------------------------------- + +void KODayMatrix::resizeEvent(QResizeEvent *) +{ + QRect sz = frameRect(); + daysize.setHeight(sz.height()*7 / NUMDAYS); + daysize.setWidth(sz.width() / 7); +} |