alarmlistview.cpp
00001 /* 00002 * alarmlistview.cpp - widget showing list of outstanding alarms 00003 * Program: kalarm 00004 * Copyright © 2001-2007 by David Jarvie <software@astrojar.org.uk> 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 along 00017 * with this program; if not, write to the Free Software Foundation, Inc., 00018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include "kalarm.h" 00022 00023 #include <tqtooltip.h> 00024 #include <tqpainter.h> 00025 #include <tqstyle.h> 00026 #include <tqheader.h> 00027 #include <tqregexp.h> 00028 00029 #include <tdeglobal.h> 00030 #include <tdelocale.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 TQToolTip 00045 { 00046 public: 00047 AlarmListTooltip(TQWidget* parent) : TQToolTip(parent) { } 00048 virtual ~AlarmListTooltip() {} 00049 protected: 00050 virtual void maybeTip(const TQPoint&); 00051 }; 00052 00053 00054 /*============================================================================= 00055 = Class: AlarmListView 00056 = Displays the list of outstanding alarms. 00057 =============================================================================*/ 00058 TQValueList<EventListViewBase*> AlarmListView::mInstanceList; 00059 bool AlarmListView::mDragging = false; 00060 00061 00062 AlarmListView::AlarmListView(const TQValueList<int>& order, TQWidget* parent, const char* name) 00063 : EventListViewBase(parent, name), 00064 mMousePressed(false), 00065 mDrawMessageInColour(false), 00066 mShowExpired(false) 00067 { 00068 static TQString titles[COLUMN_COUNT] = { 00069 i18n("Time"), 00070 i18n("Time To"), 00071 i18n("Repeat"), 00072 TQString(), 00073 TQString(), 00074 i18n("Message, File or Command") 00075 }; 00076 00077 setSelectionMode(TQListView::Extended); 00078 00079 // Set the column order 00080 int i; 00081 bool ok = false; 00082 if (order.count() >= COLUMN_COUNT) 00083 { 00084 // The column order is specified 00085 bool posns[COLUMN_COUNT]; 00086 for (i = 0; i < COLUMN_COUNT; ++i) 00087 posns[i] = false; 00088 for (i = 0; i < COLUMN_COUNT; ++i) 00089 { 00090 int ord = order[i]; 00091 if (ord < COLUMN_COUNT && ord >= 0) 00092 { 00093 mColumn[i] = ord; 00094 posns[ord] = true; 00095 } 00096 } 00097 ok = true; 00098 for (i = 0; i < COLUMN_COUNT; ++i) 00099 if (!posns[i]) 00100 ok = false; 00101 if (ok && mColumn[MESSAGE_COLUMN] != MESSAGE_COLUMN) 00102 { 00103 // Shift the message column to be last, since otherwise 00104 // column widths get screwed up. 00105 int messageCol = mColumn[MESSAGE_COLUMN]; 00106 for (i = 0; i < COLUMN_COUNT; ++i) 00107 if (mColumn[i] > messageCol) 00108 --mColumn[i]; 00109 mColumn[MESSAGE_COLUMN] = MESSAGE_COLUMN; 00110 } 00111 } 00112 if (!ok) 00113 { 00114 // Either no column order was specified, or it was invalid, 00115 // so use the default order 00116 for (i = 0; i < COLUMN_COUNT; ++i) 00117 mColumn[i] = i; 00118 } 00119 00120 // Initialise the columns 00121 for (i = 0; i < COLUMN_COUNT; ++i) 00122 { 00123 for (int j = 0; j < COLUMN_COUNT; ++j) 00124 if (mColumn[j] == i) 00125 { 00126 if (j != MESSAGE_COLUMN) 00127 addColumn(titles[j]); 00128 break; 00129 } 00130 } 00131 addLastColumn(titles[MESSAGE_COLUMN]); 00132 00133 setSorting(mColumn[TIME_COLUMN]); // sort initially by date/time 00134 mTimeColumnHeaderWidth = columnWidth(mColumn[TIME_COLUMN]); 00135 mTimeToColumnHeaderWidth = columnWidth(mColumn[TIME_TO_COLUMN]); 00136 setColumnAlignment(mColumn[REPEAT_COLUMN], TQt::AlignHCenter); 00137 setColumnWidthMode(mColumn[REPEAT_COLUMN], TQListView::Maximum); 00138 00139 // Set the width of the colour column in proportion to height 00140 setColumnWidth(mColumn[COLOUR_COLUMN], itemHeight() * 3/4); 00141 setColumnWidthMode(mColumn[COLOUR_COLUMN], TQListView::Manual); 00142 00143 // Set the width of the alarm type column to exactly accommodate the icons. 00144 // Don't allow the user to resize it (to avoid refresh problems, and bearing 00145 // in mind that resizing doesn't seem very useful anyway). 00146 setColumnWidth(mColumn[TYPE_COLUMN], AlarmListViewItem::typeIconWidth(this)); 00147 setColumnWidthMode(mColumn[TYPE_COLUMN], TQListView::Manual); 00148 header()->setResizeEnabled(false, mColumn[TYPE_COLUMN]); 00149 00150 mInstanceList.append(this); 00151 00152 mTooltip = new AlarmListTooltip(viewport()); 00153 } 00154 00155 AlarmListView::~AlarmListView() 00156 { 00157 delete mTooltip; 00158 mTooltip = 0; 00159 mInstanceList.remove(this); 00160 } 00161 00162 /****************************************************************************** 00163 * Add all the current alarms to the list. 00164 */ 00165 void AlarmListView::populate() 00166 { 00167 KAEvent event; 00168 KCal::Event::List events; 00169 KCal::Event::List::ConstIterator it; 00170 TQDateTime now = TQDateTime::currentDateTime(); 00171 if (mShowExpired) 00172 { 00173 AlarmCalendar* cal = AlarmCalendar::expiredCalendarOpen(); 00174 if (cal) 00175 { 00176 events = cal->events(); 00177 for (it = events.begin(); it != events.end(); ++it) 00178 { 00179 KCal::Event* kcalEvent = *it; 00180 if (kcalEvent->alarms().count() > 0) 00181 { 00182 event.set(*kcalEvent); 00183 addEntry(event, now); 00184 } 00185 } 00186 } 00187 } 00188 events = AlarmCalendar::activeCalendar()->events(); 00189 for (it = events.begin(); it != events.end(); ++it) 00190 { 00191 KCal::Event* kcalEvent = *it; 00192 event.set(*kcalEvent); 00193 if (mShowExpired || !event.expired()) 00194 addEntry(event, now); 00195 } 00196 } 00197 00198 /****************************************************************************** 00199 * Set which time columns are to be displayed. 00200 */ 00201 void AlarmListView::selectTimeColumns(bool time, bool timeTo) 00202 { 00203 if (!time && !timeTo) 00204 return; // always show at least one time column 00205 bool changed = false; 00206 int w = columnWidth(mColumn[TIME_COLUMN]); 00207 if (time && !w) 00208 { 00209 // Unhide the time column 00210 int colWidth = mTimeColumnHeaderWidth; 00211 TQFontMetrics fm = fontMetrics(); 00212 for (AlarmListViewItem* item = firstChild(); item; item = item->nextSibling()) 00213 { 00214 int w = item->width(fm, this, mColumn[TIME_COLUMN]); 00215 if (w > colWidth) 00216 colWidth = w; 00217 } 00218 setColumnWidth(mColumn[TIME_COLUMN], colWidth); 00219 setColumnWidthMode(mColumn[TIME_COLUMN], TQListView::Maximum); 00220 changed = true; 00221 } 00222 else if (!time && w) 00223 { 00224 // Hide the time column 00225 setColumnWidthMode(mColumn[TIME_COLUMN], TQListView::Manual); 00226 setColumnWidth(mColumn[TIME_COLUMN], 0); 00227 changed = true; 00228 } 00229 w = columnWidth(mColumn[TIME_TO_COLUMN]); 00230 if (timeTo && !w) 00231 { 00232 // Unhide the time-to-alarm column 00233 setColumnWidthMode(mColumn[TIME_TO_COLUMN], TQListView::Maximum); 00234 updateTimeToAlarms(true); 00235 if (columnWidth(mColumn[TIME_TO_COLUMN]) < mTimeToColumnHeaderWidth) 00236 setColumnWidth(mColumn[TIME_TO_COLUMN], mTimeToColumnHeaderWidth); 00237 changed = true; 00238 } 00239 else if (!timeTo && w) 00240 { 00241 // Hide the time-to-alarm column 00242 setColumnWidthMode(mColumn[TIME_TO_COLUMN], TQListView::Manual); 00243 setColumnWidth(mColumn[TIME_TO_COLUMN], 0); 00244 changed = true; 00245 } 00246 if (changed) 00247 { 00248 resizeLastColumn(); 00249 triggerUpdate(); // ensure scroll bar appears if needed 00250 } 00251 } 00252 00253 /****************************************************************************** 00254 * Update all the values in the time-to-alarm column. 00255 */ 00256 void AlarmListView::updateTimeToAlarms(bool forceDisplay) 00257 { 00258 if (forceDisplay || columnWidth(mColumn[TIME_TO_COLUMN])) 00259 { 00260 TQDateTime now = TQDateTime::currentDateTime(); 00261 for (AlarmListViewItem* item = firstChild(); item; item = item->nextSibling()) 00262 item->updateTimeToAlarm(now, forceDisplay); 00263 } 00264 } 00265 00266 /****************************************************************************** 00267 * Add an event to every list instance. 00268 * The selection highlight is moved to the new event in the specified instance only. 00269 */ 00270 void AlarmListView::addEvent(const KAEvent& event, EventListViewBase* view) 00271 { 00272 TQDateTime now = TQDateTime::currentDateTime(); 00273 for (InstanceListConstIterator it = mInstanceList.begin(); it != mInstanceList.end(); ++it) 00274 static_cast<AlarmListView*>(*it)->addEntry(event, now, true, (*it == view)); 00275 } 00276 00277 /****************************************************************************** 00278 * Add a new item to the list. 00279 */ 00280 AlarmListViewItem* AlarmListView::addEntry(const KAEvent& event, const TQDateTime& now, bool setSize, bool reselect) 00281 { 00282 if (!mShowExpired && event.expired()) 00283 return 0; 00284 AlarmListViewItem* item = new AlarmListViewItem(this, event, now); 00285 return static_cast<AlarmListViewItem*>(EventListViewBase::addEntry(item, setSize, reselect)); 00286 } 00287 00288 /****************************************************************************** 00289 * Create a new list item for addEntry(). 00290 */ 00291 EventListViewItemBase* AlarmListView::createItem(const KAEvent& event) 00292 { 00293 return new AlarmListViewItem(this, event, TQDateTime::currentDateTime()); 00294 } 00295 00296 /****************************************************************************** 00297 * Check whether an item's alarm has expired. 00298 */ 00299 bool AlarmListView::expired(AlarmListViewItem* item) const 00300 { 00301 return item->event().expired(); 00302 } 00303 00304 /****************************************************************************** 00305 * Return the column order. 00306 */ 00307 TQValueList<int> AlarmListView::columnOrder() const 00308 { 00309 TQHeader* hdr = header(); 00310 int order[COLUMN_COUNT]; 00311 order[TIME_COLUMN] = hdr->mapToIndex(mColumn[TIME_COLUMN]); 00312 order[TIME_TO_COLUMN] = hdr->mapToIndex(mColumn[TIME_TO_COLUMN]); 00313 order[REPEAT_COLUMN] = hdr->mapToIndex(mColumn[REPEAT_COLUMN]); 00314 order[COLOUR_COLUMN] = hdr->mapToIndex(mColumn[COLOUR_COLUMN]); 00315 order[TYPE_COLUMN] = hdr->mapToIndex(mColumn[TYPE_COLUMN]); 00316 order[MESSAGE_COLUMN] = hdr->mapToIndex(mColumn[MESSAGE_COLUMN]); 00317 TQValueList<int> orderList; 00318 for (int i = 0; i < COLUMN_COUNT; ++i) 00319 orderList += order[i]; 00320 return orderList; 00321 } 00322 00323 /****************************************************************************** 00324 * Returns the TQWhatsThis text for a specified column. 00325 */ 00326 TQString AlarmListView::whatsThisText(int column) const 00327 { 00328 if (column == mColumn[TIME_COLUMN]) 00329 return i18n("Next scheduled date and time of the alarm"); 00330 if (column == mColumn[TIME_TO_COLUMN]) 00331 return i18n("How long until the next scheduled trigger of the alarm"); 00332 if (column == mColumn[REPEAT_COLUMN]) 00333 return i18n("How often the alarm recurs"); 00334 if (column == mColumn[COLOUR_COLUMN]) 00335 return i18n("Background color of alarm message"); 00336 if (column == mColumn[TYPE_COLUMN]) 00337 return i18n("Alarm type (message, file, command or email)"); 00338 if (column == mColumn[MESSAGE_COLUMN]) 00339 return i18n("Alarm message text, URL of text file to display, command to execute, or email subject line"); 00340 return i18n("List of scheduled alarms"); 00341 } 00342 00343 /****************************************************************************** 00344 * Called when the mouse button is pressed. 00345 * Records the position of the mouse when the left button is pressed, for use 00346 * in drag operations. 00347 */ 00348 void AlarmListView::contentsMousePressEvent(TQMouseEvent* e) 00349 { 00350 TQListView::contentsMousePressEvent(e); 00351 if (e->button() == Qt::LeftButton) 00352 { 00353 TQPoint p(contentsToViewport(e->pos())); 00354 if (itemAt(p)) 00355 { 00356 mMousePressPos = e->pos(); 00357 mMousePressed = true; 00358 } 00359 mDragging = false; 00360 } 00361 } 00362 00363 /****************************************************************************** 00364 * Called when the mouse is moved. 00365 * Creates a drag object when the mouse drags one or more selected items. 00366 */ 00367 void AlarmListView::contentsMouseMoveEvent(TQMouseEvent* e) 00368 { 00369 TQListView::contentsMouseMoveEvent(e); 00370 if (mMousePressed 00371 && (mMousePressPos - e->pos()).manhattanLength() > TQApplication::startDragDistance()) 00372 { 00373 // Create a calendar object containing all the currently selected alarms 00374 kdDebug(5950) << "AlarmListView::contentsMouseMoveEvent(): drag started" << endl; 00375 mMousePressed = false; 00376 KCal::CalendarLocal cal(TQString::fromLatin1("UTC")); 00377 cal.setLocalTime(); // write out using local time (i.e. no time zone) 00378 TQValueList<EventListViewItemBase*> items = selectedItems(); 00379 if (!items.count()) 00380 return; 00381 for (TQValueList<EventListViewItemBase*>::Iterator it = items.begin(); it != items.end(); ++it) 00382 { 00383 const KAEvent& event = (*it)->event(); 00384 KCal::Event* kcalEvent = new KCal::Event; 00385 event.updateKCalEvent(*kcalEvent, false, true); 00386 kcalEvent->setUid(event.id()); 00387 cal.addEvent(kcalEvent); 00388 } 00389 00390 // Create the drag object for the destination program to receive 00391 mDragging = true; 00392 KCal::ICalDrag* dobj = new KCal::ICalDrag(&cal, this); 00393 dobj->dragCopy(); // the drag operation will copy the alarms 00394 } 00395 } 00396 00397 /****************************************************************************** 00398 * Called when the mouse button is released. 00399 * Notes that the mouse left button is no longer pressed, for use in drag 00400 * operations. 00401 */ 00402 void AlarmListView::contentsMouseReleaseEvent(TQMouseEvent *e) 00403 { 00404 TQListView::contentsMouseReleaseEvent(e); 00405 mMousePressed = false; 00406 mDragging = false; 00407 } 00408 00409 00410 /*============================================================================= 00411 = Class: AlarmListViewItem 00412 = Contains the details of one alarm for display in the AlarmListView. 00413 =============================================================================*/ 00414 int AlarmListViewItem::mTimeHourPos = -2; 00415 int AlarmListViewItem::mDigitWidth = -1; 00416 00417 AlarmListViewItem::AlarmListViewItem(AlarmListView* parent, const KAEvent& event, const TQDateTime& now) 00418 : EventListViewItemBase(parent, event), 00419 mMessageTruncated(false), 00420 mTimeToAlarmShown(false) 00421 { 00422 setLastColumnText(); // set the message column text 00423 00424 DateTime dateTime = event.expired() ? event.startDateTime() : event.displayDateTime(); 00425 if (parent->column(AlarmListView::TIME_COLUMN) >= 0) 00426 setText(parent->column(AlarmListView::TIME_COLUMN), alarmTimeText(dateTime)); 00427 if (parent->column(AlarmListView::TIME_TO_COLUMN) >= 0) 00428 { 00429 TQString tta = timeToAlarmText(now); 00430 setText(parent->column(AlarmListView::TIME_TO_COLUMN), tta); 00431 mTimeToAlarmShown = !tta.isNull(); 00432 } 00433 TQTime t = dateTime.time(); 00434 mDateTimeOrder.sprintf("%04d%03d%02d%02d", dateTime.date().year(), dateTime.date().dayOfYear(), 00435 t.hour(), t.minute()); 00436 00437 int repeatOrder = 0; 00438 int repeatInterval = 0; 00439 TQString repeatText = event.recurrenceText(true); // text displayed in Repeat column 00440 if (repeatText.isEmpty()) 00441 repeatText = event.repetitionText(true); 00442 if (event.repeatAtLogin()) 00443 repeatOrder = 1; 00444 else 00445 { 00446 repeatInterval = event.recurInterval(); 00447 switch (event.recurType()) 00448 { 00449 case KARecurrence::MINUTELY: 00450 repeatOrder = 2; 00451 break; 00452 case KARecurrence::DAILY: 00453 repeatOrder = 3; 00454 break; 00455 case KARecurrence::WEEKLY: 00456 repeatOrder = 4; 00457 break; 00458 case KARecurrence::MONTHLY_DAY: 00459 case KARecurrence::MONTHLY_POS: 00460 repeatOrder = 5; 00461 break; 00462 case KARecurrence::ANNUAL_DATE: 00463 case KARecurrence::ANNUAL_POS: 00464 repeatOrder = 6; 00465 break; 00466 case KARecurrence::NO_RECUR: 00467 default: 00468 break; 00469 } 00470 } 00471 setText(parent->column(AlarmListView::REPEAT_COLUMN), repeatText); 00472 mRepeatOrder.sprintf("%c%08d", '0' + repeatOrder, repeatInterval); 00473 00474 bool showColour = (event.action() == KAEvent::MESSAGE || event.action() == KAEvent::FILE); 00475 mColourOrder.sprintf("%06u", (showColour ? event.bgColour().rgb() : 0)); 00476 00477 mTypeOrder.sprintf("%02d", event.action()); 00478 } 00479 00480 /****************************************************************************** 00481 * Return the single line alarm summary text. 00482 */ 00483 TQString AlarmListViewItem::alarmText(const KAEvent& event) const 00484 { 00485 bool truncated; 00486 TQString text = AlarmText::summary(event, 1, &truncated); 00487 mMessageTruncated = truncated; 00488 return text; 00489 } 00490 00491 /****************************************************************************** 00492 * Return the alarm time text in the form "date time". 00493 */ 00494 TQString AlarmListViewItem::alarmTimeText(const DateTime& dateTime) const 00495 { 00496 TDELocale* locale = TDEGlobal::locale(); 00497 TQString dateTimeText = locale->formatDate(dateTime.date(), true); 00498 if (!dateTime.isDateOnly()) 00499 { 00500 dateTimeText += ' '; 00501 TQString time = locale->formatTime(dateTime.time()); 00502 if (mTimeHourPos == -2) 00503 { 00504 // Initialise the position of the hour within the time string, if leading 00505 // zeroes are omitted, so that displayed times can be aligned with each other. 00506 mTimeHourPos = -1; // default = alignment isn't possible/sensible 00507 if (!TQApplication::reverseLayout()) // don't try to align right-to-left languages 00508 { 00509 TQString fmt = locale->timeFormat(); 00510 int i = fmt.find(TQRegExp("%[kl]")); // check if leading zeroes are omitted 00511 if (i >= 0 && i == fmt.find('%')) // and whether the hour is first 00512 mTimeHourPos = i; // yes, so need to align 00513 } 00514 } 00515 if (mTimeHourPos >= 0 && (int)time.length() > mTimeHourPos + 1 00516 && time[mTimeHourPos].isDigit() && !time[mTimeHourPos + 1].isDigit()) 00517 dateTimeText += '~'; // improve alignment of times with no leading zeroes 00518 dateTimeText += time; 00519 } 00520 return dateTimeText + ' '; 00521 } 00522 00523 /****************************************************************************** 00524 * Return the time-to-alarm text. 00525 */ 00526 TQString AlarmListViewItem::timeToAlarmText(const TQDateTime& now) const 00527 { 00528 if (event().expired()) 00529 return TQString(); 00530 DateTime dateTime = event().displayDateTime(); 00531 if (dateTime.isDateOnly()) 00532 { 00533 int days = now.date().daysTo(dateTime.date()); 00534 return i18n("n days", " %1d ").arg(days); 00535 } 00536 int mins = (now.secsTo(dateTime.dateTime()) + 59) / 60; 00537 if (mins < 0) 00538 return TQString(); 00539 char minutes[3] = "00"; 00540 minutes[0] = (mins%60) / 10 + '0'; 00541 minutes[1] = (mins%60) % 10 + '0'; 00542 if (mins < 24*60) 00543 return i18n("hours:minutes", " %1:%2 ").arg(mins/60).arg(minutes); 00544 int days = mins / (24*60); 00545 mins = mins % (24*60); 00546 return i18n("days hours:minutes", " %1d %2:%3 ").arg(days).arg(mins/60).arg(minutes); 00547 } 00548 00549 /****************************************************************************** 00550 * Update the displayed time-to-alarm value. 00551 * The updated value is only displayed if it is different from the existing value, 00552 * or if 'forceDisplay' is true. 00553 */ 00554 void AlarmListViewItem::updateTimeToAlarm(const TQDateTime& now, bool forceDisplay) 00555 { 00556 if (event().expired()) 00557 { 00558 if (forceDisplay || mTimeToAlarmShown) 00559 { 00560 setText(alarmListView()->column(AlarmListView::TIME_TO_COLUMN), TQString()); 00561 mTimeToAlarmShown = false; 00562 } 00563 } 00564 else 00565 { 00566 TQString tta = timeToAlarmText(now); 00567 if (forceDisplay || tta != text(alarmListView()->column(AlarmListView::TIME_TO_COLUMN))) 00568 setText(alarmListView()->column(AlarmListView::TIME_TO_COLUMN), tta); 00569 mTimeToAlarmShown = !tta.isNull(); 00570 } 00571 } 00572 00573 /****************************************************************************** 00574 * Paint one value in one of the columns in the list view. 00575 */ 00576 void AlarmListViewItem::paintCell(TQPainter* painter, const TQColorGroup& cg, int column, int width, int /*align*/) 00577 { 00578 const AlarmListView* listView = alarmListView(); 00579 int margin = listView->itemMargin(); 00580 TQRect box(margin, margin, width - margin*2, height() - margin*2); // area within which to draw 00581 bool selected = isSelected(); 00582 TQColor bgColour = selected ? cg.highlight() : cg.base(); 00583 TQColor fgColour = selected ? cg.highlightedText() 00584 : !event().enabled() ? Preferences::disabledColour() 00585 : event().expired() ? Preferences::expiredColour() : cg.text(); 00586 painter->setPen(fgColour); 00587 painter->fillRect(0, 0, width, height(), bgColour); 00588 00589 if (column == listView->column(AlarmListView::TIME_COLUMN)) 00590 { 00591 int i = -1; 00592 TQString str = text(column); 00593 if (mTimeHourPos >= 0) 00594 { 00595 // Need to pad out spacing to align times without leading zeroes 00596 i = str.find(" ~"); 00597 if (i >= 0) 00598 { 00599 if (mDigitWidth < 0) 00600 mDigitWidth = painter->fontMetrics().width("0"); 00601 TQString date = str.left(i + 1); 00602 int w = painter->fontMetrics().width(date) + mDigitWidth; 00603 painter->drawText(box, AlignVCenter, date); 00604 box.setLeft(box.left() + w); 00605 painter->drawText(box, AlignVCenter, str.mid(i + 2)); 00606 } 00607 } 00608 if (i < 0) 00609 painter->drawText(box, AlignVCenter, str); 00610 } 00611 else if (column == listView->column(AlarmListView::TIME_TO_COLUMN)) 00612 painter->drawText(box, AlignVCenter | AlignRight, text(column)); 00613 else if (column == listView->column(AlarmListView::REPEAT_COLUMN)) 00614 painter->drawText(box, AlignVCenter | AlignHCenter, text(column)); 00615 else if (column == listView->column(AlarmListView::COLOUR_COLUMN)) 00616 { 00617 // Paint the cell the colour of the alarm message 00618 if (event().action() == KAEvent::MESSAGE || event().action() == KAEvent::FILE) 00619 painter->fillRect(box, event().bgColour()); 00620 } 00621 else if (column == listView->column(AlarmListView::TYPE_COLUMN)) 00622 { 00623 // Display the alarm type icon, horizontally and vertically centred in the cell 00624 TQPixmap* pixmap = eventIcon(); 00625 TQRect pixmapRect = pixmap->rect(); 00626 int diff = box.height() - pixmap->height(); 00627 if (diff < 0) 00628 { 00629 pixmapRect.setTop(-diff / 2); 00630 pixmapRect.setHeight(box.height()); 00631 } 00632 TQPoint iconTopLeft(box.left() + (box.width() - pixmapRect.width()) / 2, 00633 box.top() + (diff > 0 ? diff / 2 : 0)); 00634 painter->drawPixmap(iconTopLeft, *pixmap, pixmapRect); 00635 } 00636 else if (column == listView->column(AlarmListView::MESSAGE_COLUMN)) 00637 { 00638 if (!selected && listView->drawMessageInColour()) 00639 { 00640 painter->fillRect(box, event().bgColour()); 00641 painter->setBackgroundColor(event().bgColour()); 00642 // painter->setPen(event().fgColour()); 00643 } 00644 TQString txt = text(column); 00645 painter->drawText(box, AlignVCenter, txt); 00646 mMessageColWidth = listView->fontMetrics().boundingRect(txt).width(); 00647 } 00648 } 00649 00650 /****************************************************************************** 00651 * Return the width needed for the icons in the alarm type column. 00652 */ 00653 int AlarmListViewItem::typeIconWidth(AlarmListView* v) 00654 { 00655 return iconWidth() + 2 * v->style().pixelMetric(TQStyle::PM_DefaultFrameWidth); 00656 } 00657 00658 /****************************************************************************** 00659 * Return the column sort order for one item in the list. 00660 */ 00661 TQString AlarmListViewItem::key(int column, bool) const 00662 { 00663 AlarmListView* listView = alarmListView(); 00664 if (column == listView->column(AlarmListView::TIME_COLUMN) 00665 || column == listView->column(AlarmListView::TIME_TO_COLUMN)) 00666 return mDateTimeOrder; 00667 if (column == listView->column(AlarmListView::REPEAT_COLUMN)) 00668 return mRepeatOrder; 00669 if (column == listView->column(AlarmListView::COLOUR_COLUMN)) 00670 return mColourOrder; 00671 if (column == listView->column(AlarmListView::TYPE_COLUMN)) 00672 return mTypeOrder; 00673 return text(column).lower(); 00674 } 00675 00676 00677 /*============================================================================= 00678 = Class: AlarmListTooltip 00679 = Displays the full alarm text in a tooltip when necessary. 00680 =============================================================================*/ 00681 00682 /****************************************************************************** 00683 * Displays the full alarm text in a tooltip, if not all the text is displayed. 00684 */ 00685 void AlarmListTooltip::maybeTip(const TQPoint& pt) 00686 { 00687 AlarmListView* listView = (AlarmListView*)parentWidget()->parentWidget(); 00688 int column = listView->column(AlarmListView::MESSAGE_COLUMN); 00689 int xOffset = listView->contentsX(); 00690 if (listView->header()->sectionAt(pt.x() + xOffset) == column) 00691 { 00692 AlarmListViewItem* item = (AlarmListViewItem*)listView->itemAt(pt); 00693 if (item) 00694 { 00695 int columnX = listView->header()->sectionPos(column) - xOffset; 00696 int columnWidth = listView->columnWidth(column); 00697 int widthNeeded = item->messageColWidthNeeded(); 00698 if (!item->messageTruncated() && columnWidth >= widthNeeded) 00699 { 00700 if (columnX + widthNeeded <= listView->viewport()->width()) 00701 return; 00702 } 00703 TQRect rect = listView->itemRect(item); 00704 rect.setLeft(columnX); 00705 rect.setWidth(columnWidth); 00706 kdDebug(5950) << "AlarmListTooltip::maybeTip(): display\n"; 00707 tip(rect, AlarmText::summary(item->event(), 10)); // display up to 10 lines of text 00708 } 00709 } 00710 } 00711