kalarm

eventlistviewbase.cpp

00001 /*
00002  *  eventlistviewbase.cpp  -  base classes for widget showing list of events
00003  *  Program:  kalarm
00004  *  Copyright (c) 2004-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 <qwhatsthis.h>
00024 #include <qheader.h>
00025 
00026 #include <kiconloader.h>
00027 #include <kdebug.h>
00028 
00029 #include "find.h"
00030 #include "eventlistviewbase.moc"
00031 
00032 
00033 class EventListWhatsThisBase : public QWhatsThis
00034 {
00035     public:
00036         EventListWhatsThisBase(EventListViewBase* lv) : QWhatsThis(lv), mListView(lv) { }
00037         virtual QString text(const QPoint&);
00038     private:
00039         EventListViewBase* mListView;
00040 };
00041 
00042 
00043 /*=============================================================================
00044 =  Class: EventListViewBase
00045 =  Base class for displaying a list of events.
00046 =============================================================================*/
00047 
00048 EventListViewBase::EventListViewBase(QWidget* parent, const char* name)
00049     : KListView(parent, name),
00050       mFind(0),
00051       mLastColumn(-1),
00052       mLastColumnHeaderWidth(0)
00053 {
00054     setAllColumnsShowFocus(true);
00055     setShowSortIndicator(true);
00056 
00057     new EventListWhatsThisBase(this);
00058 }
00059 
00060 void EventListViewBase::addLastColumn(const QString& title)
00061 {
00062     addColumn(title);
00063     mLastColumn = columns() - 1;
00064     mLastColumnHeaderWidth = columnWidth(mLastColumn);
00065     setColumnWidthMode(mLastColumn, QListView::Maximum);
00066 }
00067 
00068 /******************************************************************************
00069 *  Refresh the list by clearing it and redisplaying all the current alarms.
00070 */
00071 void EventListViewBase::refresh()
00072 {
00073     QString currentID;
00074     if (currentItem())
00075         currentID = currentItem()->event().id();    // save current item for restoration afterwards
00076     clear();
00077     populate();
00078     resizeLastColumn();
00079     EventListViewItemBase* current = getEntry(currentID);
00080     if (current)
00081     {
00082         setCurrentItem(current);
00083         ensureItemVisible(current);
00084     }
00085 }
00086 
00087 /******************************************************************************
00088 *  Get the item for a given event ID.
00089 */
00090 EventListViewItemBase* EventListViewBase::getEntry(const QString& eventID) const
00091 {
00092     if (!eventID.isEmpty())
00093     {
00094         for (EventListViewItemBase* item = firstChild();  item;  item = item->nextSibling())
00095             if (item->event().id() == eventID)
00096                 return item;
00097     }
00098     return 0;
00099 }
00100 
00101 /******************************************************************************
00102 *  Add an event to every list instance.
00103 *  If 'selectionView' is non-null, the selection highlight is moved to the new
00104 *  event in that listView instance.
00105 */
00106 void EventListViewBase::addEvent(const KAEvent& event, const InstanceList& instanceList, EventListViewBase* selectionView)
00107 {
00108     for (InstanceListConstIterator it = instanceList.begin();  it != instanceList.end();  ++it)
00109         (*it)->addEntry(event, true, (*it == selectionView));
00110 }
00111 
00112 /******************************************************************************
00113 *  Modify an event in every list instance.
00114 *  If 'selectionView' is non-null, the selection highlight is moved to the
00115 *  modified event in that listView instance.
00116 */
00117 void EventListViewBase::modifyEvent(const QString& oldEventID, const KAEvent& newEvent,
00118                                     const InstanceList& instanceList, EventListViewBase* selectionView)
00119 {
00120     for (InstanceListConstIterator it = instanceList.begin();  it != instanceList.end();  ++it)
00121     {
00122         EventListViewBase* v = *it;
00123         EventListViewItemBase* item = v->getEntry(oldEventID);
00124         if (item)
00125             v->deleteEntry(item, false);
00126         v->addEntry(newEvent, true, (v == selectionView));
00127     }
00128 }
00129 
00130 /******************************************************************************
00131 *  Delete an event from every displayed list.
00132 */
00133 void EventListViewBase::deleteEvent(const QString& eventID, const InstanceList& instanceList)
00134 {
00135     for (InstanceListConstIterator it = instanceList.begin();  it != instanceList.end();  ++it)
00136     {
00137         EventListViewBase* v = *it;
00138         EventListViewItemBase* item = v->getEntry(eventID);
00139         if (item)
00140             v->deleteEntry(item, true);
00141         else
00142             v->refresh();
00143     }
00144 }
00145 
00146 /******************************************************************************
00147 *  Add a new item to the list.
00148 *  If 'reselect' is true, select/highlight the new item.
00149 */
00150 EventListViewItemBase* EventListViewBase::addEntry(const KAEvent& event, bool setSize, bool reselect)
00151 {
00152     if (!shouldShowEvent(event))
00153         return 0;
00154     return addEntry(createItem(event), setSize, reselect);
00155 }
00156 
00157 EventListViewItemBase* EventListViewBase::addEntry(EventListViewItemBase* item, bool setSize, bool reselect)
00158 {
00159     if (setSize)
00160         resizeLastColumn();
00161     if (reselect)
00162     {
00163         clearSelection();
00164         setSelected(item, true);
00165     }
00166     return item;
00167 }
00168 
00169 /******************************************************************************
00170 *  Update a specified item in the list.
00171 *  If 'reselect' is true, select the updated item.
00172 */
00173 EventListViewItemBase* EventListViewBase::updateEntry(EventListViewItemBase* item, const KAEvent& newEvent, bool setSize, bool reselect)
00174 {
00175     deleteEntry(item);
00176     return addEntry(newEvent, setSize, reselect);
00177 }
00178 
00179 /******************************************************************************
00180 *  Delete a specified item from the list.
00181 */
00182 void EventListViewBase::deleteEntry(EventListViewItemBase* item, bool setSize)
00183 {
00184     if (item)
00185     {
00186         delete item;
00187         if (setSize)
00188             resizeLastColumn();
00189         emit itemDeleted();
00190     }
00191 }
00192 
00193 /******************************************************************************
00194 *  Called when the Find action is selected.
00195 *  Display the non-modal Find dialog.
00196 */
00197 void EventListViewBase::slotFind()
00198 {
00199     if (!mFind)
00200     {
00201         mFind = new Find(this);
00202         connect(mFind, SIGNAL(active(bool)), SIGNAL(findActive(bool)));
00203     }
00204     mFind->display();
00205 }
00206 
00207 /******************************************************************************
00208 *  Called when the Find Next or Find Prev action is selected.
00209 */
00210 void EventListViewBase::findNext(bool forward)
00211 {
00212     if (mFind)
00213         mFind->findNext(forward);
00214 }
00215 
00216 /******************************************************************************
00217 *  Called when the Select All action is selected.
00218 *  Select all items in the list.
00219 */
00220 void EventListViewBase::slotSelectAll()
00221 {
00222     if (selectionMode() == QListView::Multi  ||  selectionMode() == QListView::Extended)
00223         selectAll(true);
00224 }
00225 
00226 /******************************************************************************
00227 *  Called when the Deselect action is selected.
00228 *  Deselect all items in the list.
00229 */
00230 void EventListViewBase::slotDeselect()
00231 {
00232     selectAll(false);
00233 }
00234 
00235 /******************************************************************************
00236 *  Check whether there are any selected items.
00237 */
00238 bool EventListViewBase::anySelected() const
00239 {
00240     for (QListViewItem* item = KListView::firstChild();  item;  item = item->nextSibling())
00241         if (isSelected(item))
00242             return true;
00243     return false;
00244 }
00245 
00246 /******************************************************************************
00247 *  Get the single selected event.
00248 *  Reply = the event
00249 *        = 0 if no event is selected or multiple events are selected.
00250 */
00251 const KAEvent* EventListViewBase::selectedEvent() const
00252 {
00253     EventListViewItemBase* sel = selectedItem();
00254     return sel ? &sel->event() : 0;
00255 }
00256 
00257 /******************************************************************************
00258 *  Fetch the single selected item.
00259 *  This method works in both Single and Multi selection mode, unlike
00260 *  QListView::selectedItem().
00261 *  Reply = null if no items are selected, or if multiple items are selected.
00262 */
00263 EventListViewItemBase* EventListViewBase::selectedItem() const
00264 {
00265     if (selectionMode() == QListView::Single)
00266         return (EventListViewItemBase*)KListView::selectedItem();
00267 
00268     QListViewItem* item = 0;
00269     for (QListViewItem* it = firstChild();  it;  it = it->nextSibling())
00270     {
00271         if (isSelected(it))
00272         {
00273             if (item)
00274                 return 0;
00275             item = it;
00276         }
00277     }
00278     return (EventListViewItemBase*)item;
00279 }
00280 
00281 /******************************************************************************
00282 *  Fetch all selected items.
00283 */
00284 QValueList<EventListViewItemBase*> EventListViewBase::selectedItems() const
00285 {
00286     QValueList<EventListViewItemBase*> items;
00287     for (QListViewItem* item = firstChild();  item;  item = item->nextSibling())
00288     {
00289         if (isSelected(item))
00290             items.append((EventListViewItemBase*)item);
00291     }
00292     return items;
00293 }
00294 
00295 /******************************************************************************
00296 *  Return how many items are selected.
00297 */
00298 int EventListViewBase::selectedCount() const
00299 {
00300     int count = 0;
00301     for (QListViewItem* item = firstChild();  item;  item = item->nextSibling())
00302     {
00303         if (isSelected(item))
00304             ++count;
00305     }
00306     return count;
00307 }
00308 
00309 /******************************************************************************
00310 *  Sets the last column in the list view to extend at least to the right hand
00311 *  edge of the list view.
00312 */
00313 void EventListViewBase::resizeLastColumn()
00314 {
00315     int lastColumnWidth = mLastColumnHeaderWidth;
00316     for (EventListViewItemBase* item = firstChild();  item;  item = item->nextSibling())
00317     {
00318         int mw = item->lastColumnWidth();
00319         if (mw > lastColumnWidth)
00320             lastColumnWidth = mw;
00321     }
00322     QHeader* head = header();
00323     int x = head->sectionPos(mLastColumn);
00324     int availableWidth = visibleWidth() - x;
00325     int rightColWidth = 0;
00326     int index = head->mapToIndex(mLastColumn);
00327     if (index < mLastColumn)
00328     {
00329         // The last column has been dragged by the user to a different position.
00330         // Ensure that the columns now to the right of it are still shown.
00331         for (int i = index + 1;  i <= mLastColumn;  ++i)
00332             rightColWidth += columnWidth(head->mapToSection(i));
00333         availableWidth -= rightColWidth;
00334     }
00335     if (availableWidth < lastColumnWidth)
00336         availableWidth = lastColumnWidth;
00337     setColumnWidth(mLastColumn, availableWidth);
00338     if (contentsWidth() > x + availableWidth + rightColWidth)
00339         resizeContents(x + availableWidth + rightColWidth, contentsHeight());
00340 }
00341 
00342 /******************************************************************************
00343 *  Called when the widget's size has changed (before it is painted).
00344 *  Sets the last column in the list view to extend at least to the right hand
00345 *  edge of the list view.
00346 */
00347 void EventListViewBase::resizeEvent(QResizeEvent* re)
00348 {
00349     KListView::resizeEvent(re);
00350     resizeLastColumn();
00351 }
00352 
00353 /******************************************************************************
00354 *  Called when the widget is first displayed.
00355 *  Sets the last column in the list view to extend at least to the right hand
00356 *  edge of the list view.
00357 */
00358 void EventListViewBase::showEvent(QShowEvent* se)
00359 {
00360     KListView::showEvent(se);
00361     resizeLastColumn();
00362 }
00363 
00364 /******************************************************************************
00365 *  Find the height of one list item.
00366 */
00367 int EventListViewBase::itemHeight()
00368 {
00369     EventListViewItemBase* item = firstChild();
00370     if (!item)
00371     {
00372         // The list is empty, so create a temporary item to find its height
00373         QListViewItem* item = new QListViewItem(this, QString::null);
00374         int height = item->height();
00375         delete item;
00376         return height;
00377     }
00378     else
00379         return item->height();
00380 }
00381 
00382 
00383 /*=============================================================================
00384 =  Class: EventListViewItemBase
00385 =  Base class containing the details of one event for display in an
00386 *  EventListViewBase.
00387 =============================================================================*/
00388 QPixmap* EventListViewItemBase::mTextIcon;
00389 QPixmap* EventListViewItemBase::mFileIcon;
00390 QPixmap* EventListViewItemBase::mCommandIcon;
00391 QPixmap* EventListViewItemBase::mEmailIcon;
00392 int      EventListViewItemBase::mIconWidth = 0;
00393 
00394 
00395 EventListViewItemBase::EventListViewItemBase(EventListViewBase* parent, const KAEvent& event)
00396     : QListViewItem(parent),
00397       mEvent(event)
00398 {
00399     iconWidth();    // load the icons
00400 }
00401 
00402 /******************************************************************************
00403 *  Set the text for the last column, and find its width.
00404 */
00405 void EventListViewItemBase::setLastColumnText()
00406 {
00407     EventListViewBase* parent = (EventListViewBase*)listView();
00408     setText(parent->lastColumn(), lastColumnText());
00409     mLastColumnWidth = width(parent->fontMetrics(), parent, parent->lastColumn());
00410 }
00411 
00412 /******************************************************************************
00413 *  Return the width of the widest alarm type icon.
00414 */
00415 int EventListViewItemBase::iconWidth()
00416 {
00417     if (!mIconWidth)
00418     {
00419         mTextIcon    = new QPixmap(SmallIcon("message"));
00420         mFileIcon    = new QPixmap(SmallIcon("file"));
00421         mCommandIcon = new QPixmap(SmallIcon("exec"));
00422         mEmailIcon   = new QPixmap(SmallIcon("mail_generic"));
00423         if (mTextIcon)
00424             mIconWidth = mTextIcon->width();
00425         if (mFileIcon  &&  mFileIcon->width() > mIconWidth)
00426             mIconWidth = mFileIcon->width();
00427         if (mCommandIcon  &&  mCommandIcon->width() > mIconWidth)
00428             mIconWidth = mCommandIcon->width();
00429         if (mEmailIcon  &&  mEmailIcon->width() > mIconWidth)
00430             mIconWidth = mEmailIcon->width();
00431     }
00432     return mIconWidth;
00433 }
00434 
00435 /******************************************************************************
00436 *  Return the icon associated with the event's action.
00437 */
00438 QPixmap* EventListViewItemBase::eventIcon() const
00439 {
00440     switch (mEvent.action())
00441     {
00442         case KAAlarm::FILE:     return mFileIcon;
00443         case KAAlarm::COMMAND:  return mCommandIcon;
00444         case KAAlarm::EMAIL:    return mEmailIcon;
00445         case KAAlarm::MESSAGE:
00446         default:                return mTextIcon;
00447     }
00448 }
00449 
00450 
00451 /*=============================================================================
00452 =  Class: EventListWhatsThisBase
00453 =  Sets What's This? text depending on where in the list view is clicked.
00454 =============================================================================*/
00455 
00456 QString EventListWhatsThisBase::text(const QPoint& pt)
00457 {
00458     int column = -1;
00459     QPoint viewportPt = mListView->viewport()->mapFrom(mListView, pt);
00460     QRect frame = mListView->header()->frameGeometry();
00461     if (frame.contains(pt)
00462     ||  mListView->itemAt(QPoint(mListView->itemMargin(), viewportPt.y())) && frame.contains(QPoint(pt.x(), frame.y())))
00463         column = mListView->header()->sectionAt(pt.x());
00464     return mListView->whatsThisText(column);
00465 }
00466 
KDE Home | KDE Accessibility Home | Description of Access Keys