kalarm

alarmlistview.cpp

00001 /*
00002  *  alarmlistview.cpp  -  widget showing list of outstanding alarms
00003  *  Program:  kalarm
00004  *  Copyright © 2001-2006 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 <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 =  Class: AlarmListView
00056 =  Displays the list of outstanding alarms.
00057 =============================================================================*/
00058 QValueList<EventListViewBase*>  AlarmListView::mInstanceList;
00059 bool                            AlarmListView::mDragging = false;
00060 
00061 
00062 AlarmListView::AlarmListView(const QValueList<int>& order, QWidget* parent, const char* name)
00063     : EventListViewBase(parent, name),
00064       mMousePressed(false),
00065       mDrawMessageInColour(false),
00066       mShowExpired(false)
00067 {
00068     static QString titles[COLUMN_COUNT] = {
00069         i18n("Time"),
00070         i18n("Time To"),
00071         i18n("Repeat"),
00072         QString::null,
00073         QString::null,
00074         i18n("Message, File or Command")
00075     };
00076 
00077     setSelectionMode(QListView::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], Qt::AlignHCenter);
00137     setColumnWidthMode(mColumn[REPEAT_COLUMN], QListView::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], QListView::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], QListView::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     QDateTime now = QDateTime::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         QFontMetrics 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], QListView::Maximum);
00220         changed = true;
00221     }
00222     else if (!time  &&  w)
00223     {
00224         // Hide the time column
00225         setColumnWidthMode(mColumn[TIME_COLUMN], QListView::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], QListView::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], QListView::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         QDateTime now = QDateTime::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     QDateTime now = QDateTime::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 QDateTime& 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, QDateTime::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 QValueList<int> AlarmListView::columnOrder() const
00308 {
00309     QHeader* 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     QValueList<int> orderList;
00318     for (int i = 0;  i < COLUMN_COUNT;  ++i)
00319         orderList += order[i];
00320     return orderList;
00321 }
00322 
00323 /******************************************************************************
00324 *  Returns the QWhatsThis text for a specified column.
00325 */
00326 QString 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(QMouseEvent* e)
00349 {
00350     QListView::contentsMousePressEvent(e);
00351     if (e->button() == Qt::LeftButton)
00352     {
00353         QPoint 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(QMouseEvent* e)
00368 {
00369     QListView::contentsMouseMoveEvent(e);
00370     if (mMousePressed
00371     &&  (mMousePressPos - e->pos()).manhattanLength() > QApplication::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(QString::fromLatin1("UTC"));
00377         cal.setLocalTime();    // write out using local time (i.e. no time zone)
00378         QValueList<EventListViewItemBase*> items = selectedItems();
00379         if (!items.count())
00380             return;
00381         for (QValueList<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(QMouseEvent *e)
00403 {
00404     QListView::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 QDateTime& 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.nextDateTime(false);
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         QString tta = timeToAlarmText(now);
00430         setText(parent->column(AlarmListView::TIME_TO_COLUMN), tta);
00431         mTimeToAlarmShown = !tta.isNull();
00432     }
00433     QTime 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     QString 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 QString AlarmListViewItem::alarmText(const KAEvent& event) const
00484 {
00485     bool truncated;
00486     QString 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 QString AlarmListViewItem::alarmTimeText(const DateTime& dateTime) const
00495 {
00496     KLocale* locale = KGlobal::locale();
00497     QString dateTimeText = locale->formatDate(dateTime.date(), true);
00498     if (!dateTime.isDateOnly())
00499     {
00500         dateTimeText += ' ';
00501         QString 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 (!QApplication::reverseLayout())    // don't try to align right-to-left languages
00508             {
00509                 QString fmt = locale->timeFormat();
00510                 int i = fmt.find(QRegExp("%[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 QString AlarmListViewItem::timeToAlarmText(const QDateTime& now) const
00527 {
00528     if (event().expired())
00529         return QString::null;
00530     DateTime dateTime = event().nextDateTime(false);
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 QString::null;
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 QDateTime& now, bool forceDisplay)
00555 {
00556     if (event().expired())
00557     {
00558         if (forceDisplay  ||  mTimeToAlarmShown)
00559         {
00560             setText(alarmListView()->column(AlarmListView::TIME_TO_COLUMN), QString::null);
00561             mTimeToAlarmShown = false;
00562         }
00563     }
00564     else
00565     {
00566         QString 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(QPainter* painter, const QColorGroup& cg, int column, int width, int /*align*/)
00577 {
00578     const AlarmListView* listView = alarmListView();
00579     int    margin = listView->itemMargin();
00580     QRect  box(margin, margin, width - margin*2, height() - margin*2);   // area within which to draw
00581     bool   selected = isSelected();
00582     QColor bgColour = selected ? cg.highlight() : cg.base();
00583     QColor 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         QString 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                 QString 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         QPixmap* pixmap = eventIcon();
00625         QRect 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         QPoint 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         QString 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(QStyle::PM_DefaultFrameWidth);
00656 }
00657 
00658 /******************************************************************************
00659 *  Return the column sort order for one item in the list.
00660 */
00661 QString 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 QPoint& 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             QRect 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 
KDE Home | KDE Accessibility Home | Description of Access Keys