update epan/dissectors/pidl/drsuapi/drsuapi.idl from samba
[wireshark-sm.git] / ui / qt / models / interface_tree_model.cpp
blobafba48cd89b8907a6d73ccc38ef735e5a038323e
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 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
11 #include "config.h"
13 #include <ui/qt/models/interface_tree_model.h>
15 #ifdef HAVE_LIBPCAP
16 #include "ui/capture.h"
17 #include "capture/capture-pcap-util.h"
18 #include "capture_opts.h"
19 #include "ui/capture_ui_utils.h"
20 #include "ui/capture_globals.h"
21 #endif
23 #include "wsutil/filesystem.h"
25 #include <ui/qt/utils/qt_ui_utils.h>
26 #include <ui/qt/utils/stock_icon.h>
27 #include "main_application.h"
29 /* Needed for the meta type declaration of QList<int>* */
30 #include <ui/qt/models/sparkline_delegate.h>
32 #include "extcap.h"
34 const QString InterfaceTreeModel::DefaultNumericValue = QObject::tr("default");
36 /**
37 * This is the data model for interface trees. It implies, that the index within
38 * global_capture_opts.all_ifaces is identical to the row. This is always the case, even
39 * when interfaces are hidden by the proxy model. But for this to work, every access
40 * to the index from within the view, has to be filtered through the proxy model.
42 InterfaceTreeModel::InterfaceTreeModel(QObject *parent) :
43 QAbstractTableModel(parent)
44 #ifdef HAVE_LIBPCAP
45 ,stat_cache_(NULL)
46 #endif
48 connect(mainApp, &MainApplication::appInitialized, this, &InterfaceTreeModel::interfaceListChanged);
49 connect(mainApp, &MainApplication::localInterfaceListChanged, this, &InterfaceTreeModel::interfaceListChanged);
52 InterfaceTreeModel::~InterfaceTreeModel(void)
54 #ifdef HAVE_LIBPCAP
55 if (stat_cache_) {
56 capture_stat_stop(stat_cache_);
57 stat_cache_ = NULL;
59 #endif // HAVE_LIBPCAP
62 QString InterfaceTreeModel::interfaceError()
64 #ifdef HAVE_LIBPCAP
66 // First, see if there was an error fetching the interfaces.
67 // If so, report it.
69 if (global_capture_opts.ifaces_err != 0)
71 return tr(global_capture_opts.ifaces_err_info);
75 // Otherwise, if there are no rows, there were no interfaces
76 // found.
78 if (rowCount() == 0)
80 return tr("No interfaces found.");
84 // No error. Return an empty string.
86 return "";
87 #else
89 // We were built without pcap support, so we have no notion of
90 // local interfaces.
92 return tr("This version of Wireshark was built without packet capture support.");
93 #endif
96 int InterfaceTreeModel::rowCount(const QModelIndex &) const
98 #ifdef HAVE_LIBPCAP
99 return (global_capture_opts.all_ifaces ? global_capture_opts.all_ifaces->len : 0);
100 #else
101 /* Currently no interfaces available for libpcap-less builds */
102 return 0;
103 #endif
106 int InterfaceTreeModel::columnCount(const QModelIndex &) const
108 /* IFTREE_COL_MAX is not being displayed, it is the definition for the maximum numbers of columns */
109 return ((int) IFTREE_COL_MAX);
112 QVariant InterfaceTreeModel::data(const QModelIndex &index, int role) const
114 #ifdef HAVE_LIBPCAP
115 bool interfacesLoaded = true;
116 if (! global_capture_opts.all_ifaces || global_capture_opts.all_ifaces->len == 0)
117 interfacesLoaded = false;
119 if (!index.isValid())
120 return QVariant();
122 int row = index.row();
123 InterfaceTreeColumns col = (InterfaceTreeColumns) index.column();
125 if (interfacesLoaded)
127 interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, row);
129 /* Data for display in cell */
130 if (role == Qt::DisplayRole)
132 /* Only the name is being displayed */
133 if (col == IFTREE_COL_NAME)
135 return QString(device->name);
137 else if (col == IFTREE_COL_DESCRIPTION)
139 return QString(device->if_info.friendly_name);
141 else if (col == IFTREE_COL_DISPLAY_NAME)
143 return QString(device->display_name);
145 else if (col == IFTREE_COL_PIPE_PATH)
147 return QString(device->if_info.name);
149 else if (col == IFTREE_COL_CAPTURE_FILTER)
151 if (device->cfilter && strlen(device->cfilter) > 0)
152 return html_escape(QString(device->cfilter));
154 else if (col == IFTREE_COL_EXTCAP_PATH)
156 return QString(device->if_info.extcap);
158 else if (col == IFTREE_COL_SNAPLEN)
160 return device->has_snaplen ? QString::number(device->snaplen) : DefaultNumericValue;
162 #ifdef CAN_SET_CAPTURE_BUFFER_SIZE
163 else if (col == IFTREE_COL_BUFFERLEN)
165 return QString::number(device->buffer);
167 #endif
168 else if (col == IFTREE_COL_TYPE)
170 return QVariant::fromValue((int)device->if_info.type);
172 else if (col == IFTREE_COL_COMMENT)
174 QString comment = gchar_free_to_qstring(capture_dev_user_descr_find(device->name));
175 if (comment.length() > 0)
176 return comment;
177 else
178 return QString(device->if_info.vendor_description);
180 else if (col == IFTREE_COL_DLT)
182 // XXX - this is duplicated in
183 // InterfaceTreeWidgetItem::updateInterfaceColumns;
184 // it should be done in common code somewhere.
185 QString linkname;
186 if (device->active_dlt == -1)
187 linkname = "Unknown";
188 else {
189 linkname = QObject::tr("DLT %1").arg(device->active_dlt);
190 for (GList *list = device->links; list != Q_NULLPTR; list = gxx_list_next(list)) {
191 link_row *linkr = gxx_list_data(link_row *, list);
192 if (linkr->dlt == device->active_dlt) {
193 linkname = linkr->name;
194 break;
199 return linkname;
201 else
203 /* Return empty string for every other DisplayRole */
204 return QVariant();
207 else if (role == Qt::CheckStateRole)
209 if (col == IFTREE_COL_HIDDEN)
211 /* Hidden is a de-selection, therefore inverted logic here */
212 return device->hidden ? Qt::Unchecked : Qt::Checked;
214 else if (col == IFTREE_COL_PROMISCUOUSMODE)
216 return device->pmode ? Qt::Checked : Qt::Unchecked;
218 #ifdef HAVE_PCAP_CREATE
219 else if (col == IFTREE_COL_MONITOR_MODE)
221 return device->monitor_mode_enabled ? Qt::Checked : Qt::Unchecked;
223 #endif
225 /* Used by SparkLineDelegate for loading the data for the statistics line */
226 else if (role == Qt::UserRole)
228 if (col == IFTREE_COL_STATS)
230 if ((active.contains(device->name) && active[device->name]) && points.contains(device->name))
231 return QVariant::fromValue(points[device->name]);
233 else if (col == IFTREE_COL_ACTIVE)
235 if (active.contains(device->name))
236 return QVariant::fromValue(active[device->name]);
238 else if (col == IFTREE_COL_HIDDEN)
240 return QVariant::fromValue((bool)device->hidden);
243 /* Displays the configuration icon for extcap interfaces */
244 else if (role == Qt::DecorationRole)
246 if (col == IFTREE_COL_EXTCAP)
248 if (device->if_info.type == IF_EXTCAP)
249 return QIcon(StockIcon("x-capture-options"));
252 else if (role == Qt::TextAlignmentRole)
254 if (col == IFTREE_COL_EXTCAP)
256 return Qt::AlignRight;
259 /* Displays the tooltip for each row */
260 else if (role == Qt::ToolTipRole)
262 return toolTipForInterface(row);
265 #else
266 Q_UNUSED(index)
267 Q_UNUSED(role)
268 #endif
270 return QVariant();
273 QVariant InterfaceTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
275 if (orientation == Qt::Horizontal)
277 if (role == Qt::DisplayRole)
279 if (section == IFTREE_COL_HIDDEN)
281 return tr("Show");
283 else if (section == IFTREE_COL_NAME)
285 return tr("Interface Name");
287 else if (section == IFTREE_COL_DESCRIPTION)
289 return tr("Friendly Name");
291 else if (section == IFTREE_COL_DISPLAY_NAME)
293 return tr("Friendly Name");
295 else if (section == IFTREE_COL_PIPE_PATH)
297 return tr("Local Pipe Path");
299 else if (section == IFTREE_COL_COMMENT)
301 return tr("Comment");
303 else if (section == IFTREE_COL_DLT)
305 return tr("Link-Layer Header");
307 else if (section == IFTREE_COL_PROMISCUOUSMODE)
309 return tr("Promiscuous");
311 else if (section == IFTREE_COL_SNAPLEN)
313 return tr("Snaplen (B)");
315 #ifdef CAN_SET_CAPTURE_BUFFER_SIZE
316 else if (section == IFTREE_COL_BUFFERLEN)
318 return tr("Buffer (MB)");
320 #endif
321 #ifdef HAVE_PCAP_CREATE
322 else if (section == IFTREE_COL_MONITOR_MODE)
324 return tr("Monitor Mode");
326 #endif
327 else if (section == IFTREE_COL_CAPTURE_FILTER)
329 return tr("Capture Filter");
334 return QVariant();
337 QVariant InterfaceTreeModel::getColumnContent(int idx, int col, int role)
339 return InterfaceTreeModel::data(index(idx, col), role);
342 #ifdef HAVE_PCAP_REMOTE
343 bool InterfaceTreeModel::isRemote(int idx)
345 interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, idx);
346 if (device->remote_opts.src_type == CAPTURE_IFREMOTE)
347 return true;
348 return false;
350 #endif
353 * The interface list has changed. global_capture_opts.all_ifaces may have been reloaded
354 * or changed with current data. beginResetModel() and endResetModel() will signalize the
355 * proxy model and the view, that the data has changed and the view has to reload
357 void InterfaceTreeModel::interfaceListChanged()
359 beginResetModel();
361 points.clear();
362 active.clear();
364 endResetModel();
368 * Displays the tooltip code for the given device index.
370 QVariant InterfaceTreeModel::toolTipForInterface(int idx) const
372 #ifdef HAVE_LIBPCAP
373 if (! global_capture_opts.all_ifaces || global_capture_opts.all_ifaces->len <= (unsigned) idx)
374 return QVariant();
376 interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, idx);
378 QString tt_str = "<p>";
379 if (device->no_addresses > 0)
381 tt_str += QStringLiteral("%1: %2")
382 .arg(device->no_addresses > 1 ? tr("Addresses") : tr("Address"))
383 .arg(html_escape(device->addresses))
384 .replace('\n', ", ");
386 else if (device->if_info.type == IF_EXTCAP)
388 tt_str = tr("Extcap interface: %1").arg(get_basename(device->if_info.extcap));
390 else
392 tt_str = tr("No addresses");
394 tt_str += "<br/>";
396 QString cfilter = device->cfilter;
397 if (cfilter.isEmpty())
399 tt_str += tr("No capture filter");
401 else
403 tt_str += QStringLiteral("%1: %2")
404 .arg(tr("Capture filter"))
405 .arg(html_escape(cfilter));
407 tt_str += "</p>";
409 return tt_str;
410 #else
411 Q_UNUSED(idx)
413 return QVariant();
414 #endif
417 #ifdef HAVE_LIBPCAP
418 void InterfaceTreeModel::setCache(if_stat_cache_t *stat_cache)
420 stopStatistic();
421 stat_cache_ = stat_cache;
424 void InterfaceTreeModel::stopStatistic()
426 if (stat_cache_)
428 capture_stat_stop(stat_cache_);
429 stat_cache_ = NULL;
432 #endif
434 void InterfaceTreeModel::updateStatistic(unsigned int idx)
436 #ifdef HAVE_LIBPCAP
437 if (! global_capture_opts.all_ifaces || global_capture_opts.all_ifaces->len <= (unsigned) idx)
438 return;
440 interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, idx);
442 if (device->if_info.type == IF_PIPE || device->if_info.type == IF_EXTCAP)
443 return;
445 if (!stat_cache_)
447 // Start gathering statistics using dumpcap
449 // The stat cache will only properly configure if it has the list
450 // of interfaces in global_capture_opts->all_ifaces.
451 // We crash if we try to do this from InterfaceFrame::showEvent,
452 // because main.cpp calls mainw->show() before capture_opts_init().
453 stat_cache_ = capture_stat_start(&global_capture_opts);
456 struct pcap_stat stats;
457 unsigned diff = 0;
458 bool isActive = false;
460 if (capture_stats(stat_cache_, device->name, &stats))
462 if ( (int) stats.ps_recv > 0 )
463 isActive = true;
465 if ((int)(stats.ps_recv - device->last_packets) >= 0)
467 diff = stats.ps_recv - device->last_packets;
468 device->packet_diff = diff;
470 device->last_packets = stats.ps_recv;
473 points[device->name].append(diff);
475 if (active[device->name] != isActive)
477 emit layoutAboutToBeChanged();
478 active[device->name] = isActive;
479 emit layoutChanged();
482 emit dataChanged(index(idx, IFTREE_COL_STATS), index(idx, IFTREE_COL_STATS));
484 #else
485 Q_UNUSED(idx)
486 #endif
489 QItemSelection InterfaceTreeModel::selectedDevices()
491 QItemSelection mySelection;
492 #ifdef HAVE_LIBPCAP
493 for (int idx = 0; idx < rowCount(); idx++)
495 interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, idx);
497 if (device->selected)
499 QModelIndex selectIndex = index(idx, 0);
500 mySelection.merge(
501 QItemSelection(selectIndex, index(selectIndex.row(), columnCount() - 1)),
502 QItemSelectionModel::SelectCurrent
506 #endif
507 return mySelection;
510 bool InterfaceTreeModel::updateSelectedDevices(QItemSelection sourceSelection)
512 bool selectionHasChanged = false;
513 #ifdef HAVE_LIBPCAP
514 QList<int> selectedIndices;
516 QItemSelection::const_iterator it = sourceSelection.constBegin();
517 while (it != sourceSelection.constEnd())
519 QModelIndexList indeces = ((QItemSelectionRange) (*it)).indexes();
521 QModelIndexList::const_iterator cit = indeces.constBegin();
522 while (cit != indeces.constEnd())
524 QModelIndex index = (QModelIndex) (*cit);
525 if (! selectedIndices.contains(index.row()))
527 selectedIndices.append(index.row());
529 ++cit;
531 ++it;
534 global_capture_opts.num_selected = 0;
536 for (unsigned int idx = 0; idx < global_capture_opts.all_ifaces->len; idx++)
538 interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, idx);
539 if (selectedIndices.contains(idx))
541 if (! device->selected)
542 selectionHasChanged = true;
543 device->selected = true;
544 global_capture_opts.num_selected++;
545 } else {
546 if (device->selected)
547 selectionHasChanged = true;
548 device->selected = false;
551 #else
552 Q_UNUSED(sourceSelection)
553 #endif
554 return selectionHasChanged;