3
* VBox frontends: Qt4 GUI ("VirtualBox"):
4
* VBoxVMSettingsUSB class implementation
8
* Copyright (C) 2006-2008 Sun Microsystems, Inc.
10
* This file is part of VirtualBox Open Source Edition (OSE), as
11
* available from http://www.virtualbox.org. This file is free software;
12
* you can redistribute it and/or modify it under the terms of the GNU
13
* General Public License (GPL) as published by the Free Software
14
* Foundation, in version 2 as it comes in the "COPYING" file of the
15
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19
* Clara, CA 95054 USA or visit http://www.sun.com if you need
20
* additional information or have any questions.
23
#include "VBoxVMSettingsUSB.h"
24
#include "VBoxVMSettingsUSBFilterDetails.h"
25
#include "VBoxSettingsUtils.h"
26
#include "QIWidgetValidator.h"
27
#include "VBoxToolBar.h"
28
#include "VBoxGlobal.h"
30
#include <QHeaderView>
32
inline static QString emptyToNull (const QString &str)
34
return str.isEmpty() ? QString::null : str;
37
VBoxVMSettingsUSB::VBoxVMSettingsUSB (FilterType aType)
41
/* Apply UI decorations */
42
Ui::VBoxVMSettingsUSB::setupUi (this);
45
mNewAction = new QAction (mTwFilters);
46
mAddAction = new QAction (mTwFilters);
47
mEdtAction = new QAction (mTwFilters);
48
mDelAction = new QAction (mTwFilters);
49
mMupAction = new QAction (mTwFilters);
50
mMdnAction = new QAction (mTwFilters);
52
mNewAction->setShortcut (QKeySequence ("Ins"));
53
mAddAction->setShortcut (QKeySequence ("Alt+Ins"));
54
mEdtAction->setShortcut (QKeySequence ("Ctrl+Return"));
55
mDelAction->setShortcut (QKeySequence ("Del"));
56
mMupAction->setShortcut (QKeySequence ("Ctrl+Up"));
57
mMdnAction->setShortcut (QKeySequence ("Ctrl+Down"));
59
mNewAction->setIcon (VBoxGlobal::iconSet (":/usb_new_16px.png",
60
":/usb_new_disabled_16px.png"));
61
mAddAction->setIcon (VBoxGlobal::iconSet (":/usb_add_16px.png",
62
":/usb_add_disabled_16px.png"));
63
mEdtAction->setIcon (VBoxGlobal::iconSet (":/usb_filter_edit_16px.png",
64
":/usb_filter_edit_disabled_16px.png"));
65
mDelAction->setIcon (VBoxGlobal::iconSet (":/usb_remove_16px.png",
66
":/usb_remove_disabled_16px.png"));
67
mMupAction->setIcon (VBoxGlobal::iconSet (":/usb_moveup_16px.png",
68
":/usb_moveup_disabled_16px.png"));
69
mMdnAction->setIcon (VBoxGlobal::iconSet (":/usb_movedown_16px.png",
70
":/usb_movedown_disabled_16px.png"));
72
/* Prepare menu and toolbar */
73
mMenu = new QMenu (mTwFilters);
74
mMenu->addAction (mNewAction);
75
mMenu->addAction (mAddAction);
76
mMenu->addSeparator();
77
mMenu->addAction (mEdtAction);
78
mMenu->addSeparator();
79
mMenu->addAction (mDelAction);
80
mMenu->addSeparator();
81
mMenu->addAction (mMupAction);
82
mMenu->addAction (mMdnAction);
85
VBoxToolBar *toolBar = new VBoxToolBar (mWtFilterHandler);
86
toolBar->setUsesTextLabel (false);
87
toolBar->setIconSize (QSize (16, 16));
88
toolBar->setOrientation (Qt::Vertical);
89
toolBar->addAction (mNewAction);
90
toolBar->addAction (mAddAction);
91
toolBar->addAction (mEdtAction);
92
toolBar->addAction (mDelAction);
93
toolBar->addAction (mMupAction);
94
toolBar->addAction (mMdnAction);
95
toolBar->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::MinimumExpanding);
96
toolBar->updateGeometry();
97
toolBar->setMinimumHeight (toolBar->sizeHint().height());
98
mWtFilterHandler->layout()->addWidget (toolBar);
100
/* Setup connections */
101
connect (mGbUSB, SIGNAL (toggled (bool)),
102
this, SLOT (usbAdapterToggled (bool)));
103
connect (mTwFilters, SIGNAL (currentItemChanged (QTreeWidgetItem*, QTreeWidgetItem*)),
104
this, SLOT (currentChanged (QTreeWidgetItem*, QTreeWidgetItem*)));
105
connect (mTwFilters, SIGNAL (customContextMenuRequested (const QPoint &)),
106
this, SLOT (showContextMenu (const QPoint &)));
107
connect (mTwFilters, SIGNAL (itemDoubleClicked (QTreeWidgetItem *, int)),
108
this, SLOT (edtClicked ()));
110
mUSBDevicesMenu = new VBoxUSBMenu (this);
111
connect (mUSBDevicesMenu, SIGNAL (triggered (QAction*)),
112
this, SLOT (addConfirmed (QAction *)));
113
connect (mNewAction, SIGNAL (triggered (bool)),
114
this, SLOT (newClicked()));
115
connect (mAddAction, SIGNAL (triggered (bool)),
116
this, SLOT (addClicked()));
117
connect (mEdtAction, SIGNAL (triggered (bool)),
118
this, SLOT (edtClicked()));
119
connect (mDelAction, SIGNAL (triggered (bool)),
120
this, SLOT (delClicked()));
121
connect (mMupAction, SIGNAL (triggered (bool)),
122
this, SLOT (mupClicked()));
123
connect (mMdnAction, SIGNAL (triggered (bool)),
124
this, SLOT (mdnClicked()));
127
mTwFilters->header()->hide();
129
/* Applying language settings */
133
void VBoxVMSettingsUSB::getFrom (const CSystemProperties &, const VBoxGlobalSettings &)
135
mGbUSB->setVisible (false);
137
CHostUSBDeviceFilterVector filtvec = vboxGlobal().virtualBox().GetHost()
138
.GetUSBDeviceFilters();
139
for (int i = 0; i < filtvec.size(); ++i)
141
CHostUSBDeviceFilter hostFilter = filtvec[i];
142
CUSBDeviceFilter filter (hostFilter);
143
addUSBFilter (filter, false /* isNew */);
146
mTwFilters->setCurrentItem (mTwFilters->topLevelItem (0));
147
currentChanged (mTwFilters->currentItem());
150
void VBoxVMSettingsUSB::putBackTo (CSystemProperties &, VBoxGlobalSettings &)
152
CHost host = vboxGlobal().virtualBox().GetHost();
154
if (mUSBFilterListModified)
156
/* First, remove all old filters */
157
for (ulong count = host.GetUSBDeviceFilters().size(); count; -- count)
158
host.RemoveUSBDeviceFilter (0);
160
/* Then add all new filters */
161
for (int i = 0; i < mFilters.size(); ++ i)
163
CUSBDeviceFilter filter = mFilters [i];
164
filter.SetActive (mTwFilters->topLevelItem (i)->
165
checkState (0) == Qt::Checked);
166
CHostUSBDeviceFilter insertedFilter (filter);
167
host.InsertUSBDeviceFilter (host.GetUSBDeviceFilters().size(),
172
mUSBFilterListModified = false;
175
void VBoxVMSettingsUSB::getFrom (const CMachine &aMachine)
179
CUSBController ctl = aMachine.GetUSBController();
180
mGbUSB->setChecked (!ctl.isNull() && ctl.GetEnabled());
181
mCbUSB2->setChecked (!ctl.isNull() && ctl.GetEnabledEhci());
182
usbAdapterToggled (mGbUSB->isChecked());
186
CUSBDeviceFilterVector filtvec = ctl.GetDeviceFilters();
187
for (int i = 0; i < filtvec.size(); ++i)
188
addUSBFilter (filtvec[i], false /* isNew */);
191
mTwFilters->setCurrentItem (mTwFilters->topLevelItem (0));
192
currentChanged (mTwFilters->currentItem());
195
void VBoxVMSettingsUSB::putBackTo()
197
CUSBController ctl = mMachine.GetUSBController();
200
ctl.SetEnabled (mGbUSB->isChecked());
201
ctl.SetEnabledEhci (mCbUSB2->isChecked());
203
if (mUSBFilterListModified)
205
/* First, remove all old filters */
206
for (ulong count = ctl.GetDeviceFilters().size(); count; -- count)
207
ctl.RemoveDeviceFilter (0);
209
/* Then add all new filters */
210
for (int i = 0; i < mFilters.size(); ++ i)
212
CUSBDeviceFilter filter = mFilters [i];
213
filter.SetActive (mTwFilters->topLevelItem (i)->
214
checkState (0) == Qt::Checked);
215
ctl.InsertDeviceFilter (~0, filter);
219
mUSBFilterListModified = false;
222
void VBoxVMSettingsUSB::setValidator (QIWidgetValidator *aVal)
227
void VBoxVMSettingsUSB::setOrderAfter (QWidget *aWidget)
229
setTabOrder (aWidget, mGbUSB);
230
setTabOrder (mGbUSB, mCbUSB2);
231
setTabOrder (mCbUSB2, mTwFilters);
234
void VBoxVMSettingsUSB::retranslateUi()
236
/* Translate uic generated strings */
237
Ui::VBoxVMSettingsUSB::retranslateUi (this);
239
mNewAction->setText (tr ("&Add Empty Filter"));
240
mAddAction->setText (tr ("A&dd Filter From Device"));
241
mEdtAction->setText (tr ("&Edit Filter"));
242
mDelAction->setText (tr ("&Remove Filter"));
243
mMupAction->setText (tr ("&Move Filter Up"));
244
mMdnAction->setText (tr ("M&ove Filter Down"));
246
mNewAction->setToolTip (mNewAction->text().remove ('&') +
247
QString (" (%1)").arg (mNewAction->shortcut().toString()));
248
mAddAction->setToolTip (mAddAction->text().remove ('&') +
249
QString (" (%1)").arg (mAddAction->shortcut().toString()));
250
mEdtAction->setToolTip (mEdtAction->text().remove ('&') +
251
QString (" (%1)").arg (mEdtAction->shortcut().toString()));
252
mDelAction->setToolTip (mDelAction->text().remove ('&') +
253
QString (" (%1)").arg (mDelAction->shortcut().toString()));
254
mMupAction->setToolTip (mMupAction->text().remove ('&') +
255
QString (" (%1)").arg (mMupAction->shortcut().toString()));
256
mMdnAction->setToolTip (mMdnAction->text().remove ('&') +
257
QString (" (%1)").arg (mMdnAction->shortcut().toString()));
259
mNewAction->setWhatsThis (tr ("Adds a new USB filter with all fields "
260
"initially set to empty strings. Note "
261
"that such a filter will match any "
262
"attached USB device."));
263
mAddAction->setWhatsThis (tr ("Adds a new USB filter with all fields "
264
"set to the values of the selected USB "
265
"device attached to the host PC."));
266
mEdtAction->setWhatsThis (tr ("Edits the selected USB filter."));
267
mDelAction->setWhatsThis (tr ("Removes the selected USB filter."));
268
mMupAction->setWhatsThis (tr ("Moves the selected USB filter up."));
269
mMdnAction->setWhatsThis (tr ("Moves the selected USB filter down."));
271
mUSBFilterName = tr ("New Filter %1", "usb");
274
void VBoxVMSettingsUSB::usbAdapterToggled (bool aOn)
276
mGbUSBFilters->setEnabled (aOn);
279
void VBoxVMSettingsUSB::currentChanged (QTreeWidgetItem *aItem,
282
/* Make sure only the current item if present => selected */
283
if (mTwFilters->selectedItems().count() != 1 ||
284
mTwFilters->selectedItems() [0] != aItem)
286
QList<QTreeWidgetItem*> list = mTwFilters->selectedItems();
287
for (int i = 0; i < list.size(); ++ i)
288
list [i]->setSelected (false);
290
aItem->setSelected (true);
293
/* Enable/disable operational buttons */
294
mEdtAction->setEnabled (aItem);
295
mDelAction->setEnabled (aItem);
296
mMupAction->setEnabled (aItem && mTwFilters->itemAbove (aItem));
297
mMdnAction->setEnabled (aItem && mTwFilters->itemBelow (aItem));
300
void VBoxVMSettingsUSB::newClicked()
302
/* Search for the max available filter index */
303
int maxFilterIndex = 0;
304
QRegExp regExp (QString ("^") + mUSBFilterName.arg ("([0-9]+)") + QString ("$"));
305
QTreeWidgetItemIterator iterator (mTwFilters);
308
QString filterName = (*iterator)->text (twUSBFilters_Name);
309
int pos = regExp.indexIn (filterName);
311
maxFilterIndex = regExp.cap (1).toInt() > maxFilterIndex ?
312
regExp.cap (1).toInt() : maxFilterIndex;
316
/* Creating new usb filter */
317
CUSBDeviceFilter filter;
319
if (mType == HostType)
321
CHost host = vboxGlobal().virtualBox().GetHost();
322
CHostUSBDeviceFilter hostFilter = host
323
.CreateUSBDeviceFilter (mUSBFilterName.arg (maxFilterIndex + 1));
324
hostFilter.SetAction (KUSBDeviceFilterAction_Hold);
327
else if (mType == MachineType)
329
CUSBController ctl = mMachine.GetUSBController();
332
filter = ctl.CreateDeviceFilter (mUSBFilterName.arg (maxFilterIndex + 1));
336
AssertMsgFailed (("Invalid VBoxVMSettingsUSB type"));
339
filter.SetActive (true);
340
addUSBFilter (filter, true /* isNew */);
342
mUSBFilterListModified = true;
345
void VBoxVMSettingsUSB::addClicked()
347
mUSBDevicesMenu->exec (QCursor::pos());
350
void VBoxVMSettingsUSB::addConfirmed (QAction *aAction)
352
CUSBDevice usb = mUSBDevicesMenu->getUSB (aAction);
353
/* if null then some other item but a USB device is selected */
357
/* Creating new usb filter */
358
CUSBDeviceFilter filter;
360
if (mType == HostType)
362
CHost host = vboxGlobal().virtualBox().GetHost();
363
CHostUSBDeviceFilter hostFilter = host
364
.CreateUSBDeviceFilter (vboxGlobal().details (usb));
365
hostFilter.SetAction (KUSBDeviceFilterAction_Hold);
368
else if (mType == MachineType)
370
CUSBController ctl = mMachine.GetUSBController();
373
filter = ctl.CreateDeviceFilter (vboxGlobal().details (usb));
377
AssertMsgFailed (("Invalid VBoxVMSettingsUSB type"));
380
filter.SetVendorId (QString().sprintf ("%04hX", usb.GetVendorId()));
381
filter.SetProductId (QString().sprintf ("%04hX", usb.GetProductId()));
382
filter.SetRevision (QString().sprintf ("%04hX", usb.GetRevision()));
383
/* The port property depends on the host computer rather than on the USB
384
* device itself; for this reason only a few people will want to use it
385
* in the filter since the same device plugged into a different socket
386
* will not match the filter in this case. */
388
/// @todo set it anyway if Alt is currently pressed
389
filter.SetPort (QString().sprintf ("%04hX", usb.GetPort()));
391
filter.SetManufacturer (usb.GetManufacturer());
392
filter.SetProduct (usb.GetProduct());
393
filter.SetSerialNumber (usb.GetSerialNumber());
394
filter.SetRemote (usb.GetRemote() ? "yes" : "no");
396
filter.SetActive (true);
397
addUSBFilter (filter, true /* isNew */);
399
mUSBFilterListModified = true;
402
void VBoxVMSettingsUSB::edtClicked()
404
QTreeWidgetItem *item = mTwFilters->currentItem();
407
VBoxVMSettingsUSBFilterDetails fd (mType, this);
409
CUSBDeviceFilter filter =
410
mFilters [mTwFilters->indexOfTopLevelItem (item)];
412
fd.mLeName->setText (filter.isNull() ? QString::null : filter.GetName());
413
fd.mLeVendorID->setText (filter.isNull() ? QString::null : filter.GetVendorId());
414
fd.mLeProductID->setText (filter.isNull() ? QString::null : filter.GetProductId());
415
fd.mLeRevision->setText (filter.isNull() ? QString::null : filter.GetRevision());
416
fd.mLePort->setText (filter.isNull() ? QString::null : filter.GetPort());
417
fd.mLeManufacturer->setText (filter.isNull() ? QString::null : filter.GetManufacturer());
418
fd.mLeProduct->setText (filter.isNull() ? QString::null : filter.GetProduct());
419
fd.mLeSerialNo->setText (filter.isNull() ? QString::null : filter.GetSerialNumber());
425
QString remote = filter.isNull() ? QString::null : filter.GetRemote().toLower();
426
if (remote == "yes" || remote == "true" || remote == "1")
427
fd.mCbRemote->setCurrentIndex (ModeOn);
428
else if (remote == "no" || remote == "false" || remote == "0")
429
fd.mCbRemote->setCurrentIndex (ModeOff);
431
fd.mCbRemote->setCurrentIndex (ModeAny);
436
CHostUSBDeviceFilter hostFilter (filter);
437
KUSBDeviceFilterAction action = hostFilter.isNull() ?
438
KUSBDeviceFilterAction_Ignore : hostFilter.GetAction();
439
if (action == KUSBDeviceFilterAction_Ignore)
440
fd.mCbAction->setCurrentIndex (0);
441
else if (action == KUSBDeviceFilterAction_Hold)
442
fd.mCbAction->setCurrentIndex (1);
444
AssertMsgFailed (("Invalid USBDeviceFilterAction type"));
449
AssertMsgFailed (("Invalid VBoxVMSettingsUSB type"));
454
if (fd.exec() == QDialog::Accepted)
456
filter.SetName (fd.mLeName->text().isEmpty() ? QString::null : fd.mLeName->text());
457
item->setText (twUSBFilters_Name, fd.mLeName->text());
458
filter.SetVendorId (fd.mLeVendorID->text().isEmpty() ? QString::null : fd.mLeVendorID->text());
459
filter.SetProductId (fd.mLeProductID->text().isEmpty() ? QString::null : fd.mLeProductID->text());
460
filter.SetRevision (fd.mLeRevision->text().isEmpty() ? QString::null : fd.mLeRevision->text());
461
filter.SetManufacturer (fd.mLeManufacturer->text().isEmpty() ? QString::null : fd.mLeManufacturer->text());
462
filter.SetProduct (fd.mLeProduct->text().isEmpty() ? QString::null : fd.mLeProduct->text());
463
filter.SetSerialNumber (fd.mLeSerialNo->text().isEmpty() ? QString::null : fd.mLeSerialNo->text());
464
filter.SetPort (fd.mLePort->text().isEmpty() ? QString::null : fd.mLePort->text());
465
if (mType == MachineType)
467
switch (fd.mCbRemote->currentIndex())
469
case ModeAny: filter.SetRemote (QString::null); break;
470
case ModeOn: filter.SetRemote ("yes"); break;
471
case ModeOff: filter.SetRemote ("no"); break;
472
default: AssertMsgFailed (("Invalid combo box index"));
476
if (mType == HostType)
478
CHostUSBDeviceFilter hostFilter (filter);
479
hostFilter.SetAction (vboxGlobal().toUSBDevFilterAction (fd.mCbAction->currentText()));
481
item->setToolTip (0, vboxGlobal().toolTip (filter));
485
void VBoxVMSettingsUSB::delClicked()
487
QTreeWidgetItem *item = mTwFilters->currentItem();
489
int index = mTwFilters->indexOfTopLevelItem (item);
492
mFilters.removeAt (index);
494
/* Setup validators */
495
if (!mTwFilters->topLevelItemCount())
499
mValidator->rescan();
500
mValidator->revalidate();
504
currentChanged (mTwFilters->currentItem());
505
mUSBFilterListModified = true;
508
void VBoxVMSettingsUSB::mupClicked()
510
QTreeWidgetItem *item = mTwFilters->currentItem();
513
int index = mTwFilters->indexOfTopLevelItem (item);
514
QTreeWidgetItem *takenItem = mTwFilters->takeTopLevelItem (index);
515
Assert (item == takenItem);
516
mTwFilters->insertTopLevelItem (index - 1, takenItem);
517
mFilters.swap (index, index - 1);
519
mTwFilters->setCurrentItem (takenItem);
520
mUSBFilterListModified = true;
523
void VBoxVMSettingsUSB::mdnClicked()
525
QTreeWidgetItem *item = mTwFilters->currentItem();
528
int index = mTwFilters->indexOfTopLevelItem (item);
529
QTreeWidgetItem *takenItem = mTwFilters->takeTopLevelItem (index);
530
Assert (item == takenItem);
531
mTwFilters->insertTopLevelItem (index + 1, takenItem);
532
mFilters.swap (index, index + 1);
534
mTwFilters->setCurrentItem (takenItem);
535
mUSBFilterListModified = true;
538
void VBoxVMSettingsUSB::showContextMenu (const QPoint &aPos)
540
mMenu->exec (mTwFilters->mapToGlobal (aPos));
543
void VBoxVMSettingsUSB::addUSBFilter (const CUSBDeviceFilter &aFilter,
546
QTreeWidgetItem *currentItem = isNew ?
547
mTwFilters->currentItem() :
548
mTwFilters->topLevelItem (mTwFilters->topLevelItemCount() - 1);
550
int pos = currentItem ? mTwFilters->indexOfTopLevelItem (currentItem) : -1;
551
mFilters.insert (pos + 1, aFilter);
553
QTreeWidgetItem *item = pos >= 0 ?
554
new QTreeWidgetItem (mTwFilters, mTwFilters->topLevelItem (pos)) :
555
new QTreeWidgetItem (mTwFilters);
556
item->setCheckState (0, aFilter.GetActive() ? Qt::Checked : Qt::Unchecked);
557
item->setText (twUSBFilters_Name, aFilter.GetName());
558
item->setToolTip (0, vboxGlobal().toolTip (aFilter));
561
mTwFilters->setCurrentItem (item);
564
mValidator->revalidate();