00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kalarm.h"
00022
00023 #include <qtooltip.h>
00024 #include <qpainter.h>
00025 #include <qstyle.h>
00026 #include <qheader.h>
00027 #include <qregexp.h>
00028
00029 #include <kglobal.h>
00030 #include <klocale.h>
00031 #include <kdebug.h>
00032
00033 #include <libkcal/icaldrag.h>
00034 #include <libkcal/calendarlocal.h>
00035
00036 #include "alarmcalendar.h"
00037 #include "alarmtext.h"
00038 #include "functions.h"
00039 #include "kalarmapp.h"
00040 #include "preferences.h"
00041 #include "alarmlistview.moc"
00042
00043
00044 class AlarmListTooltip : public QToolTip
00045 {
00046 public:
00047 AlarmListTooltip(QWidget* parent) : QToolTip(parent) { }
00048 virtual ~AlarmListTooltip() {}
00049 protected:
00050 virtual void maybeTip(const QPoint&);
00051 };
00052
00053
00054
00055
00056
00057
00058 QValueList<EventListViewBase*> AlarmListView::mInstanceList;
00059 bool AlarmListView::mDragging = false;
00060
00061
00062 AlarmListView::AlarmListView(QWidget* parent, const char* name)
00063 : EventListViewBase(parent, name),
00064 mTimeColumn(0),
00065 mTimeToColumn(1),
00066 mRepeatColumn(2),
00067 mColourColumn(3),
00068 mTypeColumn(4),
00069 mMessageColumn(5),
00070 mMousePressed(false),
00071 mDrawMessageInColour(false),
00072 mShowExpired(false)
00073 {
00074 setSelectionMode(QListView::Extended);
00075
00076 addColumn(i18n("Time"));
00077 addColumn(i18n("Time To"));
00078 addColumn(i18n("Repeat"));
00079 addColumn(QString::null);
00080 addColumn(QString::null);
00081 addLastColumn(i18n("Message, File or Command"));
00082 setSorting(mTimeColumn);
00083 mTimeColumnHeaderWidth = columnWidth(mTimeColumn);
00084 mTimeToColumnHeaderWidth = columnWidth(mTimeToColumn);
00085 setColumnAlignment(mRepeatColumn, Qt::AlignHCenter);
00086 setColumnWidthMode(mRepeatColumn, QListView::Maximum);
00087
00088
00089 setColumnWidth(mColourColumn, itemHeight() * 3/4);
00090 setColumnWidthMode(mColourColumn, QListView::Manual);
00091
00092
00093 setColumnWidth(mTypeColumn, AlarmListViewItem::typeIconWidth(this));
00094 setColumnWidthMode(mTypeColumn, QListView::Manual);
00095
00096 mInstanceList.append(this);
00097
00098 mTooltip = new AlarmListTooltip(viewport());
00099 }
00100
00101 AlarmListView::~AlarmListView()
00102 {
00103 delete mTooltip;
00104 mTooltip = 0;
00105 mInstanceList.remove(this);
00106 }
00107
00108
00109
00110
00111 void AlarmListView::populate()
00112 {
00113 KAEvent event;
00114 KCal::Event::List events;
00115 KCal::Event::List::ConstIterator it;
00116 QDateTime now = QDateTime::currentDateTime();
00117 if (mShowExpired)
00118 {
00119 AlarmCalendar* cal = AlarmCalendar::expiredCalendarOpen();
00120 if (cal)
00121 {
00122 events = cal->events();
00123 for (it = events.begin(); it != events.end(); ++it)
00124 {
00125 KCal::Event* kcalEvent = *it;
00126 if (kcalEvent->alarms().count() > 0)
00127 {
00128 event.set(*kcalEvent);
00129 addEntry(event, now);
00130 }
00131 }
00132 }
00133 }
00134 events = AlarmCalendar::activeCalendar()->events();
00135 for (it = events.begin(); it != events.end(); ++it)
00136 {
00137 KCal::Event* kcalEvent = *it;
00138 event.set(*kcalEvent);
00139 if (mShowExpired || !event.expired())
00140 addEntry(event, now);
00141 }
00142 }
00143
00144
00145
00146
00147 void AlarmListView::selectTimeColumns(bool time, bool timeTo)
00148 {
00149 if (!time && !timeTo)
00150 return;
00151 bool changed = false;
00152 int w = columnWidth(mTimeColumn);
00153 if (time && !w)
00154 {
00155
00156 int colWidth = mTimeColumnHeaderWidth;
00157 QFontMetrics fm = fontMetrics();
00158 for (AlarmListViewItem* item = firstChild(); item; item = item->nextSibling())
00159 {
00160 int w = item->width(fm, this, mTimeColumn);
00161 if (w > colWidth)
00162 colWidth = w;
00163 }
00164 setColumnWidth(mTimeColumn, colWidth);
00165 setColumnWidthMode(mTimeColumn, QListView::Maximum);
00166 changed = true;
00167 }
00168 else if (!time && w)
00169 {
00170
00171 setColumnWidthMode(mTimeColumn, QListView::Manual);
00172 setColumnWidth(mTimeColumn, 0);
00173 changed = true;
00174 }
00175 w = columnWidth(mTimeToColumn);
00176 if (timeTo && !w)
00177 {
00178
00179 setColumnWidthMode(mTimeToColumn, QListView::Maximum);
00180 updateTimeToAlarms(true);
00181 if (columnWidth(mTimeToColumn) < mTimeToColumnHeaderWidth)
00182 setColumnWidth(mTimeToColumn, mTimeToColumnHeaderWidth);
00183 changed = true;
00184 }
00185 else if (!timeTo && w)
00186 {
00187
00188 setColumnWidthMode(mTimeToColumn, QListView::Manual);
00189 setColumnWidth(mTimeToColumn, 0);
00190 changed = true;
00191 }
00192 if (changed)
00193 resizeLastColumn();
00194 }
00195
00196
00197
00198
00199 void AlarmListView::updateTimeToAlarms(bool forceDisplay)
00200 {
00201 if (forceDisplay || columnWidth(mTimeToColumn))
00202 {
00203 QDateTime now = QDateTime::currentDateTime();
00204 for (AlarmListViewItem* item = firstChild(); item; item = item->nextSibling())
00205 item->updateTimeToAlarm(now, forceDisplay);
00206 }
00207 }
00208
00209
00210
00211
00212
00213 void AlarmListView::addEvent(const KAEvent& event, EventListViewBase* view)
00214 {
00215 QDateTime now = QDateTime::currentDateTime();
00216 for (InstanceListConstIterator it = mInstanceList.begin(); it != mInstanceList.end(); ++it)
00217 static_cast<AlarmListView*>(*it)->addEntry(event, now, true, (*it == view));
00218 }
00219
00220
00221
00222
00223 AlarmListViewItem* AlarmListView::addEntry(const KAEvent& event, const QDateTime& now, bool setSize, bool reselect)
00224 {
00225 if (!mShowExpired && event.expired())
00226 return 0;
00227 AlarmListViewItem* item = new AlarmListViewItem(this, event, now);
00228 return static_cast<AlarmListViewItem*>(EventListViewBase::addEntry(item, setSize, reselect));
00229 }
00230
00231
00232
00233
00234 EventListViewItemBase* AlarmListView::createItem(const KAEvent& event)
00235 {
00236 return new AlarmListViewItem(this, event, QDateTime::currentDateTime());
00237 }
00238
00239
00240
00241
00242 bool AlarmListView::expired(AlarmListViewItem* item) const
00243 {
00244 return item->event().expired();
00245 }
00246
00247
00248
00249
00250 QString AlarmListView::whatsThisText(int column) const
00251 {
00252 if (column == mTimeColumn)
00253 return i18n("Next scheduled date and time of the alarm");
00254 if (column == mTimeToColumn)
00255 return i18n("How long until the next scheduled trigger of the alarm");
00256 if (column == mRepeatColumn)
00257 return i18n("How often the alarm recurs");
00258 if (column == mColourColumn)
00259 return i18n("Background color of alarm message");
00260 if (column == mTypeColumn)
00261 return i18n("Alarm type (message, file, command or email)");
00262 if (column == mMessageColumn)
00263 return i18n("Alarm message text, URL of text file to display, command to execute, or email subject line");
00264 return i18n("List of scheduled alarms");
00265 }
00266
00267
00268
00269
00270
00271
00272 void AlarmListView::contentsMousePressEvent(QMouseEvent* e)
00273 {
00274 QListView::contentsMousePressEvent(e);
00275 if (e->button() == Qt::LeftButton)
00276 {
00277 QPoint p(contentsToViewport(e->pos()));
00278 if (itemAt(p))
00279 {
00280 mMousePressPos = e->pos();
00281 mMousePressed = true;
00282 }
00283 mDragging = false;
00284 }
00285 }
00286
00287
00288
00289
00290
00291 void AlarmListView::contentsMouseMoveEvent(QMouseEvent* e)
00292 {
00293 QListView::contentsMouseMoveEvent(e);
00294 if (mMousePressed
00295 && (mMousePressPos - e->pos()).manhattanLength() > QApplication::startDragDistance())
00296 {
00297
00298 kdDebug(5950) << "AlarmListView::contentsMouseMoveEvent(): drag started" << endl;
00299 mMousePressed = false;
00300 KCal::CalendarLocal cal(QString::fromLatin1("UTC"));
00301 cal.setLocalTime();
00302 QValueList<EventListViewItemBase*> items = selectedItems();
00303 if (!items.count())
00304 return;
00305 for (QValueList<EventListViewItemBase*>::Iterator it = items.begin(); it != items.end(); ++it)
00306 {
00307 const KAEvent& event = (*it)->event();
00308 KCal::Event* kcalEvent = new KCal::Event;
00309 event.updateKCalEvent(*kcalEvent, false, true);
00310 kcalEvent->setUid(event.id());
00311 cal.addEvent(kcalEvent);
00312 }
00313
00314
00315 mDragging = true;
00316 KCal::ICalDrag* dobj = new KCal::ICalDrag(&cal, this);
00317 dobj->dragCopy();
00318 }
00319 }
00320
00321
00322
00323
00324
00325
00326 void AlarmListView::contentsMouseReleaseEvent(QMouseEvent *e)
00327 {
00328 QListView::contentsMouseReleaseEvent(e);
00329 mMousePressed = false;
00330 mDragging = false;
00331 }
00332
00333
00334
00335
00336
00337
00338 int AlarmListViewItem::mTimeHourPos = -2;
00339 int AlarmListViewItem::mDigitWidth = -1;
00340
00341 AlarmListViewItem::AlarmListViewItem(AlarmListView* parent, const KAEvent& event, const QDateTime& now)
00342 : EventListViewItemBase(parent, event),
00343 mMessageTruncated(false),
00344 mTimeToAlarmShown(false)
00345 {
00346 setLastColumnText();
00347
00348 DateTime dateTime = event.expired() ? event.startDateTime() : event.nextDateTime(false);
00349 if (parent->timeColumn() >= 0)
00350 setText(parent->timeColumn(), alarmTimeText(dateTime));
00351 if (parent->timeToColumn() >= 0)
00352 {
00353 QString tta = timeToAlarmText(now);
00354 setText(parent->timeToColumn(), tta);
00355 mTimeToAlarmShown = !tta.isNull();
00356 }
00357 QTime t = dateTime.time();
00358 mDateTimeOrder.sprintf("%04d%03d%02d%02d", dateTime.date().year(), dateTime.date().dayOfYear(),
00359 t.hour(), t.minute());
00360
00361 int repeatOrder = 0;
00362 int repeatInterval = 0;
00363 QString repeatText = event.recurrenceText(true);
00364 if (repeatText.isEmpty())
00365 repeatText = event.repetitionText(true);
00366 if (event.repeatAtLogin())
00367 repeatOrder = 1;
00368 else
00369 {
00370 repeatInterval = event.recurInterval();
00371 switch (event.recurType())
00372 {
00373 case KARecurrence::MINUTELY:
00374 repeatOrder = 2;
00375 break;
00376 case KARecurrence::DAILY:
00377 repeatOrder = 3;
00378 break;
00379 case KARecurrence::WEEKLY:
00380 repeatOrder = 4;
00381 break;
00382 case KARecurrence::MONTHLY_DAY:
00383 case KARecurrence::MONTHLY_POS:
00384 repeatOrder = 5;
00385 break;
00386 case KARecurrence::ANNUAL_DATE:
00387 case KARecurrence::ANNUAL_POS:
00388 repeatOrder = 6;
00389 break;
00390 case KARecurrence::NO_RECUR:
00391 default:
00392 break;
00393 }
00394 }
00395 setText(parent->repeatColumn(), repeatText);
00396 mRepeatOrder.sprintf("%c%08d", '0' + repeatOrder, repeatInterval);
00397
00398 bool showColour = (event.action() == KAEvent::MESSAGE || event.action() == KAEvent::FILE);
00399 mColourOrder.sprintf("%06u", (showColour ? event.bgColour().rgb() : 0));
00400
00401 mTypeOrder.sprintf("%02d", event.action());
00402 }
00403
00404
00405
00406
00407 QString AlarmListViewItem::alarmText(const KAEvent& event) const
00408 {
00409 bool truncated;
00410 QString text = AlarmText::summary(event, 1, &truncated);
00411 mMessageTruncated = truncated;
00412 return text;
00413 }
00414
00415
00416
00417
00418 QString AlarmListViewItem::alarmTimeText(const DateTime& dateTime) const
00419 {
00420 KLocale* locale = KGlobal::locale();
00421 QString dateTimeText = locale->formatDate(dateTime.date(), true);
00422 if (!dateTime.isDateOnly())
00423 {
00424 dateTimeText += ' ';
00425 QString time = locale->formatTime(dateTime.time());
00426 if (mTimeHourPos == -2)
00427 {
00428
00429
00430 mTimeHourPos = -1;
00431 if (!QApplication::reverseLayout())
00432 {
00433 QString fmt = locale->timeFormat();
00434 int i = fmt.find(QRegExp("%[kl]"));
00435 if (i >= 0 && i == fmt.find('%'))
00436 mTimeHourPos = i;
00437 }
00438 }
00439 if (mTimeHourPos >= 0 && (int)time.length() > mTimeHourPos + 1
00440 && time[mTimeHourPos].isDigit() && !time[mTimeHourPos + 1].isDigit())
00441 dateTimeText += '~';
00442 dateTimeText += time;
00443 }
00444 return dateTimeText + ' ';
00445 }
00446
00447
00448
00449
00450 QString AlarmListViewItem::timeToAlarmText(const QDateTime& now) const
00451 {
00452 if (event().expired())
00453 return QString::null;
00454 DateTime dateTime = event().nextDateTime(false);
00455 if (dateTime.isDateOnly())
00456 {
00457 int days = now.date().daysTo(dateTime.date());
00458 return i18n("n days", " %1d ").arg(days);
00459 }
00460 int mins = (now.secsTo(dateTime.dateTime()) + 59) / 60;
00461 if (mins < 0)
00462 return QString::null;
00463 char minutes[3] = "00";
00464 minutes[0] = (mins%60) / 10 + '0';
00465 minutes[1] = (mins%60) % 10 + '0';
00466 if (mins < 24*60)
00467 return i18n("hours:minutes", " %1:%2 ").arg(mins/60).arg(minutes);
00468 int days = mins / (24*60);
00469 mins = mins % (24*60);
00470 return i18n("days hours:minutes", " %1d %2:%3 ").arg(days).arg(mins/60).arg(minutes);
00471 }
00472
00473
00474
00475
00476
00477
00478 void AlarmListViewItem::updateTimeToAlarm(const QDateTime& now, bool forceDisplay)
00479 {
00480 if (event().expired())
00481 {
00482 if (forceDisplay || mTimeToAlarmShown)
00483 {
00484 setText(alarmListView()->timeToColumn(), QString::null);
00485 mTimeToAlarmShown = false;
00486 }
00487 }
00488 else
00489 {
00490 QString tta = timeToAlarmText(now);
00491 if (forceDisplay || tta != text(alarmListView()->timeToColumn()))
00492 setText(alarmListView()->timeToColumn(), tta);
00493 mTimeToAlarmShown = !tta.isNull();
00494 }
00495 }
00496
00497
00498
00499
00500 void AlarmListViewItem::paintCell(QPainter* painter, const QColorGroup& cg, int column, int width, int )
00501 {
00502 const AlarmListView* listView = alarmListView();
00503 int margin = listView->itemMargin();
00504 QRect box(margin, margin, width - margin*2, height() - margin*2);
00505 bool selected = isSelected();
00506 QColor bgColour = selected ? cg.highlight() : cg.base();
00507 QColor fgColour = selected ? cg.highlightedText()
00508 : !event().enabled() ? Preferences::disabledColour()
00509 : event().expired() ? Preferences::expiredColour() : cg.text();
00510 painter->setPen(fgColour);
00511 painter->fillRect(0, 0, width, height(), bgColour);
00512
00513 if (column == listView->timeColumn())
00514 {
00515 int i = -1;
00516 QString str = text(column);
00517 if (mTimeHourPos >= 0)
00518 {
00519
00520 i = str.find(" ~");
00521 if (i >= 0)
00522 {
00523 if (mDigitWidth < 0)
00524 mDigitWidth = painter->fontMetrics().width("0");
00525 QString date = str.left(i + 1);
00526 int w = painter->fontMetrics().width(date) + mDigitWidth;
00527 painter->drawText(box, AlignVCenter, date);
00528 box.setLeft(box.left() + w);
00529 painter->drawText(box, AlignVCenter, str.mid(i + 2));
00530 }
00531 }
00532 if (i < 0)
00533 painter->drawText(box, AlignVCenter, str);
00534 }
00535 else if (column == listView->timeToColumn())
00536 painter->drawText(box, AlignVCenter | AlignRight, text(column));
00537 else if (column == listView->repeatColumn())
00538 painter->drawText(box, AlignVCenter | AlignHCenter, text(column));
00539 else if (column == listView->colourColumn())
00540 {
00541
00542 if (event().action() == KAEvent::MESSAGE || event().action() == KAEvent::FILE)
00543 painter->fillRect(box, event().bgColour());
00544 }
00545 else if (column == listView->typeColumn())
00546 {
00547
00548 QPixmap* pixmap = eventIcon();
00549 QRect pixmapRect = pixmap->rect();
00550 int diff = box.height() - pixmap->height();
00551 if (diff < 0)
00552 {
00553 pixmapRect.setTop(-diff / 2);
00554 pixmapRect.setHeight(box.height());
00555 }
00556 QPoint iconTopLeft(box.left() + (box.width() - pixmapRect.width()) / 2,
00557 box.top() + (diff > 0 ? diff / 2 : 0));
00558 painter->drawPixmap(iconTopLeft, *pixmap, pixmapRect);
00559 }
00560 else if (column == listView->messageColumn())
00561 {
00562 if (!selected && listView->drawMessageInColour())
00563 {
00564 painter->fillRect(box, event().bgColour());
00565 painter->setBackgroundColor(event().bgColour());
00566
00567 }
00568 QString txt = text(column);
00569 painter->drawText(box, AlignVCenter, txt);
00570 mMessageColWidth = listView->fontMetrics().boundingRect(txt).width();
00571 }
00572 }
00573
00574
00575
00576
00577 int AlarmListViewItem::typeIconWidth(AlarmListView* v)
00578 {
00579 return iconWidth() + 2 * v->style().pixelMetric(QStyle::PM_DefaultFrameWidth);
00580 }
00581
00582
00583
00584
00585 QString AlarmListViewItem::key(int column, bool) const
00586 {
00587 AlarmListView* listView = alarmListView();
00588 if (column == listView->timeColumn()
00589 || column == listView->timeToColumn())
00590 return mDateTimeOrder;
00591 if (column == listView->repeatColumn())
00592 return mRepeatOrder;
00593 if (column == listView->colourColumn())
00594 return mColourOrder;
00595 if (column == listView->typeColumn())
00596 return mTypeOrder;
00597 return text(column).lower();
00598 }
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609 void AlarmListTooltip::maybeTip(const QPoint& pt)
00610 {
00611 AlarmListView* listView = (AlarmListView*)parentWidget()->parentWidget();
00612 int column = listView->messageColumn();
00613 int xOffset = listView->contentsX();
00614 if (listView->header()->sectionAt(pt.x() + xOffset) == column)
00615 {
00616 AlarmListViewItem* item = (AlarmListViewItem*)listView->itemAt(pt);
00617 if (item)
00618 {
00619 int columnX = listView->header()->sectionPos(column) - xOffset;
00620 int columnWidth = listView->columnWidth(column);
00621 int widthNeeded = item->messageColWidthNeeded();
00622 if (!item->messageTruncated() && columnWidth >= widthNeeded)
00623 {
00624 if (columnX + widthNeeded <= listView->viewport()->width())
00625 return;
00626 }
00627 QRect rect = listView->itemRect(item);
00628 rect.setLeft(columnX);
00629 rect.setWidth(columnWidth);
00630 kdDebug(5950) << "AlarmListTooltip::maybeTip(): display\n";
00631 tip(rect, AlarmText::summary(item->event(), 10));
00632 }
00633 }
00634 }
00635