routerlistwidget.cpp

Go to the documentation of this file.
00001 /****************************************************************
00002  *  Vidalia is distributed under the following license:
00003  *
00004  *  Copyright (C) 2006,  Matt Edman, Justin Hipple
00005  *
00006  *  This program is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU General Public License
00008  *  as published by the Free Software Foundation; either version 2
00009  *  of the License, or (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
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, 
00019  *  Boston, MA  02110-1301, USA.
00020  ****************************************************************/
00021 
00022 /** 
00023  * \file routerlistwidget.cpp
00024  * \version $Id: routerlistwidget.cpp 1638 2007-02-16 21:51:40Z edmanm $
00025  * \brief Displays a list of Tor servers and their status
00026  */
00027 
00028 #include <QHeaderView>
00029 #include <vidalia.h>
00030 
00031 #include "routerlistwidget.h"
00032 
00033 #define IMG_ZOOM   ":/images/16x16/zoom.png"
00034 
00035 
00036 RouterListWidget::RouterListWidget(QWidget *parent)
00037 : QTreeWidget(parent)
00038 {
00039   _onlineRouterCount = 0;
00040   
00041   /* Create and initialize columns */
00042   setHeaderLabels(QStringList() << QString("")
00043                                 << QString("")
00044                                 << tr("Server"));
00045 
00046   /* Sort by descending server bandwidth */
00047   sortItems(StatusColumn, Qt::DescendingOrder);
00048 
00049   /* Find out when the selected item has changed. */
00050   connect(this, SIGNAL(itemSelectionChanged()), 
00051           this, SLOT(onSelectionChanged()));
00052 
00053   /* Set up the router item context menu */
00054   _routerContextMenu = new QMenu(this);
00055   _zoomToRouterAct = new QAction(QIcon(IMG_ZOOM), tr("Zoom to Server"), this);
00056   _routerContextMenu->addAction(_zoomToRouterAct);
00057 }
00058 
00059 /** Called when the user presses and releases a mouse button. If the event
00060  * indicates a right-click on a router item, a context menu will be displayed
00061  * providing a list of actions, including zooming in on the server. */
00062 void
00063 RouterListWidget::mouseReleaseEvent(QMouseEvent *e)
00064 {
00065   if (e->button() == Qt::RightButton) {
00066     /* Find out which server was right-clicked */
00067     RouterListItem *item = (RouterListItem *)itemAt(e->pos());
00068     if (!item) {
00069       return;
00070     }
00071 
00072     /* Display a context menu for this router item */
00073     QPoint pos = e->globalPos();
00074     QAction *action = _routerContextMenu->exec(pos);
00075     if (action == _zoomToRouterAct) {
00076       /* Zoom in on this router */
00077       emit zoomToRouter(item->id());
00078     }
00079   }
00080 }
00081 
00082 /** Deselects all currently selected routers. */
00083 void
00084 RouterListWidget::deselectAll()
00085 {
00086   QList<QTreeWidgetItem *> selected = selectedItems();
00087   foreach (QTreeWidgetItem *item, selected) {
00088     setItemSelected(item, false);
00089   }
00090 }
00091 
00092 /** Clear the list of router items. */
00093 void
00094 RouterListWidget::clearRouters()
00095 {
00096   _idmap.clear();
00097   _onlineRouterCount = 0;
00098   QTreeWidget::clear();
00099 }
00100 
00101 /** Inserts a new router list item into the list, in its proper sorted place
00102  * according to the current sort column. */
00103 void
00104 RouterListWidget::insertSorted(RouterListItem *item)
00105 {
00106   /* Qt >= 4.2 handles the sorting in addTopLevelItem(). We need to do the
00107    * sorted inserts ourselves in older Qts. */
00108 #if QT_VERSION < 0x040200
00109   Qt::SortOrder order = header()->sortIndicatorOrder();
00110   int left  = 0;
00111   int right = topLevelItemCount();
00112   int mid;
00113 
00114   while (left < right) {
00115     mid = (left + right)/2;
00116     if (order == Qt::AscendingOrder) {
00117       if (*((RouterListItem *)topLevelItem(mid)) < *item) {
00118         left = mid + 1;
00119       } else {
00120         right = mid;
00121       }
00122     } else {
00123       if (*item < *((RouterListItem *)topLevelItem(mid))) {
00124         left = mid+1;
00125       } else {
00126         right = mid;
00127       }
00128     }
00129   }
00130  
00131   if (left == topLevelItemCount()) {
00132     addTopLevelItem(item);
00133   } else {
00134     insertTopLevelItem(left, item);
00135   }
00136 #else
00137   addTopLevelItem(item);
00138 #endif
00139 }
00140 
00141 /** Called when the user selects a router from the list. This will search the
00142  * list for a router whose names starts with the key pressed. */
00143 void
00144 RouterListWidget::keyPressEvent(QKeyEvent *event)
00145 {
00146   int index;
00147   
00148   QString key = event->text();
00149   if (!key.isEmpty() && key.at(0).isLetterOrNumber()) {
00150     /* A text key was pressed, so search for routers that begin with that key. */
00151     QList<QTreeWidgetItem *> list = findItems(QString("^[%1%2].*$")
00152                                                   .arg(key.toUpper())
00153                                                   .arg(key.toLower()),
00154                                                Qt::MatchRegExp|Qt::MatchWrap,
00155                                                NameColumn);
00156     if (list.size() > 0) {
00157       QList<QTreeWidgetItem *> s = selectedItems();
00158       
00159       /* A match was found, so deselect any previously selected routers,
00160        * select the new match, and make sure it's visible. If there was
00161        * already a router selected that started with the search key, go to the
00162        * next match in the list. */
00163       deselectAll();
00164       index = (!s.size() ? 0 : (list.indexOf(s.at(0)) + 1) % list.size());
00165 
00166       /* Select the item and scroll to it */
00167       setItemSelected(list.at(index), true);
00168       scrollToItem(list.at(index));
00169     }
00170     event->accept();
00171   } else {
00172     /* It was something we don't understand, so hand it to the parent class */
00173     QTreeWidget::keyPressEvent(event);
00174   }
00175 }
00176 
00177 /** Finds the list item whose key ID matches <b>id</b>. Returns 0 if not 
00178  * found. */
00179 RouterListItem*
00180 RouterListWidget::findRouterById(QString id)
00181 {
00182   if (_idmap.contains(id)) {
00183     return _idmap.value(id);
00184   }
00185   return 0;
00186 }
00187 
00188 /** Finds the list item whose router nickname matches <b>name</b>. If more 
00189  * than one router exists with given name, the first match will be returned. 
00190  * Returns 0 if not found. */
00191 RouterListItem*
00192 RouterListWidget::findRouterByName(QString name)
00193 {
00194   QList<QTreeWidgetItem *> list = findItems(name,
00195                                             Qt::MatchExactly,
00196                                             NameColumn);
00197   /* It's possible that more than one router could have the same name, but
00198    * without a fingerprint on which to match, we just have to pick one. We'll
00199    * return the first match. */
00200   if (list.size() > 0) {
00201     return (RouterListItem *)list.at(0);
00202   }
00203   return 0;
00204 }
00205 
00206 /** Adds a router descriptor to the list. */
00207 void
00208 RouterListWidget::addRouter(RouterDescriptor rd)
00209 {
00210   QString id = rd.id();
00211   if (!id.isEmpty()) {
00212     RouterListItem *item = findRouterById(id);
00213     if (item) {
00214       /* This is an updated descriptor, so remove the old item and we'll 
00215        * add a new, updated item. */
00216       if (item->descriptor().online())
00217         _onlineRouterCount--;
00218       delete takeTopLevelItem(indexOfTopLevelItem(item));
00219       _idmap.remove(id);
00220     }
00221 
00222     /* Add the router item to the list and store its descriptor. */
00223     item = new RouterListItem(this, rd);
00224     insertSorted(item);
00225     _idmap.insert(id, item);
00226 
00227     /* Set our status tip to the number of servers in the list */
00228     if (rd.online())
00229       _onlineRouterCount++;
00230     setStatusTip(tr("%1 servers online (%2 total)")
00231                               .arg(_onlineRouterCount)
00232                               .arg(topLevelItemCount()));
00233   }
00234 }
00235 
00236 /** Called when the selected items have changed. This emits the 
00237  * routerSelected() signal with the descriptor for the selected router.
00238  */
00239 void
00240 RouterListWidget::onSelectionChanged()
00241 {
00242   RouterDescriptor rd;
00243   QList<QTreeWidgetItem *> items = selectedItems();
00244 
00245   if (items.count() > 0) {
00246     rd = ((RouterListItem *)items[0])->descriptor();
00247   }
00248   emit routerSelected(rd);
00249 }
00250 

Generated on Wed Sep 5 15:49:28 2007 for Vidalia by  doxygen 1.5.3