iface_lists: Access ifaces member by reference
[metze/wireshark/wip.git] / ui / qt / interface_toolbar.cpp
1 /* interface_toolbar.cpp
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "config.h"
23
24 #include <errno.h>
25
26 #include "interface_toolbar.h"
27 #include <ui/qt/widgets/interface_toolbar_lineedit.h>
28 #include "simple_dialog.h"
29 #include "ui/main_statusbar.h"
30 #include <ui_interface_toolbar.h>
31
32 #include "capture_opts.h"
33 #include "ui/capture_globals.h"
34 #include "sync_pipe.h"
35 #include "wsutil/file_util.h"
36
37 #include <QCheckBox>
38 #include <QComboBox>
39 #include <QDesktopServices>
40 #include <QLineEdit>
41 #include <QPushButton>
42 #include <QThread>
43 #include <QUrl>
44
45 static const char *interface_type_property = "control_type";
46 static const char *interface_role_property = "control_role";
47
48 // From interface control protocol.
49 enum InterfaceControlCommand {
50     commandControlInitialized  = 0,
51     commandControlSet          = 1,
52     commandControlAdd          = 2,
53     commandControlRemove       = 3,
54     commandControlEnable       = 4,
55     commandControlDisable      = 5,
56     commandStatusMessage       = 6,
57     commandInformationMessage  = 7,
58     commandWarningMessage      = 8,
59     commandErrorMessage        = 9,
60 };
61
62 // To do:
63 // - Move control pipe handling to extcap
64
65 InterfaceToolbar::InterfaceToolbar(QWidget *parent, const iface_toolbar *toolbar) :
66     QFrame(parent),
67     ui(new Ui::InterfaceToolbar),
68     help_link_(toolbar->help),
69     use_spacer_(true)
70 {
71     ui->setupUi(this);
72
73     // Fill inn interfaces list and initialize default interface values
74     for (GList *walker = toolbar->ifnames; walker; walker = walker->next)
75     {
76         QString ifname((gchar *)walker->data);
77         interface_[ifname].reader_thread = NULL;
78         interface_[ifname].out_fd = -1;
79         interface_[ifname].log_dialog = NULL;
80     }
81
82     initializeControls(toolbar);
83
84 #ifdef Q_OS_MAC
85     foreach (QWidget *w, findChildren<QWidget *>())
86     {
87         w->setAttribute(Qt::WA_MacSmallSize, true);
88     }
89 #endif
90
91     if (!use_spacer_)
92     {
93         ui->horizontalSpacer->changeSize(0,0, QSizePolicy::Fixed, QSizePolicy::Fixed);
94     }
95
96     updateWidgets();
97 }
98
99 InterfaceToolbar::~InterfaceToolbar()
100 {
101     foreach (QString ifname, interface_.keys())
102     {
103         if (interface_[ifname].log_dialog)
104         {
105             interface_[ifname].log_dialog->close();
106         }
107     }
108
109     delete ui;
110 }
111
112 void InterfaceToolbar::initializeControls(const iface_toolbar *toolbar)
113 {
114     for (GList *walker = toolbar->controls; walker; walker = walker->next)
115     {
116         iface_toolbar_control *control = (iface_toolbar_control *)walker->data;
117
118         if (control_widget_.contains(control->num))
119         {
120             // Already have a widget with this number
121             continue;
122         }
123
124         QWidget *widget = NULL;
125         switch (control->ctrl_type)
126         {
127             case INTERFACE_TYPE_BOOLEAN:
128                 widget = createCheckbox(control);
129                 break;
130
131             case INTERFACE_TYPE_BUTTON:
132                 widget = createButton(control);
133                 break;
134
135             case INTERFACE_TYPE_SELECTOR:
136                 widget = createSelector(control);
137                 break;
138
139             case INTERFACE_TYPE_STRING:
140                 widget = createString(control);
141                 break;
142
143             default:
144                 // Not supported
145                 break;
146         }
147
148         if (widget)
149         {
150             widget->setProperty(interface_type_property, control->ctrl_type);
151             widget->setProperty(interface_role_property, control->ctrl_role);
152             control_widget_[control->num] = widget;
153         }
154     }
155 }
156
157 void InterfaceToolbar::setDefaultValue(int num, const QByteArray &value)
158 {
159     foreach (QString ifname, interface_.keys())
160     {
161         // Adding default value to all interfaces
162         interface_[ifname].value[num] = value;
163     }
164     default_value_[num] = value;
165 }
166
167 QWidget *InterfaceToolbar::createCheckbox(iface_toolbar_control *control)
168 {
169     QCheckBox *checkbox = new QCheckBox(QString().fromUtf8(control->display));
170     checkbox->setToolTip(QString().fromUtf8(control->tooltip));
171
172     if (control->default_value.boolean)
173     {
174         checkbox->setCheckState(Qt::Checked);
175         QByteArray default_value(1, 1);
176         setDefaultValue(control->num, default_value);
177     }
178
179     connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(onCheckBoxChanged(int)));
180
181     ui->leftLayout->addWidget(checkbox);
182
183     return checkbox;
184 }
185
186 QWidget *InterfaceToolbar::createButton(iface_toolbar_control *control)
187 {
188     QPushButton *button = new QPushButton(QString().fromUtf8((gchar *)control->display));
189     button->setMaximumHeight(27);
190     button->setToolTip(QString().fromUtf8(control->tooltip));
191
192     switch (control->ctrl_role)
193     {
194         case INTERFACE_ROLE_CONTROL:
195             setDefaultValue(control->num, (gchar *)control->display);
196             connect(button, SIGNAL(pressed()), this, SLOT(onControlButtonPressed()));
197             break;
198
199         case INTERFACE_ROLE_HELP:
200             connect(button, SIGNAL(pressed()), this, SLOT(onHelpButtonPressed()));
201             if (help_link_.isEmpty())
202             {
203                 // No help URL provided
204                 button->hide();
205             }
206             break;
207
208         case INTERFACE_ROLE_LOGGER:
209             connect(button, SIGNAL(pressed()), this, SLOT(onLogButtonPressed()));
210             break;
211
212         case INTERFACE_ROLE_RESTORE:
213             connect(button, SIGNAL(pressed()), this, SLOT(onRestoreButtonPressed()));
214             break;
215
216         default:
217             // Not supported
218             break;
219     }
220
221     ui->rightLayout->addWidget(button);
222
223     return button;
224 }
225
226 QWidget *InterfaceToolbar::createSelector(iface_toolbar_control *control)
227 {
228     QLabel *label = new QLabel(QString().fromUtf8(control->display));
229     label->setToolTip(QString().fromUtf8(control->tooltip));
230     QComboBox *combobox = new QComboBox();
231     combobox->setToolTip(QString().fromUtf8(control->tooltip));
232     combobox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
233
234     for (GList *walker = control->values; walker; walker = walker->next)
235     {
236         iface_toolbar_value *val = (iface_toolbar_value *)walker->data;
237         QString value = QString().fromUtf8((gchar *)val->value);
238         if (value.isEmpty())
239         {
240             // Invalid value
241             continue;
242         }
243         QString display = QString().fromUtf8((gchar *)val->display);
244         QByteArray interface_value;
245
246         interface_value.append(value);
247         if (display.isEmpty())
248         {
249             display = value;
250         }
251         else
252         {
253             interface_value.append('\0' + display);
254         }
255         combobox->addItem(display, value);
256         if (val->is_default)
257         {
258 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
259             combobox->setCurrentText(display);
260 #else
261             int new_index = combobox->findText(display);
262             if (new_index >= 0)
263             {
264                 combobox->setCurrentIndex(new_index);
265             }
266 #endif
267             setDefaultValue(control->num, value.toUtf8());
268         }
269         foreach (QString ifname, interface_.keys())
270         {
271             // Adding values to all interfaces
272             interface_[ifname].list[control->num].append(interface_value);
273         }
274         default_list_[control->num].append(interface_value);
275     }
276
277     connect(combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(onComboBoxChanged(int)));
278
279     ui->leftLayout->addWidget(label);
280     ui->leftLayout->addWidget(combobox);
281     label_widget_[control->num] = label;
282
283     return combobox;
284 }
285
286 QWidget *InterfaceToolbar::createString(iface_toolbar_control *control)
287 {
288     QLabel *label = new QLabel(QString().fromUtf8(control->display));
289     label->setToolTip(QString().fromUtf8(control->tooltip));
290     InterfaceToolbarLineEdit *lineedit = new InterfaceToolbarLineEdit(NULL, control->validation, control->is_required);
291     lineedit->setToolTip(QString().fromUtf8(control->tooltip));
292     lineedit->setPlaceholderText(QString().fromUtf8(control->placeholder));
293
294     if (control->default_value.string)
295     {
296         lineedit->setText(QString().fromUtf8(control->default_value.string));
297         setDefaultValue(control->num, control->default_value.string);
298     }
299
300     connect(lineedit, SIGNAL(editedTextApplied()), this, SLOT(onLineEditChanged()));
301
302     ui->leftLayout->addWidget(label);
303     ui->leftLayout->addWidget(lineedit);
304     label_widget_[control->num] = label;
305     use_spacer_ = false;
306
307     return lineedit;
308 }
309
310 void InterfaceToolbar::setWidgetValue(QWidget *widget, int command, QByteArray payload)
311 {
312     if (QComboBox *combobox = dynamic_cast<QComboBox *>(widget))
313     {
314         combobox->blockSignals(true);
315         switch (command)
316         {
317             case commandControlSet:
318             {
319                 int idx = combobox->findData(payload);
320                 if (idx != -1)
321                 {
322                     combobox->setCurrentIndex(idx);
323                 }
324                 break;
325             }
326
327             case commandControlAdd:
328             {
329                 QString value;
330                 QString display;
331                 if (payload.contains('\0'))
332                 {
333                     // The payload contains "value\0display"
334                     QList<QByteArray> values = payload.split('\0');
335                     value = values[0];
336                     display = values[1];
337                 }
338                 else
339                 {
340                     value = display = payload;
341                 }
342
343                 int idx = combobox->findData(value);
344                 if (idx != -1)
345                 {
346                     // The value already exists, update item text
347                     combobox->setItemText(idx, display);
348                 }
349                 else
350                 {
351                     combobox->addItem(display, value);
352                 }
353                 break;
354             }
355
356             case commandControlRemove:
357             {
358                 if (payload.size() == 0)
359                 {
360                     combobox->clear();
361                 }
362                 else
363                 {
364                     int idx = combobox->findData(payload);
365                     if (idx != -1)
366                     {
367                         combobox->removeItem(idx);
368                     }
369                 }
370                 break;
371             }
372
373             default:
374                 break;
375         }
376         combobox->blockSignals(false);
377     }
378     else if (InterfaceToolbarLineEdit *lineedit = dynamic_cast<InterfaceToolbarLineEdit *>(widget))
379     {
380         // We don't block signals here because changes are applied with enter or apply button,
381         // and we want InterfaceToolbarLineEdit to always syntax check the text.
382         switch (command)
383         {
384             case commandControlSet:
385                 lineedit->setText(payload);
386                 lineedit->disableApplyButton();
387                 break;
388
389             default:
390                 break;
391         }
392     }
393     else if (QCheckBox *checkbox = dynamic_cast<QCheckBox *>(widget))
394     {
395         checkbox->blockSignals(true);
396         switch (command)
397         {
398             case commandControlSet:
399             {
400                 Qt::CheckState state = Qt::Unchecked;
401                 if (payload.size() > 0 && payload.at(0) != 0)
402                 {
403                     state = Qt::Checked;
404                 }
405                 checkbox->setCheckState(state);
406                 break;
407             }
408
409             default:
410                 break;
411         }
412         checkbox->blockSignals(false);
413     }
414     else if (QPushButton *button = dynamic_cast<QPushButton *>(widget))
415     {
416         if ((command == commandControlSet) &&
417             widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL)
418         {
419             button->setText(payload);
420         }
421     }
422 }
423
424 void InterfaceToolbar::setInterfaceValue(QString ifname, QWidget *widget, int num, int command, QByteArray payload)
425 {
426     if (dynamic_cast<QComboBox *>(widget))
427     {
428         switch (command)
429         {
430             case commandControlSet:
431                 if (interface_[ifname].value[num] != payload)
432                 {
433                     interface_[ifname].value_changed[num] = false;
434                 }
435                 foreach (QByteArray entry, interface_[ifname].list[num])
436                 {
437                     if (entry == payload || entry.startsWith(payload + '\0'))
438                     {
439                         interface_[ifname].value[num] = payload;
440                     }
441                 }
442                 break;
443
444             case commandControlAdd:
445                 interface_[ifname].list[num].append(payload);
446                 break;
447
448             case commandControlRemove:
449                 if (payload.size() == 0)
450                 {
451                     interface_[ifname].value[num].clear();
452                     interface_[ifname].list[num].clear();
453                 }
454                 else
455                 {
456                     foreach (QByteArray entry, interface_[ifname].list[num])
457                     {
458                         if (entry == payload || entry.startsWith(payload + '\0'))
459                         {
460                             interface_[ifname].list[num].removeAll(entry);
461                         }
462                     }
463                 }
464                 break;
465
466             default:
467                 break;
468         }
469     }
470     else if (dynamic_cast<InterfaceToolbarLineEdit *>(widget))
471     {
472         switch (command)
473         {
474             case commandControlSet:
475                 if (interface_[ifname].value[num] != payload)
476                 {
477                     interface_[ifname].value_changed[num] = false;
478                 }
479                 interface_[ifname].value[num] = payload;
480                 break;
481
482             default:
483                 break;
484         }
485     }
486     else if ((widget->property(interface_type_property).toInt() == INTERFACE_TYPE_BUTTON) &&
487              (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_LOGGER))
488     {
489         if (command == commandControlSet)
490         {
491             if (interface_[ifname].log_dialog)
492             {
493                 interface_[ifname].log_dialog->clearText();
494             }
495             interface_[ifname].log_text.clear();
496         }
497         if (command == commandControlSet || command == commandControlAdd)
498         {
499             if (interface_[ifname].log_dialog)
500             {
501                 interface_[ifname].log_dialog->appendText(payload);
502             }
503             interface_[ifname].log_text.append(payload);
504         }
505     }
506     else if (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL)
507     {
508         // QCheckBox or QPushButton
509         switch (command)
510         {
511             case commandControlSet:
512                 if (interface_[ifname].value[num] != payload)
513                 {
514                     interface_[ifname].value_changed[num] = false;
515                 }
516                 interface_[ifname].value[num] = payload;
517                 break;
518
519             default:
520                 break;
521         }
522     }
523 }
524
525 void InterfaceToolbar::controlReceived(QString ifname, int num, int command, QByteArray payload)
526 {
527     switch (command)
528     {
529         case commandControlSet:
530         case commandControlAdd:
531         case commandControlRemove:
532             if (control_widget_.contains(num))
533             {
534                 QWidget *widget = control_widget_[num];
535                 setInterfaceValue(ifname, widget, num, command, payload);
536
537                 if (ifname.compare(ui->interfacesComboBox->currentText()) == 0)
538                 {
539                     setWidgetValue(widget, command, payload);
540                 }
541             }
542             break;
543
544         case commandControlEnable:
545         case commandControlDisable:
546             if (control_widget_.contains(num))
547             {
548                 QWidget *widget = control_widget_[num];
549                 if (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL)
550                 {
551                     bool enable = (command == commandControlEnable ? true : false);
552                     interface_[ifname].widget_disabled[num] = !enable;
553
554                     if (ifname.compare(ui->interfacesComboBox->currentText()) == 0)
555                     {
556                         widget->setEnabled(enable);
557                         if (label_widget_.contains(num))
558                         {
559                             label_widget_[num]->setEnabled(enable);
560                         }
561                     }
562                 }
563             }
564             break;
565
566         case commandStatusMessage:
567             statusbar_push_temporary_msg("%s", payload.data());
568             break;
569
570         case commandInformationMessage:
571             simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, "%s", payload.data());
572             break;
573
574         case commandWarningMessage:
575             simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK, "%s", payload.data());
576             break;
577
578         case commandErrorMessage:
579             simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", payload.data());
580             break;
581
582         default:
583             // Unknown commands are silently ignored
584             break;
585     }
586 }
587
588 void InterfaceToolbar::controlSend(QString ifname, int num, int command, const QByteArray &payload = QByteArray())
589 {
590     if (payload.length() > 65535)
591     {
592         // Not supported
593         return;
594     }
595
596     if (ifname.isEmpty() || interface_[ifname].out_fd == -1)
597     {
598         // Does not have a control out channel
599         return;
600     }
601
602     ssize_t payload_length = payload.length() + 2;
603     unsigned char high_nibble = (payload_length >> 16) & 0xFF;
604     unsigned char mid_nibble = (payload_length >> 8) & 0xFF;
605     unsigned char low_nibble = (payload_length >> 0) & 0xFF;
606
607     QByteArray ba;
608
609     ba.append(SP_TOOLBAR_CTRL);
610     ba.append(high_nibble);
611     ba.append(mid_nibble);
612     ba.append(low_nibble);
613     ba.append(num);
614     ba.append(command);
615     ba.append(payload);
616
617     if (ws_write(interface_[ifname].out_fd, ba.data(), ba.length()) != ba.length())
618     {
619         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
620                       "Unable to send control message:\n%s.",
621                       g_strerror(errno));
622     }
623 }
624
625 void InterfaceToolbar::onControlButtonPressed()
626 {
627     const QString &ifname = ui->interfacesComboBox->currentText();
628     QPushButton *button = static_cast<QPushButton *>(sender());
629     int num = control_widget_.key(button);
630
631     controlSend(ifname, num, commandControlSet);
632 }
633
634 void InterfaceToolbar::onCheckBoxChanged(int state)
635 {
636     const QString &ifname = ui->interfacesComboBox->currentText();
637     QCheckBox *checkbox = static_cast<QCheckBox *>(sender());
638     int num = control_widget_.key(checkbox);
639
640     QByteArray payload(1, state == Qt::Unchecked ? 0 : 1);
641     controlSend(ifname, num, commandControlSet, payload);
642     interface_[ifname].value[num] = payload;
643     interface_[ifname].value_changed[num] = true;
644 }
645
646 void InterfaceToolbar::onComboBoxChanged(int idx)
647 {
648     const QString &ifname = ui->interfacesComboBox->currentText();
649     QComboBox *combobox = static_cast<QComboBox *>(sender());
650     int num = control_widget_.key(combobox);
651     QString value = combobox->itemData(idx).toString();
652
653     QByteArray payload(value.toUtf8());
654     controlSend(ifname, num, commandControlSet, payload);
655     interface_[ifname].value[num] = payload;
656     interface_[ifname].value_changed[num] = true;
657 }
658
659 void InterfaceToolbar::onLineEditChanged()
660 {
661     const QString &ifname = ui->interfacesComboBox->currentText();
662     InterfaceToolbarLineEdit *lineedit = static_cast<InterfaceToolbarLineEdit *>(sender());
663     int num = control_widget_.key(lineedit);
664
665     QByteArray payload(lineedit->text().toUtf8());
666     controlSend(ifname, num, commandControlSet, payload);
667     interface_[ifname].value[num] = payload;
668     interface_[ifname].value_changed[num] = true;
669 }
670
671 void InterfaceToolbar::onLogButtonPressed()
672 {
673     const QString &ifname = ui->interfacesComboBox->currentText();
674
675     if (!interface_[ifname].log_dialog)
676     {
677         QPushButton *button = static_cast<QPushButton *>(sender());
678         interface_[ifname].log_dialog = new FunnelTextDialog(ifname + " " + button->text());
679         connect(interface_[ifname].log_dialog, SIGNAL(accepted()), this, SLOT(closeLog()));
680         connect(interface_[ifname].log_dialog, SIGNAL(rejected()), this, SLOT(closeLog()));
681
682         interface_[ifname].log_dialog->setText(interface_[ifname].log_text);
683     }
684
685     interface_[ifname].log_dialog->show();
686     interface_[ifname].log_dialog->raise();
687     interface_[ifname].log_dialog->activateWindow();
688 }
689
690 void InterfaceToolbar::onHelpButtonPressed()
691 {
692     QUrl help_url(help_link_);
693
694     if (help_url.scheme().compare("file") != 0)
695     {
696         QDesktopServices::openUrl(help_url);
697     }
698 }
699
700 void InterfaceToolbar::closeLog()
701 {
702     FunnelTextDialog *log_dialog = static_cast<FunnelTextDialog *>(sender());
703
704     foreach (QString ifname, interface_.keys())
705     {
706         if (interface_[ifname].log_dialog == log_dialog)
707         {
708             interface_[ifname].log_dialog = NULL;
709         }
710     }
711 }
712
713
714 void InterfaceToolbar::startReaderThread(QString ifname, void *control_in)
715 {
716     QThread *thread = new QThread;
717     InterfaceToolbarReader *reader = new InterfaceToolbarReader(ifname, control_in);
718     reader->moveToThread(thread);
719
720     connect(thread, SIGNAL(started()), reader, SLOT(loop()));
721     connect(reader, SIGNAL(finished()), thread, SLOT(quit()));
722     connect(reader, SIGNAL(finished()), reader, SLOT(deleteLater()));
723     connect(thread, SIGNAL(finished()), reader, SLOT(deleteLater()));
724     connect(reader, SIGNAL(received(QString, int, int, QByteArray)),
725             this, SLOT(controlReceived(QString, int, int, QByteArray)));
726
727     interface_[ifname].reader_thread = thread;
728
729     thread->start();
730 }
731
732 void InterfaceToolbar::startCapture(GArray *ifaces)
733 {
734     if (!ifaces || ifaces->len == 0)
735         return;
736
737 #ifdef HAVE_EXTCAP
738     const QString &selected_ifname = ui->interfacesComboBox->currentText();
739     QString first_capturing_ifname;
740     bool selected_found = false;
741
742     for (guint i = 0; i < ifaces->len; i++)
743     {
744         interface_options *interface_opts = &g_array_index(ifaces, interface_options, i);
745         QString ifname(interface_opts->name);
746
747         if (!interface_.contains(ifname))
748             // This interface is not for us
749             continue;
750
751         if (first_capturing_ifname.isEmpty())
752             first_capturing_ifname = ifname;
753
754         if (ifname.compare(selected_ifname) == 0)
755             selected_found = true;
756
757         if (interface_[ifname].out_fd != -1)
758             // Already have control channels for this interface
759             continue;
760
761         // Open control out channel
762 #ifdef _WIN32
763         startReaderThread(ifname, interface_opts->extcap_control_in_h);
764         interface_[ifname].out_fd = _open_osfhandle((intptr_t)interface_opts->extcap_control_out_h, O_APPEND | O_BINARY);
765 #else
766         startReaderThread(ifname, interface_opts->extcap_control_in);
767         interface_[ifname].out_fd = ws_open(interface_opts->extcap_control_out, O_WRONLY | O_BINARY, 0);
768 #endif
769         sendChangedValues(ifname);
770         controlSend(ifname, 0, commandControlInitialized);
771     }
772
773     if (!selected_found && !first_capturing_ifname.isEmpty())
774     {
775 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
776         ui->interfacesComboBox->setCurrentText(first_capturing_ifname);
777 #else
778         int new_index = ui->interfacesComboBox->findText(first_capturing_ifname);
779         if (new_index >= 0)
780         {
781             ui->interfacesComboBox->setCurrentIndex(new_index);
782         }
783 #endif
784     }
785     else
786     {
787         updateWidgets();
788     }
789 #endif // HAVE_EXTCAP
790 }
791
792 void InterfaceToolbar::stopCapture()
793 {
794     foreach (QString ifname, interface_.keys())
795     {
796         if (interface_[ifname].reader_thread)
797         {
798 #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
799             interface_[ifname].reader_thread->requestInterruption();
800 #endif
801             interface_[ifname].reader_thread = NULL;
802         }
803
804         if (interface_[ifname].out_fd != -1)
805         {
806 #ifndef _WIN32
807             ws_close (interface_[ifname].out_fd);
808 #endif
809             interface_[ifname].out_fd = -1;
810         }
811
812         foreach (int num, control_widget_.keys())
813         {
814             // Reset disabled property for all widgets
815             interface_[ifname].widget_disabled[num] = false;
816
817             QWidget *widget = control_widget_[num];
818             if ((widget->property(interface_type_property).toInt() == INTERFACE_TYPE_BUTTON) &&
819                 (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL))
820             {
821                 // Reset default value for control buttons
822                 interface_[ifname].value[num] = default_value_[num];
823
824                 if (ifname.compare(ui->interfacesComboBox->currentText()) == 0)
825                 {
826                     setWidgetValue(widget, commandControlSet, default_value_[num]);
827                 }
828             }
829         }
830     }
831
832     updateWidgets();
833 }
834
835 void InterfaceToolbar::sendChangedValues(QString ifname)
836 {
837     // Send all values which has changed
838     foreach (int num, control_widget_.keys())
839     {
840         QWidget *widget = control_widget_[num];
841         if ((interface_[ifname].value_changed[num]) &&
842             (widget->property(interface_type_property).toInt() != INTERFACE_TYPE_BUTTON) &&
843             (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL))
844         {
845             controlSend(ifname, num, commandControlSet, interface_[ifname].value[num]);
846         }
847     }
848 }
849
850 void InterfaceToolbar::onRestoreButtonPressed()
851 {
852     const QString &ifname = ui->interfacesComboBox->currentText();
853
854     // Set default values to all widgets and interfaces
855     foreach (int num, control_widget_.keys())
856     {
857         QWidget *widget = control_widget_[num];
858         if (default_list_[num].size() > 0)
859         {
860             // This is a QComboBox.  Clear list and add new entries.
861             setWidgetValue(widget, commandControlRemove, QByteArray());
862             interface_[ifname].list[num].clear();
863
864             foreach (QByteArray value, default_list_[num])
865             {
866                 setWidgetValue(widget, commandControlAdd, value);
867                 interface_[ifname].list[num].append(value);
868             }
869         }
870
871         switch (widget->property(interface_role_property).toInt())
872         {
873             case INTERFACE_ROLE_CONTROL:
874                 setWidgetValue(widget, commandControlSet, default_value_[num]);
875                 interface_[ifname].value[num] = default_value_[num];
876                 interface_[ifname].value_changed[num] = false;
877                 break;
878
879             case INTERFACE_ROLE_LOGGER:
880                 if (interface_[ifname].log_dialog)
881                 {
882                     interface_[ifname].log_dialog->clearText();
883                 }
884                 interface_[ifname].log_text.clear();
885                 break;
886
887             default:
888                 break;
889         }
890     }
891 }
892
893 bool InterfaceToolbar::hasInterface(QString ifname)
894 {
895     return interface_.contains(ifname);
896 }
897
898 void InterfaceToolbar::updateWidgets()
899 {
900     const QString &ifname = ui->interfacesComboBox->currentText();
901     bool is_capturing = (interface_[ifname].out_fd == -1 ? false : true);
902
903     foreach (int num, control_widget_.keys())
904     {
905         QWidget *widget = control_widget_[num];
906         bool widget_enabled = true;
907
908         if (ifname.isEmpty() &&
909             (widget->property(interface_role_property).toInt() != INTERFACE_ROLE_HELP))
910         {
911             // No interface selected, disable all but Help button
912             widget_enabled = false;
913         }
914         else if (!is_capturing &&
915                  (widget->property(interface_type_property).toInt() == INTERFACE_TYPE_BUTTON) &&
916                  (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL))
917         {
918             widget_enabled = false;
919         }
920         else if (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL)
921         {
922             widget_enabled = !interface_[ifname].widget_disabled[num];
923         }
924
925         widget->setEnabled(widget_enabled);
926         if (label_widget_.contains(num))
927         {
928             label_widget_[num]->setEnabled(widget_enabled);
929         }
930     }
931
932     foreach (int num, control_widget_.keys())
933     {
934         QWidget *widget = control_widget_[num];
935         if ((widget->property(interface_type_property).toInt() == INTERFACE_TYPE_BUTTON) &&
936             (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_RESTORE))
937         {
938             widget->setEnabled(!is_capturing);
939         }
940     }
941 }
942
943 void InterfaceToolbar::interfaceListChanged()
944 {
945 #ifdef HAVE_LIBPCAP
946     const QString &selected_ifname = ui->interfacesComboBox->currentText();
947     bool keep_selected = false;
948
949     ui->interfacesComboBox->blockSignals(true);
950     ui->interfacesComboBox->clear();
951
952     for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++)
953     {
954         interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
955         if (device->hidden)
956             continue;
957
958         if (interface_.keys().contains(device->name))
959         {
960             ui->interfacesComboBox->addItem(device->name);
961             if (selected_ifname.compare(device->name) == 0)
962             {
963                 // Keep selected interface
964 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
965                 ui->interfacesComboBox->setCurrentText(device->name);
966 #else
967                 int new_index = ui->interfacesComboBox->findText(device->name);
968                 if (new_index >= 0)
969                 {
970                     ui->interfacesComboBox->setCurrentIndex(new_index);
971                 }
972 #endif
973                 keep_selected = true;
974             }
975         }
976     }
977
978     ui->interfacesComboBox->blockSignals(false);
979
980     if (!keep_selected)
981     {
982         // Select the first interface
983         on_interfacesComboBox_currentIndexChanged(ui->interfacesComboBox->currentText());
984     }
985
986     updateWidgets();
987 #endif
988 }
989
990 void InterfaceToolbar::on_interfacesComboBox_currentIndexChanged(const QString &ifname)
991 {
992     foreach (int num, control_widget_.keys())
993     {
994         QWidget *widget = control_widget_[num];
995         if (interface_[ifname].list[num].size() > 0)
996         {
997             // This is a QComboBox.  Clear list and add new entries.
998             setWidgetValue(widget, commandControlRemove, QByteArray());
999
1000             foreach (QByteArray value, interface_[ifname].list[num])
1001             {
1002                 setWidgetValue(widget, commandControlAdd, value);
1003             }
1004         }
1005
1006         if (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL)
1007         {
1008             setWidgetValue(widget, commandControlSet, interface_[ifname].value[num]);
1009         }
1010     }
1011
1012     updateWidgets();
1013 }
1014
1015 /*
1016  * Editor modelines
1017  *
1018  * Local Variables:
1019  * c-basic-offset: 4
1020  * tab-width: 8
1021  * indent-tabs-mode: nil
1022  * End:
1023  *
1024  * ex: set shiftwidth=4 tabstop=8 expandtab:
1025  * :indentSize=4:tabSize=8:noTabs=true:
1026  */