extcap: Implement QT extcap options
[metze/wireshark/wip.git] / ui / qt / extcap_argument.cpp
1 /* extcap_argument.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 <extcap_argument.h>
23
24 #include <QObject>
25 #include <QWidget>
26 #include <QLabel>
27 #include <QLineEdit>
28 #include <QIntValidator>
29 #include <QDoubleValidator>
30 #include <QCheckBox>
31 #include <QButtonGroup>
32 #include <QBoxLayout>
33 #include <QRadioButton>
34 #include <QComboBox>
35 #include <QPushButton>
36 #include <QMargins>
37 #include <QVariant>
38 #include <QAbstractItemModel>
39 #include <QStringList>
40 #include <QStandardItem>
41 #include <QStandardItemModel>
42 #include <QItemSelectionModel>
43 #include <QTreeView>
44
45 #include <extcap_parser.h>
46 #include <extcap_argument_file.h>
47
48 class ExtArgMultiSelect : public ExtcapArgument
49 {
50 public:
51     ExtArgMultiSelect(extcap_arg * argument) :
52         ExtcapArgument(argument), treeView(0), viewModel(0) {};
53
54     virtual QList<QStandardItem *> valueWalker(ExtcapValueList list, QStringList &defaults)
55     {
56         ExtcapValueList::iterator iter = list.begin();
57         QList<QStandardItem *> items;
58
59         while ( iter != list.end() )
60         {
61             QStandardItem * item = new QStandardItem((*iter).value());
62             if ( (*iter).enabled() == false )
63             {
64                 item->setSelectable(false);
65             }
66             else
67                 item->setSelectable(true);
68
69             item->setData((*iter).call(), Qt::UserRole);
70             if ((*iter).isDefault())
71                 defaults << (*iter).call();
72
73             item->setEditable(false);
74             QList<QStandardItem *> childs = valueWalker((*iter).children(), defaults);
75             if ( childs.length() > 0 )
76                 item->appendRows(childs);
77
78             items << item;
79             ++iter;
80         }
81
82         return items;
83     }
84
85     void selectItemsWalker(QStandardItem * item, QStringList defaults)
86     {
87         QModelIndexList results;
88         QModelIndex index;
89
90         if ( item->hasChildren() )
91         {
92             for (int row = 0; row < item->rowCount(); row++)
93             {
94                 QStandardItem * child = item->child(row);
95                 if ( child != 0 )
96                 {
97                     selectItemsWalker(child, defaults);
98                 }
99             }
100         }
101
102         QString data = item->data(Qt::UserRole).toString();
103
104         if ( defaults.contains(data) )
105         {
106             treeView->selectionModel()->select(item->index(), QItemSelectionModel::Select);
107             index = item->index();
108             while ( index.isValid() )
109             {
110                 treeView->setExpanded(index, true);
111                 index = index.parent();
112             }
113         }
114     }
115
116     virtual QWidget * createEditor(QWidget * parent)
117     {
118         QStringList defaults;
119
120         QList<QStandardItem *> items = valueWalker(values, defaults);
121         if (items.length() == 0)
122             return new QWidget();
123
124         if ( _default != 0 )
125              defaults = _default->toString().split(",", QString::SkipEmptyParts);
126
127         viewModel = new QStandardItemModel();
128         QList<QStandardItem *>::const_iterator iter = items.constBegin();
129         while ( iter != items.constEnd() )
130         {
131             ((QStandardItemModel *)viewModel)->appendRow((*iter));
132             ++iter;
133         }
134
135         treeView = new QTreeView(parent);
136         treeView->setModel(viewModel);
137
138         /* Shows at minimum 6 entries at most desktops */
139         treeView->setMinimumHeight(100);
140         treeView->setHeaderHidden(true);
141         treeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
142         treeView->setEditTriggers(QAbstractItemView::NoEditTriggers);
143
144         for (int row = 0; row < viewModel->rowCount(); row++ )
145             selectItemsWalker(((QStandardItemModel*)viewModel)->item(row), defaults);
146
147         return treeView;
148     }
149
150     virtual QString value()
151     {
152         if ( viewModel == 0 )
153             return QString();
154
155         QStringList result;
156         QModelIndexList selected = treeView->selectionModel()->selectedIndexes();
157
158         if ( selected.size() <= 0 )
159             return QString();
160
161         QModelIndexList::const_iterator iter = selected.constBegin();
162         while ( iter != selected.constEnd() )
163         {
164             QModelIndex index = (QModelIndex)(*iter);
165
166             result << viewModel->data(index, Qt::UserRole).toString();
167
168             ++iter;
169         }
170
171         return result.join(QString(","));
172     }
173
174     virtual QString defaultValue()
175     {
176         if ( _argument != 0 && _argument->default_complex != 0)
177         {
178             gchar * str = extcap_get_complex_as_string(_argument->default_complex);
179             if ( str != 0 )
180                 return QString(str);
181         }
182
183         return QString();
184     }
185
186 private:
187     QTreeView * treeView;
188     QAbstractItemModel * viewModel;
189 };
190
191 class ExtArgSelector : public ExtcapArgument
192 {
193 public:
194     ExtArgSelector(extcap_arg * argument) :
195         ExtcapArgument(argument), boxSelection(0) {};
196
197     virtual QWidget * createEditor(QWidget * parent)
198     {
199         int counter = 0;
200         int selected = -1;
201
202         boxSelection = new QComboBox(parent);
203
204         if ( values.length() > 0 )
205         {
206             ExtcapValueList::const_iterator iter = values.constBegin();
207
208             while ( iter != values.constEnd() )
209             {
210                 boxSelection->addItem((*iter).value(), (*iter).call());
211                 if ( (*iter).isDefault() )
212                     selected = counter;
213
214                 counter++;
215                 ++iter;
216             }
217
218             if ( selected > -1 && selected < boxSelection->count() )
219                 boxSelection->setCurrentIndex(selected);
220         }
221
222         return boxSelection;
223     }
224
225     virtual QString value()
226     {
227         if ( boxSelection == 0 )
228             return QString();
229
230 #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
231         QVariant data = boxSelection->currentData();
232 #else
233         QVariant data = boxSelection->itemData(boxSelection->currentIndex());
234 #endif
235
236         return data.toString();
237     }
238
239 private:
240     QComboBox * boxSelection;
241 };
242
243 class ExtArgRadio : public ExtcapArgument
244 {
245 public:
246     ExtArgRadio(extcap_arg * argument) :
247         ExtcapArgument(argument), selectorGroup(0), callStrings(0)
248     {
249     };
250
251     virtual QWidget * createEditor(QWidget * parent)
252     {
253
254         int count = 0;
255         bool anyChecked = false;
256
257         selectorGroup = new QButtonGroup(parent);
258         QWidget * radioButtons = new QWidget;
259         QVBoxLayout * vrLayout = new QVBoxLayout();
260         QMargins margins = vrLayout->contentsMargins();
261         vrLayout->setContentsMargins(0, 0, 0, margins.bottom());
262         if ( callStrings != 0 )
263             delete callStrings;
264
265         callStrings = new QList<QString>();
266
267         if ( values.length() > 0  )
268         {
269             ExtcapValueList::const_iterator iter = values.constBegin();
270
271             while ( iter != values.constEnd() )
272            {
273                 QRadioButton * radio = new QRadioButton((*iter).value());
274                 QString callString = (*iter).call();
275                 callStrings->append(callString);
276
277                 if ( _default != NULL && (*iter).isDefault() )
278                 {
279                     radio->setChecked(true);
280                     anyChecked = true;
281                 }
282                 else if (_default != NULL)
283                 {
284                     if ( callString.compare(_default->toString()) == 0 )
285                     {
286                         radio->setChecked(true);
287                         anyChecked = true;
288                     }
289                 }
290                 selectorGroup->addButton(radio, count);
291
292                 vrLayout->addWidget(radio);
293                 count++;
294
295                 ++iter;
296             }
297         }
298
299         /* No default was provided, and not saved value exists */
300         if ( anyChecked == false && count > 0 )
301             ((QRadioButton*)(selectorGroup->button(0)))->setChecked(true);
302
303         radioButtons->setLayout(vrLayout);
304
305         return radioButtons;
306     }
307
308     virtual QString value()
309     {
310         int idx = 0;
311         if ( selectorGroup == 0 || callStrings == 0 )
312             return QString();
313
314         idx = selectorGroup->checkedId();
315         if ( idx > -1 && callStrings->length() > idx )
316             return callStrings->takeAt(idx);
317
318         return QString();
319     }
320
321 private:
322     QButtonGroup * selectorGroup;
323     QList<QString> * callStrings;
324 };
325
326 class ExtArgBool : public ExtcapArgument
327 {
328 public:
329     ExtArgBool(extcap_arg * argument) :
330         ExtcapArgument(argument), boolBox(0) {};
331
332     virtual QWidget * createLabel(QWidget * parent)
333     {
334         return new QWidget(parent);
335     }
336
337     virtual QWidget * createEditor(QWidget * parent)
338     {
339         boolBox = new QCheckBox(QString().fromUtf8(_argument->display), parent);
340         if ( _argument->tooltip != NULL )
341             boolBox->setToolTip(QString().fromUtf8(_argument->tooltip));
342
343         if ( _argument->default_complex != NULL )
344             if ( extcap_complex_get_bool(_argument->default_complex) == (gboolean)TRUE )
345                 boolBox->setCheckState(Qt::Checked);
346
347         if ( _default != NULL )
348         {
349             if ( _default->toString().compare("true") )
350                 boolBox->setCheckState(Qt::Checked);
351         }
352
353         return boolBox;
354     }
355
356     virtual QString call()
357     {
358         if ( boolBox == NULL )
359             return QString("");
360
361         if ( _argument->arg_type == EXTCAP_ARG_BOOLEAN )
362             return ExtcapArgument::call();
363
364         return QString(boolBox->checkState() == Qt::Checked ? _argument->call : "");
365     }
366
367     virtual QString value()
368     {
369         if ( boolBox == NULL || _argument->arg_type == EXTCAP_ARG_BOOLFLAG )
370             return QString();
371         return QString(boolBox->checkState() == Qt::Checked ? "true" : "false");
372     }
373
374     virtual QString defaultValue()
375     {
376         if ( _argument != 0 && _argument->default_complex != NULL )
377             if ( extcap_complex_get_bool(_argument->default_complex) == (gboolean)TRUE )
378                 return QString("true");
379
380         return QString("false");
381     }
382
383 private:
384     QCheckBox * boolBox;
385 };
386
387 class ExtArgText : public ExtcapArgument
388 {
389 public:
390     ExtArgText(extcap_arg * argument) :
391         ExtcapArgument(argument), textBox(0)
392     {
393         _default = new QVariant(QString(""));
394     };
395
396     virtual QWidget * createEditor(QWidget * parent)
397     {
398         textBox = new QLineEdit(_default->toString(), parent);
399
400         textBox->setText(defaultValue());
401
402         if ( _argument->tooltip != NULL )
403             textBox->setToolTip(QString().fromUtf8(_argument->tooltip));
404
405         return textBox;
406     }
407
408     virtual QString value()
409     {
410         if ( textBox == 0 )
411             return QString();
412
413         return textBox->text();
414     }
415
416     virtual QString defaultValue()
417     {
418         if ( _argument != 0 && _argument->default_complex != 0)
419         {
420             gchar * str = extcap_get_complex_as_string(_argument->default_complex);
421             if ( str != 0 )
422                 return QString(str);
423         }
424
425         return QString();
426     }
427
428 protected:
429     QLineEdit * textBox;
430 };
431
432 class ExtArgNumber : public ExtArgText
433 {
434 public:
435     ExtArgNumber(extcap_arg * argument) :
436         ExtArgText(argument) {};
437
438     virtual QWidget * createEditor(QWidget * parent)
439     {
440         textBox = (QLineEdit *)ExtArgText::createEditor(parent);
441
442         if ( _argument->arg_type == EXTCAP_ARG_INTEGER || _argument->arg_type == EXTCAP_ARG_UNSIGNED )
443         {
444             QIntValidator * textValidator = new QIntValidator(parent);
445             if ( _argument->range_start != NULL )
446                 textValidator->setBottom(extcap_complex_get_int(_argument->range_start));
447
448             if ( _argument->arg_type == EXTCAP_ARG_UNSIGNED && textValidator->bottom() < 0 )
449                 textValidator->setBottom(0);
450
451             if ( _argument->range_end != NULL )
452                 textValidator->setTop(extcap_complex_get_int(_argument->range_end));
453             textBox->setValidator(textValidator);
454         }
455         else if ( _argument->arg_type == EXTCAP_ARG_DOUBLE )
456         {
457             QDoubleValidator * textValidator = new QDoubleValidator(parent);
458             if ( _argument->range_start != NULL )
459                 textValidator->setBottom(extcap_complex_get_double(_argument->range_start));
460             if ( _argument->range_end != NULL )
461                 textValidator->setTop(extcap_complex_get_double(_argument->range_end));
462
463             textBox->setValidator(textValidator);
464         }
465
466         textBox->setText(defaultValue());
467
468         return textBox;
469     };
470
471     virtual QString defaultValue()
472     {
473         QString result;
474
475         if ( _argument != 0 && _argument->default_complex != NULL )
476         {
477             if ( _argument->arg_type == EXTCAP_ARG_DOUBLE )
478                 result = QString::number(extcap_complex_get_double(_argument->default_complex));
479             else if ( _argument->arg_type == EXTCAP_ARG_INTEGER )
480                 result = QString::number(extcap_complex_get_int(_argument->default_complex));
481             else if ( _argument->arg_type == EXTCAP_ARG_UNSIGNED )
482                 result = QString::number(extcap_complex_get_uint(_argument->default_complex));
483             else if ( _argument->arg_type == EXTCAP_ARG_LONG )
484                 result = QString::number(extcap_complex_get_long(_argument->default_complex));
485             else
486                 result = QString();
487         }
488
489         return result;
490     }
491 };
492
493 ExtcapValue::~ExtcapValue() {}
494
495 void ExtcapValue::setChildren(ExtcapValueList children)
496 {
497     ExtcapValueList::iterator iter = children.begin();
498     while ( iter != children.end() )
499     {
500         (*iter)._depth = _depth + 1;
501         ++iter;
502     }
503
504     _children.append(children);
505 }
506
507 ExtcapArgument::ExtcapArgument(extcap_arg * argument, QObject *parent) :
508         QObject(parent), _argument(argument), _default(0)
509 {
510     if ( _argument->values != 0 )
511     {
512         ExtcapValueList elements = loadValues(QString(""));
513         if ( elements.length() > 0 )
514             values.append(elements);
515     }
516 }
517
518 ExtcapValueList ExtcapArgument::loadValues(QString parent)
519 {
520     if (_argument->values == 0 )
521         return ExtcapValueList();
522
523     GList * walker = 0;
524     extcap_value * v;
525     ExtcapValueList elements;
526
527     for (walker = g_list_first((GList *)(_argument->values)); walker != NULL ; walker = walker->next)
528     {
529         v = (extcap_value *) walker->data;
530         if (v == NULL || v->display == NULL || v->call == NULL )
531             break;
532
533         QString valParent(v->parent == 0 ? "" : QString().fromUtf8(v->parent));
534
535         if ( parent.compare(valParent) == 0 )
536         {
537
538             QString display = QString().fromUtf8(v->display);
539             QString call = QString().fromUtf8(v->call);
540
541             ExtcapValue element = ExtcapValue(display, call,
542                             v->enabled == (gboolean)TRUE, v->is_default == (gboolean)TRUE);
543
544             element.setChildren(this->loadValues(call));
545             elements.append(element);
546         }
547     }
548
549     return elements;
550 }
551
552 ExtcapArgument::~ExtcapArgument() {
553     // TODO Auto-generated destructor stub
554 }
555
556 QWidget * ExtcapArgument::createLabel(QWidget * parent)
557 {
558     if ( _argument == 0 || _argument->display == 0 )
559         return 0;
560
561     QString text = QString().fromUtf8(_argument->display);
562
563     QLabel * label = new QLabel(text, parent);
564     if ( _argument->tooltip != 0 )
565         label->setToolTip(QString().fromUtf8(_argument->tooltip));
566
567     return label;
568 }
569
570 QWidget * ExtcapArgument::createEditor(QWidget * parent)
571 {
572     Q_UNUSED(parent);
573     return 0;
574 }
575
576 QString ExtcapArgument::call()
577 {
578     return QString(_argument->call);
579 }
580
581 QString ExtcapArgument::value()
582 {
583     return QString();
584 }
585
586 QString ExtcapArgument::defaultValue()
587 {
588     return QString();
589 }
590
591 void ExtcapArgument::setDefault(GHashTable * defaultsList)
592 {
593     if ( defaultsList != NULL && g_hash_table_size(defaultsList) > 0 )
594     {
595         GList * keys = g_hash_table_get_keys(defaultsList);
596         while ( keys != NULL )
597         {
598             if ( call().compare(QString().fromUtf8((gchar *)keys->data)) == 0 )
599             {
600                 gpointer data = g_hash_table_lookup(defaultsList, keys->data);
601                 QString dataStr = QString().fromUtf8((gchar *)data);
602                 /* We assume an empty value but set entry must be a boolflag */
603                 if ( dataStr.length() == 0 )
604                     dataStr = "true";
605                 _default = new QVariant(dataStr);
606                 break;
607             }
608             keys = keys->next;
609         }
610     }
611 }
612
613 ExtcapArgument * ExtcapArgument::create(extcap_arg * argument, GHashTable * device_defaults)
614 {
615     if ( argument == 0 || argument->display == 0 )
616         return 0;
617
618     ExtcapArgument * result = 0;
619
620     if ( argument->arg_type == EXTCAP_ARG_STRING )
621         result = new ExtArgText(argument);
622     else if ( argument->arg_type == EXTCAP_ARG_INTEGER || argument->arg_type == EXTCAP_ARG_LONG ||
623             argument->arg_type == EXTCAP_ARG_UNSIGNED || argument->arg_type == EXTCAP_ARG_DOUBLE )
624         result = new ExtArgNumber(argument);
625     else if ( argument->arg_type == EXTCAP_ARG_BOOLEAN || argument->arg_type == EXTCAP_ARG_BOOLFLAG )
626         result = new ExtArgBool(argument);
627     else if ( argument->arg_type == EXTCAP_ARG_SELECTOR )
628         result = new ExtArgSelector(argument);
629     else if ( argument->arg_type == EXTCAP_ARG_RADIO )
630         result = new ExtArgRadio(argument);
631     else if ( argument->arg_type == EXTCAP_ARG_FILESELECT )
632         result = new ExtcapArgumentFileSelection(argument);
633     else if ( argument->arg_type == EXTCAP_ARG_MULTICHECK )
634         result = new ExtArgMultiSelect(argument);
635     else
636     {
637         /* For everything else, we just print the label */
638         result = new ExtcapArgument(argument);
639     }
640
641     result->setDefault(device_defaults);
642
643     return result;
644 }
645
646 /*
647  * Editor modelines
648  *
649  * Local Variables:
650  * c-basic-offset: 4
651  * tab-width: 8
652  * indent-tabs-mode: nil
653  * End:
654  *
655  * ex: set shiftwidth=4 tabstop=8 expandtab:
656  * :indentSize=4:tabSize=8:noTabs=true:
657  */