1 /* interface_tree_model.cpp
2 * Model for the interface data for display in the interface frame
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "interface_tree_model.h"
28 #include "ui/capture.h"
29 #include "caputils/capture-pcap-util.h"
30 #include "capture_opts.h"
31 #include "ui/capture_ui_utils.h"
32 #include "ui/capture_globals.h"
35 #include "wsutil/filesystem.h"
37 #include "qt_ui_utils.h"
38 #include "stock_icon.h"
39 #include "wireshark_application.h"
41 /* Needed for the meta type declaration of QList<int>* */
42 #include "sparkline_delegate.h"
48 const QString InterfaceTreeModel::DefaultNumericValue = QObject::tr("default");
51 * This is the data model for interface trees. It implies, that the index within
52 * global_capture_opts.all_ifaces is identical to the row. This is always the case, even
53 * when interfaces are hidden by the proxy model. But for this to work, every access
54 * to the index from within the view, has to be filtered through the proxy model.
56 InterfaceTreeModel::InterfaceTreeModel(QObject *parent) :
57 QAbstractTableModel(parent)
62 connect(wsApp, SIGNAL(appInitialized()), this, SLOT(interfaceListChanged()));
63 connect(wsApp, SIGNAL(localInterfaceListChanged()), this, SLOT(interfaceListChanged()));
66 InterfaceTreeModel::~InterfaceTreeModel(void)
70 capture_stat_stop(stat_cache_);
73 #endif // HAVE_LIBPCAP
76 QString InterfaceTreeModel::interfaceError()
79 if ( rowCount() == 0 )
81 errorText = tr("No Interfaces found.");
84 else if ( global_capture_opts.ifaces_err != 0 )
86 errorText = tr(global_capture_opts.ifaces_err_info);
93 int InterfaceTreeModel::rowCount(const QModelIndex & ) const
96 return (global_capture_opts.all_ifaces ? global_capture_opts.all_ifaces->len : 0);
98 /* Currently no interfaces available for libpcap-less builds */
103 int InterfaceTreeModel::columnCount(const QModelIndex & ) const
105 /* IFTREE_COL_MAX is not being displayed, it is the definition for the maximum numbers of columns */
106 return ((int) IFTREE_COL_MAX);
109 QVariant InterfaceTreeModel::data(const QModelIndex &index, int role) const
112 bool interfacesLoaded = true;
113 if ( ! global_capture_opts.all_ifaces || global_capture_opts.all_ifaces->len == 0 )
114 interfacesLoaded = false;
116 if ( !index.isValid() )
119 int row = index.row();
120 InterfaceTreeColumns col = (InterfaceTreeColumns) index.column();
122 if ( interfacesLoaded )
124 interface_t device = g_array_index(global_capture_opts.all_ifaces, interface_t, row);
126 /* Data for display in cell */
127 if ( role == Qt::DisplayRole )
129 /* Only the name is being displayed */
130 if ( col == IFTREE_COL_NAME )
132 return QString(device.display_name);
134 else if ( col == IFTREE_COL_INTERFACE_NAME )
136 return QString(device.name);
138 else if ( col == IFTREE_COL_PIPE_PATH )
140 return QString(device.if_info.name);
142 else if ( col == IFTREE_COL_CAPTURE_FILTER )
144 if ( device.cfilter && strlen(device.cfilter) > 0 )
145 return html_escape(QString(device.cfilter));
148 else if ( col == IFTREE_COL_EXTCAP_PATH )
150 return QString(device.if_info.extcap);
153 else if ( col == IFTREE_COL_SNAPLEN )
155 return device.has_snaplen ? QString::number(device.snaplen) : DefaultNumericValue;
157 #ifdef CAN_SET_CAPTURE_BUFFER_SIZE
158 else if ( col == IFTREE_COL_BUFFERLEN )
160 return QString::number(device.buffer);
163 else if ( col == IFTREE_COL_TYPE )
165 return QVariant::fromValue((int)device.if_info.type);
167 else if ( col == IFTREE_COL_INTERFACE_COMMENT )
169 QString comment = gchar_free_to_qstring(capture_dev_user_descr_find(device.name));
170 if ( comment.length() > 0 )
173 return QString(device.if_info.vendor_description);
175 else if ( col == IFTREE_COL_DLT )
177 QString linkname = QObject::tr("DLT %1").arg(device.active_dlt);
178 for (GList *list = device.links; list != NULL; list = g_list_next(list)) {
179 link_row *linkr = (link_row*)(list->data);
180 if (linkr->dlt != -1 && linkr->dlt == device.active_dlt) {
181 linkname = linkr->name;
190 /* Return empty string for every other DisplayRole */
194 else if ( role == Qt::CheckStateRole )
196 if ( col == IFTREE_COL_HIDDEN )
198 /* Hidden is a de-selection, therefore inverted logic here */
199 return device.hidden ? Qt::Unchecked : Qt::Checked;
201 else if ( col == IFTREE_COL_PROMISCUOUSMODE )
203 return device.pmode ? Qt::Checked : Qt::Unchecked;
205 #ifdef HAVE_PCAP_CREATE
206 else if ( col == IFTREE_COL_MONITOR_MODE )
208 return device.monitor_mode_enabled ? Qt::Checked : Qt::Unchecked;
212 /* Used by SparkLineDelegate for loading the data for the statistics line */
213 else if ( role == Qt::UserRole )
215 if ( col == IFTREE_COL_STATS )
217 if ( points.contains(device.name) )
218 return qVariantFromValue(points[device.name]);
220 else if ( col == IFTREE_COL_HIDDEN )
222 return QVariant::fromValue((bool)device.hidden);
226 /* Displays the configuration icon for extcap interfaces */
227 else if ( role == Qt::DecorationRole )
229 if ( col == IFTREE_COL_EXTCAP )
231 if ( device.if_info.type == IF_EXTCAP )
232 return QIcon(StockIcon("x-capture-options"));
235 else if ( role == Qt::TextAlignmentRole )
237 if ( col == IFTREE_COL_EXTCAP )
239 return Qt::AlignRight;
243 /* Displays the tooltip for each row */
244 else if ( role == Qt::ToolTipRole )
246 return toolTipForInterface(row);
257 QVariant InterfaceTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
259 if ( orientation == Qt::Horizontal )
261 if ( role == Qt::DisplayRole )
263 if ( section == IFTREE_COL_HIDDEN )
267 else if ( section == IFTREE_COL_INTERFACE_NAME )
269 return tr("Friendly Name");
271 else if ( section == IFTREE_COL_NAME )
273 return tr("Interface Name");
275 else if ( section == IFTREE_COL_PIPE_PATH )
277 return tr("Local Pipe Path");
279 else if ( section == IFTREE_COL_INTERFACE_COMMENT )
281 return tr("Comment");
283 else if ( section == IFTREE_COL_DLT )
285 return tr("Link-Layer Header");
287 else if ( section == IFTREE_COL_PROMISCUOUSMODE )
289 return tr("Promiscuous");
291 else if ( section == IFTREE_COL_SNAPLEN )
293 return tr("Snaplen (B)");
295 #ifdef CAN_SET_CAPTURE_BUFFER_SIZE
296 else if ( section == IFTREE_COL_BUFFERLEN )
298 return tr("Buffer (MB)");
301 #ifdef HAVE_PCAP_CREATE
302 else if ( section == IFTREE_COL_MONITOR_MODE )
304 return tr("Monitor Mode");
307 else if ( section == IFTREE_COL_CAPTURE_FILTER )
309 return tr("Capture Filter");
317 QVariant InterfaceTreeModel::getColumnContent(int idx, int col, int role)
319 return InterfaceTreeModel::data(index(idx, col), role);
322 #ifdef HAVE_PCAP_REMOTE
323 bool InterfaceTreeModel::isRemote(int idx)
325 interface_t device = g_array_index(global_capture_opts.all_ifaces, interface_t, idx);
326 if ( device.remote_opts.src_type == CAPTURE_IFREMOTE )
333 * The interface list has changed. global_capture_opts.all_ifaces may have been reloaded
334 * or changed with current data. beginResetModel() and endResetModel() will signalize the
335 * proxy model and the view, that the data has changed and the view has to reload
337 void InterfaceTreeModel::interfaceListChanged()
339 emit beginResetModel();
343 emit endResetModel();
347 * Displays the tooltip code for the given device index.
349 QVariant InterfaceTreeModel::toolTipForInterface(int idx) const
352 if ( ! global_capture_opts.all_ifaces || global_capture_opts.all_ifaces->len <= (guint) idx)
355 interface_t device = g_array_index(global_capture_opts.all_ifaces, interface_t, idx);
357 QString tt_str = "<p>";
358 if ( device.no_addresses > 0 )
360 tt_str += QString("%1: %2")
361 .arg(device.no_addresses > 1 ? tr("Addresses") : tr("Address"))
362 .arg(html_escape(device.addresses))
363 .replace('\n', ", ");
366 else if ( device.if_info.type == IF_EXTCAP )
368 tt_str = QString(tr("Extcap interface: %1")).arg(get_basename(device.if_info.extcap));
373 tt_str = tr("No addresses");
377 QString cfilter = device.cfilter;
378 if ( cfilter.isEmpty() )
380 tt_str += tr("No capture filter");
384 tt_str += QString("%1: %2")
385 .arg(tr("Capture filter"))
386 .arg(html_escape(cfilter));
399 void InterfaceTreeModel::stopStatistic()
403 capture_stat_stop(stat_cache_);
409 void InterfaceTreeModel::updateStatistic(unsigned int idx)
413 if ( ! global_capture_opts.all_ifaces || global_capture_opts.all_ifaces->len <= (guint) idx )
416 interface_t device = g_array_index(global_capture_opts.all_ifaces, interface_t, idx);
418 if ( device.if_info.type == IF_PIPE )
423 // Start gathering statistics using dumpcap
424 // We crash (on OS X at least) if we try to do this from ::showEvent.
425 stat_cache_ = capture_stat_start(&global_capture_opts);
430 struct pcap_stat stats;
433 if ( capture_stats(stat_cache_, device.name, &stats) )
435 if ( (int)(stats.ps_recv - device.last_packets) >= 0 )
437 diff = stats.ps_recv - device.last_packets;
438 device.packet_diff = diff;
440 device.last_packets = stats.ps_recv;
442 global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, idx);
443 g_array_insert_val(global_capture_opts.all_ifaces, idx, device);
446 points[device.name].append(diff);
447 emit dataChanged(index(idx, IFTREE_COL_STATS), index(idx, IFTREE_COL_STATS));
453 void InterfaceTreeModel::getPoints(int idx, PointList *pts)
456 if ( ! global_capture_opts.all_ifaces || global_capture_opts.all_ifaces->len <= (guint) idx )
459 interface_t device = g_array_index(global_capture_opts.all_ifaces, interface_t, idx);
460 if ( points.contains(device.name) )
461 pts->append(points[device.name]);
468 QItemSelection InterfaceTreeModel::selectedDevices()
470 QItemSelection mySelection;
472 for( int idx = 0; idx < rowCount(); idx++ )
474 interface_t device = g_array_index(global_capture_opts.all_ifaces, interface_t, idx);
476 if ( device.selected )
478 QModelIndex selectIndex = index(idx, 0);
480 QItemSelection( selectIndex, index(selectIndex.row(), columnCount() - 1) ),
481 QItemSelectionModel::SelectCurrent
489 bool InterfaceTreeModel::updateSelectedDevices(QItemSelection sourceSelection)
491 bool selectionHasChanged = false;
493 QList<int> selectedIndices;
495 QItemSelection::const_iterator it = sourceSelection.constBegin();
496 while(it != sourceSelection.constEnd())
498 QModelIndexList indeces = ((QItemSelectionRange) (*it)).indexes();
500 QModelIndexList::const_iterator cit = indeces.constBegin();
501 while(cit != indeces.constEnd())
503 QModelIndex index = (QModelIndex) (*cit);
504 if ( ! selectedIndices.contains(index.row()) )
506 selectedIndices.append(index.row());
513 global_capture_opts.num_selected = 0;
515 for ( unsigned int idx = 0; idx < global_capture_opts.all_ifaces->len; idx++ )
517 interface_t device = g_array_index(global_capture_opts.all_ifaces, interface_t, idx);
518 if ( !device.locked )
520 if ( selectedIndices.contains(idx) )
522 if (! device.selected )
523 selectionHasChanged = true;
524 device.selected = TRUE;
525 global_capture_opts.num_selected++;
527 if ( device.selected )
528 selectionHasChanged = true;
529 device.selected = FALSE;
531 device.locked = TRUE;
532 global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, idx);
533 g_array_insert_val(global_capture_opts.all_ifaces, idx, device);
535 device.locked = FALSE;
536 global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, idx);
537 g_array_insert_val(global_capture_opts.all_ifaces, idx, device);
541 Q_UNUSED(sourceSelection);
543 return selectionHasChanged;
553 * indent-tabs-mode: nil
556 * ex: set shiftwidth=4 tabstop=8 expandtab:
557 * :indentSize=4:tabSize=8:noTabs=true: