summaryrefslogtreecommitdiffabout
path: root/korganizer/kodaymatrix.cpp
Unidiff
Diffstat (limited to 'korganizer/kodaymatrix.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--korganizer/kodaymatrix.cpp597
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 @@
1/*
2 This file is part of KOrganizer.
3 Copyright (c) 2001 Eitzenberger Thomas <thomas.eitzenberger@siemens.at>
4 Parts of the source code have been copied from kdpdatebutton.cpp
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 As a special exception, permission is given to link this program
21 with any edition of Qt, and distribute the resulting executable,
22 without including the source code for Qt in the source distribution.
23*/
24
25#include <qevent.h>
26#include <qpainter.h>
27#include <qptrlist.h>
28
29#include <kglobal.h>
30#include <kdebug.h>
31#include <klocale.h>
32
33#include <libkcal/vcaldrag.h>
34#include <libkcal/icaldrag.h>
35#include <libkcal/dndfactory.h>
36#include <libkcal/calendarresources.h>
37#include <libkcal/resourcecalendar.h>
38#include <kresources/resourceselectdialog.h>
39
40#include <kcalendarsystem.h>
41
42#ifndef KORG_NOPLUGINS
43#include "kocore.h"
44#endif
45#include "koprefs.h"
46#include "koglobals.h"
47
48#include "kodaymatrix.h"
49#include "kodaymatrix.moc"
50
51// ============================================================================
52// D Y N A M I C T I P
53// ============================================================================
54
55DynamicTip::DynamicTip( QWidget * parent )
56 : QToolTip( parent )
57{
58 matrix = (KODayMatrix*)parent;
59}
60
61
62void DynamicTip::maybeTip( const QPoint &pos )
63{
64 //calculate which cell of the matrix the mouse is in
65 QRect sz = matrix->frameRect();
66 int dheight = sz.height()*7 / 42;
67 int dwidth = sz.width() / 7;
68 int row = pos.y()/dheight;
69 int col = pos.x()/dwidth;
70
71 QRect rct(col*dwidth, row*dheight, dwidth, dheight);
72
73// kdDebug() << "DynamicTip::maybeTip matrix cell index [" <<
74// col << "][" << row << "] => " <<(col+row*7) << endl;
75
76 //show holiday names only
77 QString str = matrix->getHolidayLabel(col+row*7);
78 if (str.isEmpty()) return;
79 tip(rct, str);
80}
81
82
83// ============================================================================
84// K O D A Y M A T R I X
85// ============================================================================
86
87const int KODayMatrix::NOSELECTION = -1000;
88const int KODayMatrix::NUMDAYS = 42;
89
90KODayMatrix::KODayMatrix(QWidget *parent, Calendar* calendar, QDate date, const char *name) :
91 QFrame(parent, name)
92{
93 mCalendar = calendar;
94
95 // initialize dynamic arrays
96 days = new QDate[NUMDAYS];
97 daylbls = new QString[NUMDAYS];
98 events = new int[NUMDAYS];
99 mToolTip = new DynamicTip(this);
100
101 // set default values used for drawing the matrix
102 mDefaultBackColor = palette().active().base();
103 mDefaultTextColor = palette().active().foreground();
104 mDefaultTextColorShaded = getShadedColor(mDefaultTextColor);
105 mHolidayColorShaded = getShadedColor(KOPrefs::instance()->mHolidayColor);
106 mSelectedDaysColor = QColor("white");
107 mTodayMarginWidth = 2;
108 mSelEnd = mSelStart = NOSELECTION;
109
110 setAcceptDrops(true);
111 //setFont( QFont("Arial", 10) );
112 updateView(date);
113}
114
115QColor KODayMatrix::getShadedColor(QColor color)
116{
117 QColor shaded;
118 int h=0;
119 int s=0;
120 int v=0;
121 color.hsv(&h,&s,&v);
122 s = s/4;
123 v = 192+v/4;
124 shaded.setHsv(h,s,v);
125
126 return shaded;
127}
128
129KODayMatrix::~KODayMatrix()
130{
131 delete [] days;
132 delete [] daylbls;
133 delete [] events;
134 delete mToolTip;
135}
136
137/*
138void KODayMatrix::setStartDate(QDate start)
139{
140 updateView(start);
141}
142*/
143
144void KODayMatrix::addSelectedDaysTo(DateList& selDays)
145{
146 kdDebug() << "KODayMatrix::addSelectedDaysTo() - " << "mSelStart:" << mSelStart << endl;
147
148 if (mSelStart == NOSELECTION) {
149 return;
150 }
151
152 //cope with selection being out of matrix limits at top (< 0)
153 int i0 = mSelStart;
154 if (i0 < 0) {
155 for (int i = i0; i < 0; i++) {
156 selDays.append(days[0].addDays(i));
157 }
158 i0 = 0;
159 }
160
161 //cope with selection being out of matrix limits at bottom (> NUMDAYS-1)
162 if (mSelEnd > NUMDAYS-1) {
163 for (int i = i0; i <= NUMDAYS-1; i++) {
164 selDays.append(days[i]);
165 }
166 for (int i = NUMDAYS; i < mSelEnd; i++) {
167 selDays.append(days[0].addDays(i));
168 }
169
170 // apply normal routine to selection being entirely within matrix limits
171 } else {
172 for (int i = i0; i <= mSelEnd; i++) {
173 selDays.append(days[i]);
174 }
175 }
176}
177
178void KODayMatrix::setSelectedDaysFrom(const QDate& start, const QDate& end)
179{
180 mSelStart = startdate.daysTo(start);
181 mSelEnd = startdate.daysTo(end);
182}
183
184
185void KODayMatrix::recalculateToday()
186{
187 today = -1;
188 for (int i=0; i<NUMDAYS; i++) {
189 days[i] = startdate.addDays(i);
190 daylbls[i] = QString::number( KOGlobals::self()->calendarSystem()->day( days[i] ));
191
192 // if today is in the currently displayed month, hilight today
193 if (days[i].year() == QDate::currentDate().year() &&
194 days[i].month() == QDate::currentDate().month() &&
195 days[i].day() == QDate::currentDate().day()) {
196 today = i;
197 }
198 }
199 // qDebug(QString("Today is visible at %1.").arg(today));
200}
201
202void KODayMatrix::updateView()
203{
204 updateView(startdate);
205}
206
207void KODayMatrix::updateView(QDate actdate)
208{
209
210// kdDebug() << "KODayMatrix::updateView() " << actdate.toString() << endl;
211
212 //flag to indicate if the starting day of the matrix has changed by this call
213 bool daychanged = false;
214 // if a new startdate is to be set then apply Cornelius's calculation
215 // of the first day to be shown
216 if (actdate != startdate) {
217 // reset index of selection according to shift of starting date from startdate to actdate
218 if (mSelStart != NOSELECTION) {
219 int tmp = actdate.daysTo(startdate);
220 //kdDebug() << "Shift of Selection1: " << mSelStart << " - " << mSelEnd << " -> " << tmp << "(" << offset << ")" << endl;
221 // shift selection if new one would be visible at least partly !
222
223 if (mSelStart+tmp < NUMDAYS && mSelEnd+tmp >= 0) {
224 // nested if is required for next X display pushed from a different month - correction required
225 // otherwise, for month forward and backward, it must be avoided
226 if( mSelStart > NUMDAYS || mSelStart < 0 )
227 mSelStart = mSelStart + tmp;
228 if( mSelEnd > NUMDAYS || mSelEnd < 0 )
229 mSelEnd = mSelEnd + tmp;
230 }
231 }
232
233 startdate = actdate;
234 daychanged = true;
235 }
236
237 if (daychanged) {
238 recalculateToday();
239 }
240
241 for(int i = 0; i < NUMDAYS; i++) {
242
243 // if events are set for the day then remember to draw it bold
244 QPtrList<Event> eventlist = mCalendar->events(days[i]);
245 Event *event;
246 int numEvents = eventlist.count();
247
248 for(event=eventlist.first();event != 0;event=eventlist.next()) {
249 ushort recurType = event->recurrence()->doesRecur();
250
251 if ((recurType == Recurrence::rDaily && !KOPrefs::instance()->mDailyRecur) ||
252 (recurType == Recurrence::rWeekly && !KOPrefs::instance()->mWeeklyRecur)) {
253 numEvents--;
254 }
255 }
256 events[i] = numEvents;
257
258 //if it is a holy day then draw it red. Sundays are consider holidays, too
259#ifndef KORG_NOPLUGINS
260 QString holiStr = KOCore::self()->holiday(days[i]);
261#else
262 QString holiStr = QString::null;
263#endif
264 if ( (KOGlobals::self()->calendarSystem()->dayOfWeek(days[i]) == KOGlobals::self()->calendarSystem()->weekDayOfPray()) ||
265 !holiStr.isEmpty()) {
266 if (holiStr.isNull()) holiStr = "";
267 mHolidays[i] = holiStr;
268
269 } else {
270 mHolidays[i] = QString::null;
271 }
272 }
273}
274
275const QDate& KODayMatrix::getDate(int offset)
276{
277 if (offset < 0 || offset > NUMDAYS-1) {
278 kdDebug() << "Wrong offset (" << offset << ") in KODayMatrix::getDate(int)" << endl;
279 return days[0];
280 }
281 return days[offset];
282}
283
284QString KODayMatrix::getHolidayLabel(int offset)
285{
286 if (offset < 0 || offset > NUMDAYS-1) {
287 kdDebug() << "Wrong offset (" << offset << ") in KODayMatrix::getHolidayLabel(int)" << endl;
288 return 0;
289 }
290 return mHolidays[offset];
291}
292
293int KODayMatrix::getDayIndexFrom(int x, int y)
294{
295 return 7*(y/daysize.height()) + (KOGlobals::self()->reverseLayout() ?
296 6 - x/daysize.width() : x/daysize.width());
297}
298
299// ----------------------------------------------------------------------------
300// M O U S E E V E N T H A N D L I N G
301// ----------------------------------------------------------------------------
302
303void KODayMatrix::mousePressEvent (QMouseEvent* e)
304{
305 mSelStart = getDayIndexFrom(e->x(), e->y());
306 if (mSelStart > NUMDAYS-1) mSelStart=NUMDAYS-1;
307 mSelInit = mSelStart;
308}
309
310void KODayMatrix::mouseReleaseEvent (QMouseEvent* e)
311{
312
313 int tmp = getDayIndexFrom(e->x(), e->y());
314 if (tmp > NUMDAYS-1) tmp=NUMDAYS-1;
315
316 if (mSelInit > tmp) {
317 mSelEnd = mSelInit;
318 if (tmp != mSelStart) {
319 mSelStart = tmp;
320 repaint();
321 }
322 } else {
323 mSelStart = mSelInit;
324
325 //repaint only if selection has changed
326 if (tmp != mSelEnd) {
327 mSelEnd = tmp;
328 repaint();
329 }
330 }
331
332 DateList daylist;
333 if ( mSelStart < 0 )
334 mSelStart = 0;
335 for (int i = mSelStart; i <= mSelEnd; i++) {
336 daylist.append(days[i]);
337 }
338 emit selected((const DateList)daylist);
339
340}
341
342void KODayMatrix::mouseMoveEvent (QMouseEvent* e)
343{
344 int tmp = getDayIndexFrom(e->x(), e->y());
345 if (tmp > NUMDAYS-1) tmp=NUMDAYS-1;
346
347 if (mSelInit > tmp) {
348 mSelEnd = mSelInit;
349 if (tmp != mSelStart) {
350 mSelStart = tmp;
351 repaint();
352 }
353 } else {
354 mSelStart = mSelInit;
355
356 //repaint only if selection has changed
357 if (tmp != mSelEnd) {
358 mSelEnd = tmp;
359 repaint();
360 }
361 }
362}
363
364// ----------------------------------------------------------------------------
365// D R A G ' N D R O P H A N D L I N G
366// ----------------------------------------------------------------------------
367
368void KODayMatrix::dragEnterEvent(QDragEnterEvent *e)
369{
370#ifndef KORG_NODND
371 if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) {
372 e->ignore();
373 return;
374 }
375
376 // some visual feedback
377// oldPalette = palette();
378// setPalette(my_HilitePalette);
379// update();
380#endif
381}
382
383void KODayMatrix::dragMoveEvent(QDragMoveEvent *e)
384{
385#ifndef KORG_NODND
386 if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) {
387 e->ignore();
388 return;
389 }
390
391 e->accept();
392#endif
393}
394
395void KODayMatrix::dragLeaveEvent(QDragLeaveEvent */*dl*/)
396{
397#ifndef KORG_NODND
398// setPalette(oldPalette);
399// update();
400#endif
401}
402
403void KODayMatrix::dropEvent(QDropEvent *e)
404{
405#ifndef KORG_NODND
406// kdDebug() << "KODayMatrix::dropEvent(e) begin" << endl;
407
408 if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) {
409 e->ignore();
410 return;
411 }
412
413 DndFactory factory( mCalendar );
414 Event *event = factory.createDrop(e);
415
416 if (event) {
417 e->acceptAction();
418
419 Event *existingEvent = mCalendar->event(event->uid());
420
421 if(existingEvent) {
422 // uniquify event
423 event->recreate();
424/*
425 KMessageBox::sorry(this,
426 i18n("Event already exists in this calendar."),
427 i18n("Drop Event"));
428 delete event;
429 return;
430*/
431 }
432// kdDebug() << "Drop new Event" << endl;
433 // Adjust date
434 QDateTime start = event->dtStart();
435 QDateTime end = event->dtEnd();
436 int duration = start.daysTo(end);
437 int idx = getDayIndexFrom(e->pos().x(), e->pos().y());
438
439 start.setDate(days[idx]);
440 end.setDate(days[idx].addDays(duration));
441
442 event->setDtStart(start);
443 event->setDtEnd(end);
444 mCalendar->addEvent(event);
445
446 emit eventDropped(event);
447 } else {
448// kdDebug() << "KODayMatrix::dropEvent(): Event from drop not decodable" << endl;
449 e->ignore();
450 }
451#endif
452}
453
454// ----------------------------------------------------------------------------
455// P A I N T E V E N T H A N D L I N G
456// ----------------------------------------------------------------------------
457
458void KODayMatrix::paintEvent(QPaintEvent * pevent)
459{
460//kdDebug() << "KODayMatrix::paintEvent() BEGIN" << endl;
461
462 QPainter p(this);
463
464 QRect sz = frameRect();
465 int dheight = daysize.height();
466 int dwidth = daysize.width();
467 int row,col;
468 int selw, selh;
469 bool isRTL = KOGlobals::self()->reverseLayout();
470
471 // draw background and topleft frame
472 p.fillRect(pevent->rect(), mDefaultBackColor);
473 p.setPen(mDefaultTextColor);
474 p.drawRect(0, 0, sz.width()+1, sz.height()+1);
475
476 // draw selected days with highlighted background color
477 if (mSelStart != NOSELECTION) {
478
479 row = mSelStart/7;
480 col = mSelStart -row*7;
481 QColor selcol = KOPrefs::instance()->mHighlightColor;
482
483 if (row == mSelEnd/7) {
484 // Single row selection
485 p.fillRect(isRTL ? (7 - (mSelEnd-mSelStart+1) - col)*dwidth : col*dwidth,
486 row*dheight, (mSelEnd-mSelStart+1)*dwidth, dheight, selcol);
487 } else {
488 // draw first row to the right
489 p.fillRect(isRTL ? 0 : col*dwidth, row*dheight, (7-col)*dwidth,
490 dheight, selcol);
491 // draw full block till last line
492 selh = mSelEnd/7-row;
493 if (selh > 1) {
494 p.fillRect(0, (row+1)*dheight, 7*dwidth, (selh-1)*dheight,selcol);
495 }
496 // draw last block from left to mSelEnd
497 selw = mSelEnd-7*(mSelEnd/7)+1;
498 p.fillRect(isRTL ? (7-selw)*dwidth : 0, (row+selh)*dheight,
499 selw*dwidth, dheight, selcol);
500 }
501 }
502
503 // iterate over all days in the matrix and draw the day label in appropriate colors
504 QColor actcol = mDefaultTextColorShaded;
505 p.setPen(actcol);
506 QPen tmppen;
507 for(int i = 0; i < NUMDAYS; i++) {
508 row = i/7;
509 col = isRTL ? 6-(i-row*7) : i-row*7;
510
511 // if it is the first day of a month switch color from normal to shaded and vice versa
512 if ( KOGlobals::self()->calendarSystem()->day( days[i] ) == 1) {
513 if (actcol == mDefaultTextColorShaded) {
514 actcol = mDefaultTextColor;
515 } else {
516 actcol = mDefaultTextColorShaded;
517 }
518 p.setPen(actcol);
519 }
520
521 //Reset pen color after selected days block
522 if (i == mSelEnd+1) {
523 p.setPen(actcol);
524 }
525
526 // if today then draw rectangle around day
527 if (today == i) {
528 tmppen = p.pen();
529 QPen mTodayPen(p.pen());
530
531 mTodayPen.setWidth(mTodayMarginWidth);
532 //draw red rectangle for holidays
533 if (!mHolidays[i].isNull()) {
534 if (actcol == mDefaultTextColor) {
535 mTodayPen.setColor(KOPrefs::instance()->mHolidayColor);
536 } else {
537 mTodayPen.setColor(mHolidayColorShaded);
538 }
539 }
540 //draw gray rectangle for today if in selection
541 if (i >= mSelStart && i <= mSelEnd) {
542 QColor grey("grey");
543 mTodayPen.setColor(grey);
544 }
545 p.setPen(mTodayPen);
546 p.drawRect(col*dwidth, row*dheight, dwidth, dheight);
547 p.setPen(tmppen);
548 }
549
550 // if any events are on that day then draw it using a bold font
551 if (events[i] > 0) {
552 QFont myFont = font();
553 myFont.setBold(true);
554 p.setFont(myFont);
555 }
556
557 // if it is a holiday then use the default holiday color
558 if (!mHolidays[i].isNull()) {
559 if (actcol == mDefaultTextColor) {
560 p.setPen(KOPrefs::instance()->mHolidayColor);
561 } else {
562 p.setPen(mHolidayColorShaded);
563 }
564 }
565
566 // draw selected days with special color
567 // DO NOT specially highlight holidays in selection !
568 if (i >= mSelStart && i <= mSelEnd) {
569 p.setPen(mSelectedDaysColor);
570 }
571
572 p.drawText(col*dwidth, row*dheight, dwidth, dheight,
573 Qt::AlignHCenter | Qt::AlignVCenter, daylbls[i]);
574
575 // reset color to actual color
576 if (!mHolidays[i].isNull()) {
577 p.setPen(actcol);
578 }
579 // reset bold font to plain font
580 if (events[i] > 0) {
581 QFont myFont = font();
582 myFont.setBold(false);
583 p.setFont(myFont);
584 }
585 }
586}
587
588// ----------------------------------------------------------------------------
589// R E SI Z E E V E N T H A N D L I N G
590// ----------------------------------------------------------------------------
591
592void KODayMatrix::resizeEvent(QResizeEvent *)
593{
594 QRect sz = frameRect();
595 daysize.setHeight(sz.height()*7 / NUMDAYS);
596 daysize.setWidth(sz.width() / 7);
597}