Vidalia 0.2.10

RouterListWidget.cpp

Go to the documentation of this file.
00001 /*
00002 **  This file is part of Vidalia, and is subject to the license terms in the
00003 **  LICENSE file, found in the top level directory of this distribution. If you
00004 **  did not receive the LICENSE file with this file, you may obtain it from the
00005 **  Vidalia source package distributed by the Vidalia Project at
00006 **  http://www.vidalia-project.net/. No part of Vidalia, including this file,
00007 **  may be copied, modified, propagated, or distributed except according to the
00008 **  terms described in the LICENSE file.
00009 */
00010 
00011 /*
00012 ** \file RouterListWidget.cpp
00013 ** \version $Id: RouterListWidget.cpp 4378 2010-08-05 20:28:54Z edmanm $
00014 ** \brief Displays a list of Tor servers and their status
00015 */
00016 
00017 #include "RouterListWidget.h"
00018 #include "RouterListItem.h"
00019 #include "Vidalia.h"
00020 
00021 #include <QHeaderView>
00022 #include <QClipboard>
00023 
00024 #define IMG_ZOOM   ":/images/22x22/page-zoom.png"
00025 #define IMG_COPY   ":/images/22x22/edit-copy.png"
00026 
00027 
00028 RouterListWidget::RouterListWidget(QWidget *parent)
00029   : QTreeWidget(parent)
00030 {
00031   /* Create and initialize columns */
00032   setHeaderLabels(QStringList() << QString("")
00033                                 << QString("")
00034                                 << tr("Relay"));
00035 
00036   /* Sort by descending server bandwidth */
00037   sortItems(StatusColumn, Qt::DescendingOrder);
00038 
00039   /* Find out when the selected item has changed. */
00040   connect(this, SIGNAL(itemSelectionChanged()), 
00041           this, SLOT(onSelectionChanged()));
00042 }
00043 
00044 /** Called when the user changes the UI translation. */
00045 void
00046 RouterListWidget::retranslateUi()
00047 {
00048   setHeaderLabels(QStringList() << QString("")
00049                                 << QString("")
00050                                 << tr("Relay"));
00051 }
00052 
00053 /** Called when the user requests a context menu for a router in the list. A
00054  * context menu will be displayed providing a list of actions, including
00055  * zooming in on the server. */
00056 void
00057 RouterListWidget::contextMenuEvent(QContextMenuEvent *event)
00058 {
00059   QAction *action;
00060   QMenu *menu, *copyMenu;
00061   QList<QTreeWidgetItem *> selected;
00062 
00063   selected = selectedItems();
00064   if (! selected.size())
00065     return;
00066 
00067   menu = new QMenu();
00068   copyMenu = menu->addMenu(QIcon(IMG_COPY), tr("Copy"));
00069   action = copyMenu->addAction(tr("Nickname"));
00070   connect(action, SIGNAL(triggered()), this, SLOT(copySelectedNicknames()));
00071 
00072   action = copyMenu->addAction(tr("Fingerprint"));
00073   connect(action, SIGNAL(triggered()), this, SLOT(copySelectedFingerprints()));
00074 
00075   action = menu->addAction(QIcon(IMG_ZOOM), tr("Zoom to Relay"));
00076   if (selected.size() > 1)
00077     action->setEnabled(false);
00078   else
00079     connect(action, SIGNAL(triggered()), this, SLOT(zoomToSelectedRelay()));
00080 
00081   menu->exec(event->globalPos());
00082   delete menu;
00083 }
00084 
00085 /** Copies the nicknames for all currently selected relays to the clipboard.
00086  * Nicknames are formatted as a comma-delimited list, suitable for doing
00087  * dumb things with your torrc. */
00088 void
00089 RouterListWidget::copySelectedNicknames()
00090 {
00091   QString text;
00092 
00093   foreach (QTreeWidgetItem *item, selectedItems()) {
00094     RouterListItem *relay = dynamic_cast<RouterListItem *>(item);
00095     if (relay)
00096       text.append(relay->name() + ",");
00097   }
00098   if (text.length()) {
00099     text.remove(text.length()-1, 1);
00100     vApp->clipboard()->setText(text);
00101   }
00102 }
00103 
00104 /** Copies the fingerprints for all currently selected relays to the
00105  * clipboard. Fingerprints are formatted as a comma-delimited list, suitable
00106  * for doing dumb things with your torrc. */
00107 void
00108 RouterListWidget::copySelectedFingerprints()
00109 {
00110   QString text;
00111 
00112   foreach (QTreeWidgetItem *item, selectedItems()) {
00113     RouterListItem *relay = dynamic_cast<RouterListItem *>(item);
00114     if (relay)
00115       text.append("$" + relay->id() + ",");
00116   }
00117   if (text.length()) {
00118     text.remove(text.length()-1, 1);
00119     vApp->clipboard()->setText(text);
00120   }
00121 }
00122 
00123 /** Emits a zoomToRouter() signal containing the fingerprint of the
00124  * currently selected relay. */
00125 void
00126 RouterListWidget::zoomToSelectedRelay()
00127 {
00128   QList<QTreeWidgetItem *> selected = selectedItems();
00129   if (selected.size() != 1)
00130     return;
00131 
00132   RouterListItem *relay = dynamic_cast<RouterListItem *>(selected[0]);
00133   if (relay)
00134     emit zoomToRouter(relay->id());
00135 }
00136 
00137 /** Deselects all currently selected routers. */
00138 void
00139 RouterListWidget::deselectAll()
00140 {
00141   QList<QTreeWidgetItem *> selected = selectedItems();
00142   foreach (QTreeWidgetItem *item, selected) {
00143     setItemSelected(item, false);
00144   }
00145 }
00146 
00147 /** Clear the list of router items. */
00148 void
00149 RouterListWidget::clearRouters()
00150 {
00151   _idmap.clear();
00152   QTreeWidget::clear();
00153   setStatusTip(tr("%1 relays online").arg(0));
00154 }
00155 
00156 /** Called when the user selects a router from the list. This will search the
00157  * list for a router whose names starts with the key pressed. */
00158 void
00159 RouterListWidget::keyPressEvent(QKeyEvent *event)
00160 {
00161   int index;
00162   
00163   QString key = event->text();
00164   if (!key.isEmpty() && key.at(0).isLetterOrNumber()) {
00165     /* A text key was pressed, so search for routers that begin with that key. */
00166     QList<QTreeWidgetItem *> list = findItems(QString("^[%1%2].*$")
00167                                                   .arg(key.toUpper())
00168                                                   .arg(key.toLower()),
00169                                                Qt::MatchRegExp|Qt::MatchWrap,
00170                                                NameColumn);
00171     if (list.size() > 0) {
00172       QList<QTreeWidgetItem *> s = selectedItems();
00173       
00174       /* A match was found, so deselect any previously selected routers,
00175        * select the new match, and make sure it's visible. If there was
00176        * already a router selected that started with the search key, go to the
00177        * next match in the list. */
00178       deselectAll();
00179       index = (!s.size() ? 0 : (list.indexOf(s.at(0)) + 1) % list.size());
00180 
00181       /* Select the item and scroll to it */
00182       setItemSelected(list.at(index), true);
00183       scrollToItem(list.at(index));
00184     }
00185     event->accept();
00186   } else {
00187     /* It was something we don't understand, so hand it to the parent class */
00188     QTreeWidget::keyPressEvent(event);
00189   }
00190 }
00191 
00192 /** Finds the list item whose key ID matches <b>id</b>. Returns 0 if not 
00193  * found. */
00194 RouterListItem*
00195 RouterListWidget::findRouterById(QString id)
00196 {
00197   if (_idmap.contains(id)) {
00198     return _idmap.value(id);
00199   }
00200   return 0;
00201 }
00202 
00203 /** Adds a router descriptor to the list. */
00204 RouterListItem*
00205 RouterListWidget::addRouter(const RouterDescriptor &rd)
00206 {
00207   QString id = rd.id();
00208   if (id.isEmpty())
00209     return 0;
00210 
00211   RouterListItem *item = findRouterById(id);
00212   if (item) {
00213     item->update(rd);
00214   } else {
00215     item = new RouterListItem(this, rd);
00216     addTopLevelItem(item);
00217     _idmap.insert(id, item);
00218   }
00219 
00220   /* Set our status tip to the number of servers in the list */
00221   setStatusTip(tr("%1 relays online").arg(topLevelItemCount()));
00222 
00223   return item;
00224 }
00225 
00226 /** Called when the selected items have changed. This emits the 
00227  * routerSelected() signal with the descriptor for the selected router.
00228  */
00229 void
00230 RouterListWidget::onSelectionChanged()
00231 {
00232   QList<RouterDescriptor> descriptors;
00233 
00234   foreach (QTreeWidgetItem *item, selectedItems()) {
00235     RouterListItem *relay = dynamic_cast<RouterListItem *>(item);
00236     if (relay)
00237       descriptors << relay->descriptor();
00238   }
00239   if (descriptors.count() > 0)
00240     emit routerSelected(descriptors);
00241 }
00242