circuitlistwidget.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 circuitlistwidget.cpp
00024  * \version $Id: circuitlistwidget.cpp 1627 2007-02-05 02:04:30Z edmanm $
00025  * \brief Collection of Tor circuits as CircuitItems
00026  */
00027 
00028 #include <QPoint>
00029 #include <QTimer>
00030 
00031 #include "circuitlistwidget.h"
00032 
00033 #define IMG_CLOSE   ":/images/16x16/network-offline.png"
00034 #define IMG_ZOOM    ":/images/16x16/zoom.png"
00035 
00036 #define CLOSED_CIRCUIT_REMOVE_DELAY     3000
00037 #define FAILED_CIRCUIT_REMOVE_DELAY     5000
00038 #define CLOSED_STREAM_REMOVE_DELAY      3000
00039 #define FAILED_STREAM_REMOVE_DELAY      4000
00040 
00041 
00042 /** Default constructor. */
00043 CircuitListWidget::CircuitListWidget(QWidget *parent)
00044 : QTreeWidget(parent)
00045 {
00046   /* Create and initialize columns */
00047   setHeaderLabels(QStringList() << tr("Connection") << tr("Status"));
00048 
00049   /* Find out when a circuit has been selected */
00050   connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
00051           this, SLOT(onSelectionChanged(QTreeWidgetItem*,QTreeWidgetItem*)));
00052 
00053   /* Set up the circuit item context menu */
00054   _circuitContextMenu = new QMenu(this);
00055   _zoomCircuitAct = new QAction(QIcon(IMG_ZOOM), tr("Zoom to Circuit"), this);
00056   _closeCircuitAct = new QAction(QIcon(IMG_CLOSE), tr("Close Circuit"), this);
00057   _circuitContextMenu->addAction(_zoomCircuitAct);
00058   _circuitContextMenu->addSeparator();
00059   _circuitContextMenu->addAction(_closeCircuitAct);
00060   /* Set up the stream item context menu */
00061   _streamContextMenu = new QMenu(this);
00062   _closeStreamAct = new QAction(QIcon(IMG_CLOSE), tr("Close Stream"), this);
00063   _streamContextMenu->addAction(_closeStreamAct);
00064 }
00065 
00066 /** Called when the user presses and releases a mouse button. If the event
00067  * indicates a right-click and a circuit or stream is selected, an appropriate
00068  * context menu will be displayed. */
00069 void
00070 CircuitListWidget::mouseReleaseEvent(QMouseEvent *e)
00071 {
00072   if (e->button() == Qt::RightButton) {
00073     /* Find out which item was right-clicked */
00074     QTreeWidgetItem *item = itemAt(e->pos());
00075     if (!item) {
00076       return;
00077     }
00078     
00079     QPoint pos = e->globalPos();
00080     if (!item->parent()) {
00081       /* Circuit was right-clicked */
00082       Circuit circ   = ((CircuitItem *)item)->circuit();
00083       quint64 circid = circ.id();
00084       _zoomCircuitAct->setEnabled((circ.status() == Circuit::Built));
00085       
00086       QAction* action = _circuitContextMenu->exec(pos);
00087       if (action == _closeCircuitAct) {
00088         emit closeCircuit(circid);
00089       } else if (action == _zoomCircuitAct) {
00090         emit zoomToCircuit(circid);
00091       }
00092     } else {
00093       /* Stream was right-clicked */
00094       quint64 streamid = ((StreamItem *)item)->id();
00095       QAction* action = _streamContextMenu->exec(pos);
00096       if (action == _closeStreamAct) {
00097         emit closeStream(streamid);
00098       }
00099     }
00100   }
00101 }
00102 
00103 /** Adds a circuit to the list. If the circuit already exists in the list, the
00104  * status and path will be updated. <b>displayedPath</b> contains a
00105  * description of the circuit's path suitable for humans to read. */
00106 void
00107 CircuitListWidget::addCircuit(Circuit circuit, QString displayedPath)
00108 {
00109   /* Check to see if the circuit already exists in the tree */
00110   CircuitItem *item = findCircuitItem(circuit.id());
00111   
00112   if (!item) {
00113     /* Add the new circuit */
00114     item = new CircuitItem(circuit, displayedPath);
00115     addTopLevelItem(item);
00116   } else {
00117     /* Circuit already exists, so update its status and path */
00118     item->update(circuit, displayedPath);
00119   }
00120 
00121   /* If the circuit is closed or dead, schedule it for removal */
00122   Circuit::Status status = circuit.status();
00123   if (status == Circuit::Closed) {
00124     scheduleCircuitRemoval(item, CLOSED_CIRCUIT_REMOVE_DELAY);
00125   } else if (status == Circuit::Failed) {
00126     scheduleCircuitRemoval(item, FAILED_CIRCUIT_REMOVE_DELAY);
00127   }
00128 }
00129 
00130 /** Adds a stream to the list. If the stream already exists in the list, the
00131  * status and path will be updated. */
00132 void
00133 CircuitListWidget::addStream(Stream stream)
00134 {
00135   /* Check to see if the stream already exists in the tree */
00136   StreamItem *item = findStreamItem(stream.id());
00137 
00138   if (!item) {
00139     CircuitItem *circuit = findCircuitItem(stream.circuitId());
00140     /* New stream, so try to find its circuit and add it */
00141     if (circuit) {
00142       circuit->addStream(new StreamItem(stream));
00143       expandItem(circuit);
00144     }
00145   } else {
00146     /* Stream already exists, so just update its status */
00147     item->update(stream);
00148 
00149     /* If the stream is closed or dead, schedule it for removal */
00150     Stream::Status status = stream.status();
00151     if (status == Stream::Closed) {
00152       scheduleStreamRemoval(item, CLOSED_STREAM_REMOVE_DELAY);
00153     } else if (status == Stream::Failed) {
00154       scheduleStreamRemoval(item, FAILED_STREAM_REMOVE_DELAY);
00155     }
00156   }
00157 }
00158 
00159 /** Schedules the given circuit to be removed after the specified timeout. */
00160 void
00161 CircuitListWidget::scheduleCircuitRemoval(CircuitItem *circuit, int delay)
00162 {
00163   if (!_circuitRemovalList.contains(circuit)) {
00164     _circuitRemovalList << circuit;
00165     QTimer::singleShot(delay, this, SLOT(removeCircuit()));
00166   } 
00167 }
00168 
00169 /** Schedules the given stream to be removed after the specified timeout. */
00170 void
00171 CircuitListWidget::scheduleStreamRemoval(StreamItem *stream, int delay)
00172 {
00173   if (!_streamRemovalList.contains(stream)) {
00174     _streamRemovalList << stream;
00175     QTimer::singleShot(delay, this, SLOT(removeStream()));
00176   } 
00177 }
00178 
00179 /** Removes the first circuit scheduled to be removed. */
00180 void
00181 CircuitListWidget::removeCircuit()
00182 {
00183   if (!_circuitRemovalList.isEmpty()) {
00184     CircuitItem *circuitItem = _circuitRemovalList.takeFirst();
00185     Circuit circuit = circuitItem->circuit();
00186     removeCircuit(circuitItem);
00187     emit circuitRemoved(circuit.id());
00188   }
00189 }
00190 
00191 /** Removes the given circuit item and all streams on that circuit. */
00192 void
00193 CircuitListWidget::removeCircuit(CircuitItem *circuit)
00194 {
00195   if (circuit) {
00196     /* Remove all streams (if any) on this circuit. */
00197     QList<StreamItem *> streams = circuit->streams();
00198     foreach (StreamItem *stream, streams) {
00199       /* Check if this stream was scheduled for removal already */
00200       if (_streamRemovalList.contains(stream)) {
00201         /* If this stream was already scheduled for removal, replace its pointer
00202          * with 0, so it doesn't get removed twice. */
00203         int index = _streamRemovalList.indexOf(stream);
00204         _streamRemovalList.replace(index, (StreamItem *)0);
00205       }
00206       
00207       /* Remove the stream item from the circuit */
00208       circuit->removeStream(stream);
00209     }
00210     /* Remove the circuit item itself */
00211     delete takeTopLevelItem(indexOfTopLevelItem(circuit));
00212   }
00213 }
00214 
00215 /** Removes the first stream scheduled to be removed. */
00216 void
00217 CircuitListWidget::removeStream()
00218 {
00219   if (!_streamRemovalList.isEmpty()) {
00220     StreamItem *stream = _streamRemovalList.takeFirst();
00221     removeStream(stream);
00222   }
00223 }
00224 
00225 /** Removes the given stream item. */
00226 void
00227 CircuitListWidget::removeStream(StreamItem *stream)
00228 {
00229   if (stream) {
00230     /* Try to get the stream's parent (a circuit item) */ 
00231     CircuitItem *circuit = (CircuitItem *)stream->parent();
00232     if (circuit) {
00233       /* Remove the stream from the circuit and delete the item */
00234       circuit->removeStream(stream);
00235     } else {
00236       /* It isn't on a circuit, so just delete the stream */
00237       delete stream;
00238     }
00239   }
00240 }
00241 
00242 /** Clears all circuits and streams from the list. */
00243 void
00244 CircuitListWidget::clearCircuits()
00245 {
00246   QTreeWidget::clear();
00247   _circuitRemovalList.clear();
00248   _streamRemovalList.clear();
00249 }
00250 
00251 /** Finds the circuit with the given ID and returns a pointer to that
00252  * circuit's item in the list. */
00253 CircuitItem*
00254 CircuitListWidget::findCircuitItem(quint64 circid)
00255 {
00256   int numCircs = topLevelItemCount();
00257   for (int i = 0; i < numCircs; i++) {
00258     CircuitItem *circuit = (CircuitItem *)topLevelItem(i);
00259     if (circid == circuit->id()) {
00260       return circuit;
00261     }
00262   }
00263   return 0;
00264 }
00265 
00266 /** Finds the stream with the given ID and returns a pointer to that stream's
00267  * item in the list. */
00268 StreamItem*
00269 CircuitListWidget::findStreamItem(quint64 streamid)
00270 {
00271   int numCircs = topLevelItemCount();
00272   int numStreams;
00273   
00274   for (int i = 0; i < numCircs; i++) {
00275     CircuitItem *circuit = (CircuitItem *)topLevelItem(i);
00276     numStreams = circuit->childCount();
00277   
00278     for (int j = 0; j < numStreams; j++) {
00279       StreamItem *stream = (StreamItem *)circuit->child(j);
00280       if (streamid == stream->id()) {
00281         return stream;
00282       }
00283     }
00284   }
00285   return 0;
00286 }
00287 
00288 /** Called when the current item selection has changed. */
00289 void
00290 CircuitListWidget::onSelectionChanged(QTreeWidgetItem *cur, 
00291                                       QTreeWidgetItem *prev)
00292 {
00293   Q_UNUSED(prev);
00294 
00295   if (cur) {
00296     Circuit circuit;
00297     
00298     if (!cur->parent()) {
00299       /* User selected a CircuitItem, so just grab the Circuit */
00300       circuit = ((CircuitItem *)cur)->circuit();
00301     } else {
00302       /* User selected a StreamItem, so get its parent and then the Circuit */
00303       CircuitItem *circItem = (CircuitItem *)cur->parent();
00304       circuit = circItem->circuit();
00305     }
00306 
00307     /* If this circuit has a path, then emit it so we can highlight it */
00308     if (circuit.length() > 0) {
00309       emit circuitSelected(circuit);
00310     }
00311   }
00312 }
00313 
00314 /** Returns a list of circuits currently in the widget. */
00315 QList<Circuit>
00316 CircuitListWidget::circuits()
00317 {
00318   int numCircs = topLevelItemCount();
00319   QList<Circuit> circs;
00320   
00321   for (int i = 0; i < numCircs; i++) {
00322     CircuitItem *circ = (CircuitItem *)topLevelItem(i);
00323     circs << circ->circuit();
00324   }
00325   return circs;
00326 }
00327 

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