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 1262 2006-10-03 07:16:16Z edmanm $
00025  * \brief Collection of Tor circuits as CircuitItems
00026  */
00027 
00028 #include <QTimer>
00029 
00030 #include "circuitlistwidget.h"
00031 
00032 #define CLOSED_CIRCUIT_REMOVE_DELAY     3000
00033 #define FAILED_CIRCUIT_REMOVE_DELAY     5000
00034 #define CLOSED_STREAM_REMOVE_DELAY      3000
00035 #define FAILED_STREAM_REMOVE_DELAY      4000
00036 
00037 
00038 /** Default constructor. */
00039 CircuitListWidget::CircuitListWidget(QWidget *parent)
00040 : QTreeWidget(parent)
00041 {
00042   /* Create and initialize columns */
00043   setHeaderLabels(QStringList() << tr("Connection") << tr("Status"));
00044 
00045   /* Find out when a circuit has been selected */
00046   connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
00047           this, SLOT(onSelectionChanged(QTreeWidgetItem*,QTreeWidgetItem*)));
00048 }
00049 
00050 /** Adds a circuit to the list. If the circuit already exists in the list, the
00051  * status and path will be updated. */
00052 void
00053 CircuitListWidget::addCircuit(Circuit circuit)
00054 {
00055   /* Check to see if the circuit already exists in the tree */
00056   CircuitItem *item = findCircuitItem(circuit.id());
00057   
00058   if (!item) {
00059     /* Add the new circuit */
00060     item = new CircuitItem(circuit);
00061     addTopLevelItem(item);
00062   } else {
00063     /* Circuit already exists, so update its status and path */
00064     item->update(circuit);
00065   }
00066 
00067   /* If the circuit is closed or dead, schedule it for removal */
00068   Circuit::Status status = circuit.status();
00069   if (status == Circuit::Closed) {
00070     scheduleCircuitRemoval(item, CLOSED_CIRCUIT_REMOVE_DELAY);
00071   } else if (status == Circuit::Failed) {
00072     scheduleCircuitRemoval(item, FAILED_CIRCUIT_REMOVE_DELAY);
00073   }
00074 }
00075 
00076 /** Adds a stream to the list. If the stream already exists in the list, the
00077  * status and path will be updated. */
00078 void
00079 CircuitListWidget::addStream(Stream stream)
00080 {
00081   /* Check to see if the stream already exists in the tree */
00082   StreamItem *item = findStreamItem(stream.id());
00083 
00084   if (!item) {
00085     CircuitItem *circuit = findCircuitItem(stream.circuitId());
00086     /* New stream, so try to find its circuit and add it */
00087     if (circuit) {
00088       circuit->addStream(new StreamItem(stream));
00089       expandItem(circuit);
00090     }
00091   } else {
00092     /* Stream already exists, so just update its status */
00093     item->update(stream);
00094 
00095     /* If the stream is closed or dead, schedule it for removal */
00096     Stream::Status status = stream.status();
00097     if (status == Stream::Closed) {
00098       scheduleStreamRemoval(item, CLOSED_STREAM_REMOVE_DELAY);
00099     } else if (status == Stream::Failed) {
00100       scheduleStreamRemoval(item, FAILED_STREAM_REMOVE_DELAY);
00101     }
00102   }
00103 }
00104 
00105 /** Schedules the given circuit to be removed after the specified timeout. */
00106 void
00107 CircuitListWidget::scheduleCircuitRemoval(CircuitItem *circuit, int delay)
00108 {
00109   if (!_circuitRemovalList.contains(circuit)) {
00110     _circuitRemovalList << circuit;
00111     QTimer::singleShot(delay, this, SLOT(removeCircuit()));
00112   } 
00113 }
00114 
00115 /** Schedules the given stream to be removed after the specified timeout. */
00116 void
00117 CircuitListWidget::scheduleStreamRemoval(StreamItem *stream, int delay)
00118 {
00119   if (!_streamRemovalList.contains(stream)) {
00120     _streamRemovalList << stream;
00121     QTimer::singleShot(delay, this, SLOT(removeStream()));
00122   } 
00123 }
00124 
00125 /** Removes the first circuit scheduled to be removed. */
00126 void
00127 CircuitListWidget::removeCircuit()
00128 {
00129   if (!_circuitRemovalList.isEmpty()) {
00130     CircuitItem *circuitItem = _circuitRemovalList.takeFirst();
00131     Circuit circuit = circuitItem->circuit();
00132     removeCircuit(circuitItem);
00133     emit circuitRemoved(circuit.id());
00134   }
00135 }
00136 
00137 /** Removes the given circuit item and all streams on that circuit. */
00138 void
00139 CircuitListWidget::removeCircuit(CircuitItem *circuit)
00140 {
00141   if (circuit) {
00142     /* Remove all streams (if any) on this circuit. */
00143     QList<StreamItem *> streams = circuit->streams();
00144     foreach (StreamItem *stream, streams) {
00145       /* Check if this stream was scheduled for removal already */
00146       if (_streamRemovalList.contains(stream)) {
00147         /* If this stream was already scheduled for removal, replace its pointer
00148          * with 0, so it doesn't get removed twice. */
00149         int index = _streamRemovalList.indexOf(stream);
00150         _streamRemovalList.replace(index, (StreamItem *)0);
00151       }
00152       
00153       /* Remove the stream item from the circuit */
00154       circuit->removeStream(stream);
00155     }
00156     /* Remove the circuit item itself */
00157     delete takeTopLevelItem(indexOfTopLevelItem(circuit));
00158   }
00159 }
00160 
00161 /** Removes the first stream scheduled to be removed. */
00162 void
00163 CircuitListWidget::removeStream()
00164 {
00165   if (!_streamRemovalList.isEmpty()) {
00166     StreamItem *stream = _streamRemovalList.takeFirst();
00167     removeStream(stream);
00168   }
00169 }
00170 
00171 /** Removes the given stream item. */
00172 void
00173 CircuitListWidget::removeStream(StreamItem *stream)
00174 {
00175   if (stream) {
00176     /* Try to get the stream's parent (a circuit item) */ 
00177     CircuitItem *circuit = (CircuitItem *)stream->parent();
00178     if (circuit) {
00179       /* Remove the stream from the circuit and delete the item */
00180       circuit->removeStream(stream);
00181     } else {
00182       /* It isn't on a circuit, so just delete the stream */
00183       delete stream;
00184     }
00185   }
00186 }
00187 
00188 /** Clears all circuits and streams from the list. */
00189 void
00190 CircuitListWidget::clearCircuits()
00191 {
00192   QTreeWidget::clear();
00193   _circuitRemovalList.clear();
00194   _streamRemovalList.clear();
00195 }
00196 
00197 /** Finds the circuit with the given ID and returns a pointer to that
00198  * circuit's item in the list. */
00199 CircuitItem*
00200 CircuitListWidget::findCircuitItem(quint64 circid)
00201 {
00202   int numCircs = topLevelItemCount();
00203   for (int i = 0; i < numCircs; i++) {
00204     CircuitItem *circuit = (CircuitItem *)topLevelItem(i);
00205     if (circid == circuit->id()) {
00206       return circuit;
00207     }
00208   }
00209   return 0;
00210 }
00211 
00212 /** Finds the stream with the given ID and returns a pointer to that stream's
00213  * item in the list. */
00214 StreamItem*
00215 CircuitListWidget::findStreamItem(quint64 streamid)
00216 {
00217   int numCircs = topLevelItemCount();
00218   int numStreams;
00219   
00220   for (int i = 0; i < numCircs; i++) {
00221     CircuitItem *circuit = (CircuitItem *)topLevelItem(i);
00222     numStreams = circuit->childCount();
00223   
00224     for (int j = 0; j < numStreams; j++) {
00225       StreamItem *stream = (StreamItem *)circuit->child(j);
00226       if (streamid == stream->id()) {
00227         return stream;
00228       }
00229     }
00230   }
00231   return 0;
00232 }
00233 
00234 /** Called when the current item selection has changed. */
00235 void
00236 CircuitListWidget::onSelectionChanged(QTreeWidgetItem *cur, 
00237                                       QTreeWidgetItem *prev)
00238 {
00239   Q_UNUSED(prev);
00240 
00241   if (cur) {
00242     Circuit circuit;
00243     
00244     if (!cur->parent()) {
00245       /* User selected a CircuitItem, so just grab the Circuit */
00246       circuit = ((CircuitItem *)cur)->circuit();
00247     } else {
00248       /* User selected a StreamItem, so get its parent and then the Circuit */
00249       CircuitItem *circItem = (CircuitItem *)cur->parent();
00250       circuit = circItem->circuit();
00251     }
00252 
00253     /* If this circuit has a path, then emit it so we can highlight it */
00254     if (circuit.length() > 0) {
00255       emit circuitSelected(circuit);
00256     }
00257   }
00258 }
00259 
00260 /** Returns a list of circuits currently in the widget. */
00261 QList<Circuit>
00262 CircuitListWidget::circuits()
00263 {
00264   int numCircs = topLevelItemCount();
00265   QList<Circuit> circs;
00266   
00267   for (int i = 0; i < numCircs; i++) {
00268     CircuitItem *circ = (CircuitItem *)topLevelItem(i);
00269     circs << circ->circuit();
00270   }
00271   return circs;
00272 }
00273 

Generated on Mon Oct 23 20:08:15 2006 for Vidalia by  doxygen 1.5.0