Vidalia 0.3.1
CircuitListWidget.cpp
Go to the documentation of this file.
1/*
2** This file is part of Vidalia, and is subject to the license terms in the
3** LICENSE file, found in the top level directory of this distribution. If you
4** did not receive the LICENSE file with this file, you may obtain it from the
5** Vidalia source package distributed by the Vidalia Project at
6** http://www.torproject.org/projects/vidalia.html. No part of Vidalia,
7** including this file, may be copied, modified, propagated, or distributed
8** except according to the terms described in the LICENSE file.
9*/
10
11/*
12** \file CircuitListWidget.cpp
13** \brief Collection of Tor circuits as CircuitItems
14*/
15
16#include "config.h"
17#include "CircuitListWidget.h"
18#include "Vidalia.h"
19
20#include <QPoint>
21#include <QTimer>
22
23#define IMG_CLOSE ":/images/22x22/edit-delete.png"
24#define IMG_ZOOM ":/images/22x22/page-zoom.png"
25
26#define CLOSED_CIRCUIT_REMOVE_DELAY 3000
27#define FAILED_CIRCUIT_REMOVE_DELAY 5000
28#define CLOSED_STREAM_REMOVE_DELAY 3000
29#define FAILED_STREAM_REMOVE_DELAY 4000
30
31
32/** Default constructor. */
34: QTreeWidget(parent)
35{
36 /* Create and initialize columns */
37 setHeaderLabels(QStringList() << tr("Connection") << tr("Status"));
38
39 /* Find out when a circuit has been selected */
40 connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
41 this, SLOT(onSelectionChanged(QTreeWidgetItem*,QTreeWidgetItem*)));
42 connect(this, SIGNAL(customContextMenuRequested(QPoint)),
43 this, SLOT(customContextMenuRequested(QPoint)));
44
45 /* Respond to the Delete key by closing whatever circuits or streams are
46 * selected. */
47 vApp->createShortcut(QKeySequence::Delete, this, this,
49}
50
51/** Called when the user changes the UI translation. */
52void
54{
55 setHeaderLabels(QStringList() << tr("Connection") << tr("Status"));
56 for (int i = 0; i < topLevelItemCount(); i++) {
57 CircuitItem *circuitItem = dynamic_cast<CircuitItem *>(topLevelItem(i));
58 circuitItem->update(circuitItem->circuit());
59
60 foreach (StreamItem *streamItem, circuitItem->streams()) {
61 streamItem->update(streamItem->stream());
62 }
63 }
64}
65
66/** Called when the user requests a context menu on a circuit or stream in the
67 * list and displays a context menu appropriate for whichever type of item is
68 * currently selected. */
69void
71{
72 QMenu menu(this);
73
74 /* Find out which item was right-clicked */
75 QTreeWidgetItem *item = itemAt(pos);
76 if (!item)
77 return;
78
79 if (!item->parent()) {
80 /* A circuit was selected */
81 CircuitItem *circuitItem = dynamic_cast<CircuitItem *>(item);
82 if (!circuitItem)
83 return;
84
85 /* Set up the circuit context menu */
86 QAction *zoomAct = new QAction(QIcon(IMG_ZOOM),
87 tr("Zoom to Circuit"), this);
88 QAction *closeAct = new QAction(QIcon(IMG_CLOSE),
89 tr("Close Circuit (Del)"), this);
90#if defined(USE_MARBLE)
91 zoomAct->setEnabled(circuitItem->circuit().status() == Circuit::Built);
92 menu.addAction(zoomAct);
93 menu.addSeparator();
94#endif
95 menu.addAction(closeAct);
96
97 /* Display the context menu and find out which (if any) action was
98 * selected */
99 QAction* action = menu.exec(mapToGlobal(pos));
100 if (action == closeAct)
101 emit closeCircuit(circuitItem->id());
102 else if (action == zoomAct)
103 emit zoomToCircuit(circuitItem->id());
104 } else {
105 /* A stream was selected */
106 StreamItem *streamItem = dynamic_cast<StreamItem *>(item);
107 if (!streamItem)
108 return;
109
110 /* Set up the stream context menu */
111 QAction *closeAct = new QAction(QIcon(IMG_CLOSE),
112 tr("Close Stream (Del)"), this);
113 menu.addAction(closeAct);
114
115 /* Display the context menu and find out which (if any) action was
116 * selected */
117 QAction* action = menu.exec(mapToGlobal(pos));
118 if (action == closeAct)
119 emit closeStream(streamItem->id());
120 }
121}
122
123/** Closes all selected circuits or streams. */
124void
126{
127 QList<QTreeWidgetItem *> items = selectedItems();
128 foreach (QTreeWidgetItem *item, items) {
129 if (!item->parent()) {
130 CircuitItem *circuitItem = dynamic_cast<CircuitItem *>(item);
131 if (circuitItem)
132 emit closeCircuit(circuitItem->id());
133 } else {
134 StreamItem *streamItem = dynamic_cast<StreamItem *>(item);
135 if (streamItem)
136 emit closeStream(streamItem->id());
137 }
138 }
139}
140
141/** Adds a <b>circuit</b> to the list. If the circuit already exists in the
142 * list, the status and path will be updated. */
143void
145{
146 /* Check to see if the circuit already exists in the tree */
147 CircuitItem *item = findCircuitItem(circuit.id());
148
149 if (!item) {
150 /* Add the new circuit */
151 item = new CircuitItem(circuit);
152 addTopLevelItem(item);
153 } else {
154 /* Circuit already exists, so update its status and path */
155 item->update(circuit);
156 }
157
158 /* If the circuit is closed or dead, schedule it for removal */
159 Circuit::Status status = circuit.status();
160 if (status == Circuit::Closed) {
162 } else if (status == Circuit::Failed) {
164 }
165}
166
167/** Adds a stream to the list. If the stream already exists in the list, the
168 * status and path will be updated. */
169void
171{
172 /* Check to see if the stream already exists in the tree */
173 StreamItem *item = findStreamItem(stream.id());
174
175 if (!item) {
176 CircuitItem *circuit = findCircuitItem(stream.circuitId());
177 /* New stream, so try to find its circuit and add it */
178 if (circuit) {
179 circuit->addStream(new StreamItem(stream));
180 expandItem(circuit);
181 }
182 } else {
183 /* Stream already exists, so just update its status */
184 item->update(stream);
185
186 /* If the stream is closed or dead, schedule it for removal */
187 Stream::Status status = stream.status();
188 if (status == Stream::Closed) {
190 } else if (status == Stream::Failed) {
192 }
193 }
194}
195
196/** Schedules the given circuit to be removed after the specified timeout. */
197void
199{
200 if (!_circuitRemovalList.contains(circuit)) {
201 _circuitRemovalList << circuit;
202 QTimer::singleShot(delay, this, SLOT(removeCircuit()));
203 }
204}
205
206/** Schedules the given stream to be removed after the specified timeout. */
207void
209{
210 if (!_streamRemovalList.contains(stream)) {
211 _streamRemovalList << stream;
212 QTimer::singleShot(delay, this, SLOT(removeStream()));
213 }
214}
215
216/** Removes the first circuit scheduled to be removed. */
217void
219{
220 if (!_circuitRemovalList.isEmpty()) {
221 CircuitItem *circuitItem = _circuitRemovalList.takeFirst();
222 Circuit circuit = circuitItem->circuit();
223 removeCircuit(circuitItem);
224 emit circuitRemoved(circuit.id());
225 }
226}
227
228/** Removes the given circuit item and all streams on that circuit. */
229void
231{
232 if (circuit) {
233 /* Remove all streams (if any) on this circuit. */
234 QList<StreamItem *> streams = circuit->streams();
235 foreach (StreamItem *stream, streams) {
236 /* Check if this stream was scheduled for removal already */
237 if (_streamRemovalList.contains(stream)) {
238 /* If this stream was already scheduled for removal, replace its pointer
239 * with 0, so it doesn't get removed twice. */
240 int index = _streamRemovalList.indexOf(stream);
241 _streamRemovalList.replace(index, (StreamItem *)0);
242 }
243
244 /* Remove the stream item from the circuit */
245 circuit->removeStream(stream);
246 }
247 /* Remove the circuit item itself */
248 delete takeTopLevelItem(indexOfTopLevelItem(circuit));
249 }
250}
251
252/** Removes the first stream scheduled to be removed. */
253void
255{
256 if (!_streamRemovalList.isEmpty()) {
257 StreamItem *stream = _streamRemovalList.takeFirst();
258 removeStream(stream);
259 }
260}
261
262/** Removes the given stream item. */
263void
265{
266 if (stream) {
267 /* Try to get the stream's parent (a circuit item) */
268 CircuitItem *circuit = (CircuitItem *)stream->parent();
269 if (circuit) {
270 /* Remove the stream from the circuit and delete the item */
271 circuit->removeStream(stream);
272 } else {
273 /* It isn't on a circuit, so just delete the stream */
274 delete stream;
275 }
276 }
277}
278
279/** Clears all circuits and streams from the list. */
280void
282{
283 QTreeWidget::clear();
284 _circuitRemovalList.clear();
285 _streamRemovalList.clear();
286}
287
288/** Finds the circuit with the given ID and returns a pointer to that
289 * circuit's item in the list. */
292{
293 int numCircs = topLevelItemCount();
294 for (int i = 0; i < numCircs; i++) {
295 CircuitItem *circuit = (CircuitItem *)topLevelItem(i);
296 if (circid == circuit->id()) {
297 return circuit;
298 }
299 }
300 return 0;
301}
302
303/** Finds the stream with the given ID and returns a pointer to that stream's
304 * item in the list. */
307{
308 int numCircs = topLevelItemCount();
309 int numStreams;
310
311 for (int i = 0; i < numCircs; i++) {
312 CircuitItem *circuit = (CircuitItem *)topLevelItem(i);
313 numStreams = circuit->childCount();
314
315 for (int j = 0; j < numStreams; j++) {
316 StreamItem *stream = (StreamItem *)circuit->child(j);
317 if (streamid == stream->id()) {
318 return stream;
319 }
320 }
321 }
322 return 0;
323}
324
325/** Called when the current item selection has changed. */
326void
328 QTreeWidgetItem *prev)
329{
330 Q_UNUSED(prev);
331
332 if (cur) {
333 Circuit circuit;
334
335 if (!cur->parent()) {
336 /* User selected a CircuitItem, so just grab the Circuit */
337 circuit = ((CircuitItem *)cur)->circuit();
338 } else {
339 /* User selected a StreamItem, so get its parent and then the Circuit */
340 CircuitItem *circItem = (CircuitItem *)cur->parent();
341 circuit = circItem->circuit();
342 }
343
344 /* If this circuit has a path, then emit it so we can highlight it */
345 emit circuitSelected(circuit);
346 }
347}
348
349/** Returns a list of circuits currently in the widget. */
352{
353 int numCircs = topLevelItemCount();
354 CircuitList circs;
355
356 for (int i = 0; i < numCircs; i++) {
357 CircuitItem *circ = (CircuitItem *)topLevelItem(i);
358 circs << circ->circuit();
359 }
360 return circs;
361}
362
QList< Circuit > CircuitList
Definition: Circuit.h:81
QString CircuitId
Definition: Circuit.h:24
#define FAILED_CIRCUIT_REMOVE_DELAY
#define IMG_CLOSE
#define FAILED_STREAM_REMOVE_DELAY
#define CLOSED_STREAM_REMOVE_DELAY
#define IMG_ZOOM
#define CLOSED_CIRCUIT_REMOVE_DELAY
QString StreamId
Definition: Stream.h:28
stop errmsg connect(const QHostAddress &address, quint16 port)
#define vApp
Definition: Vidalia.h:37
CircuitId id() const
Definition: Circuit.h:51
Status
Definition: Circuit.h:33
@ Failed
Definition: Circuit.h:38
@ Closed
Definition: Circuit.h:39
@ Built
Definition: Circuit.h:36
Status status() const
Definition: Circuit.h:53
void addStream(StreamItem *stream)
Definition: CircuitItem.cpp:49
QList< StreamItem * > streams() const
Definition: CircuitItem.cpp:66
void removeStream(StreamItem *stream)
Definition: CircuitItem.cpp:56
CircuitId id() const
Definition: CircuitItem.h:43
Circuit circuit() const
Definition: CircuitItem.h:45
void update(const Circuit &circuit)
Definition: CircuitItem.cpp:29
QList< CircuitItem * > _circuitRemovalList
void closeStream(StreamId streamid)
CircuitItem * findCircuitItem(const CircuitId &circid)
QList< Circuit > circuits()
void scheduleCircuitRemoval(CircuitItem *circuit, int delay)
void closeCircuit(CircuitId circid)
StreamItem * findStreamItem(const StreamId &streamid)
void zoomToCircuit(CircuitId circid)
void scheduleStreamRemoval(StreamItem *stream, int delay)
CircuitListWidget(QWidget *parent=0)
void circuitSelected(Circuit circuit)
QList< StreamItem * > _streamRemovalList
void addCircuit(const Circuit &circuit)
void customContextMenuRequested(const QPoint &pos)
void onSelectionChanged(QTreeWidgetItem *cur, QTreeWidgetItem *prev)
void circuitRemoved(CircuitId circid)
void addStream(const Stream &stream)
Definition: Stream.h:32
StreamId id() const
Definition: Stream.h:68
CircuitId circuitId() const
Definition: Stream.h:74
Status status() const
Definition: Stream.h:70
Status
Definition: Stream.h:37
@ Failed
Definition: Stream.h:44
@ Closed
Definition: Stream.h:45
Stream stream() const
Definition: StreamItem.h:30
void update(const Stream &stream)
Definition: StreamItem.cpp:33
StreamId id() const
Definition: StreamItem.h:34
QString i(QString str)
Definition: html.cpp:32