VirtualBox

Changeset 95277 in vbox for trunk/src


Ignore:
Timestamp:
Jun 14, 2022 12:06:41 PM (3 years ago)
Author:
vboxsync
Message:

FE/Qt/Ds: bugref:6899: Machine settings: USB page accessibility improvements (part 3); Moving USB filters stuff into separate UIUSBFiltersEditor widget.

Location:
trunk/src/VBox/Frontends/VirtualBox
Files:
4 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk

    r95247 r95277  
    935935        src/settings/editors/UIUSBControllerEditor.h \
    936936        src/settings/editors/UIUSBFilterDetailsEditor.h \
     937        src/settings/editors/UIUSBFiltersEditor.h \
    937938        src/settings/editors/UIVideoMemoryEditor.h \
    938939        src/settings/editors/UIVirtualCPUEditor.h \
     
    10911092        src/settings/editors/UISharedFoldersEditor.cpp \
    10921093        src/settings/editors/UIShortcutConfigurationEditor.cpp \
     1094        src/settings/editors/UIUSBFiltersEditor.cpp \
    10931095        src/settings/machine/UIMachineSettingsNetwork.cpp \
    10941096        src/settings/machine/UIMachineSettingsSerial.cpp \
    10951097        src/settings/machine/UIMachineSettingsStorage.cpp \
    1096         src/settings/machine/UIMachineSettingsUSB.cpp \
    10971098        src/widgets/UIAddDiskEncryptionPasswordDialog.cpp \
    10981099        src/widgets/UIFilmContainer.cpp \
     
    15131514        src/settings/editors/UIUSBControllerEditor.cpp \
    15141515        src/settings/editors/UIUSBFilterDetailsEditor.cpp \
     1516        src/settings/editors/UIUSBFiltersEditor.cpp \
    15151517        src/settings/editors/UIVideoMemoryEditor.cpp \
    15161518        src/settings/editors/UIVirtualCPUEditor.cpp \
  • trunk/src/VBox/Frontends/VirtualBox/src/settings/editors/UISharedFoldersEditor.cpp

    r95129 r95277  
    269269    : QIWithRetranslateUI<QWidget>(pParent)
    270270    , m_pLabelSeparator(0)
     271    , m_pLayoutTree(0)
    271272    , m_pTreeWidget(0)
     273    , m_pToolbar(0)
     274    , m_pActionAdd(0)
     275    , m_pActionEdit(0)
     276    , m_pActionRemove(0)
    272277{
    273278    prepare();
     
    363368        m_pActionAdd->setText(tr("Add Shared Folder"));
    364369        m_pActionAdd->setToolTip(tr("Adds new shared folder."));
    365         m_pActionAdd->setToolTip(m_pActionAdd->whatsThis());
    366370    }
    367371    if (m_pActionEdit)
     
    369373        m_pActionEdit->setText(tr("Edit Shared Folder"));
    370374        m_pActionEdit->setToolTip(tr("Edits selected shared folder."));
    371         m_pActionEdit->setToolTip(m_pActionEdit->whatsThis());
    372375    }
    373376    if (m_pActionRemove)
     
    375378        m_pActionRemove->setText(tr("Remove Shared Folder"));
    376379        m_pActionRemove->setToolTip(tr("Removes selected shared folder."));
    377         m_pActionRemove->setToolTip(m_pActionRemove->whatsThis());
    378380    }
    379381}
  • trunk/src/VBox/Frontends/VirtualBox/src/settings/editors/UIUSBFiltersEditor.cpp

    r95276 r95277  
    11/* $Id$ */
    22/** @file
    3  * VBox Qt GUI - UISharedFoldersEditor class implementation.
     3 * VBox Qt GUI - UIUSBFiltersEditor class implementation.
    44 */
    55
     
    2020#include <QMenu>
    2121#include <QRegExp>
    22 #include <QTimer>
     22#include <QToolTip>
    2323#include <QVBoxLayout>
    2424
     
    2727#include "QIToolBar.h"
    2828#include "QITreeWidget.h"
     29#include "UICommon.h"
    2930#include "UIIconPool.h"
    30 #include "UISharedFolderDetailsEditor.h"
    31 #include "UISharedFoldersEditor.h"
    32 #include "VBoxUtils.h"
     31#include "UIUSBFilterDetailsEditor.h"
     32#include "UIUSBFiltersEditor.h"
     33
     34/* COM includes: */
     35#include "CConsole.h"
     36#include "CHostUSBDevice.h"
     37#include "CUSBDevice.h"
    3338
    3439/* Other VBox includes: */
    3540#include "iprt/assert.h"
    3641
    37 
    38 /** Shared Folder tree-widget item. */
    39 class SFTreeViewItem : public QITreeWidgetItem, public UIDataSharedFolder
     42/* VirtualBox interface declarations: */
     43#include <VBox/com/VirtualBox.h>
     44
     45
     46/** USB Filter tree-widget item. */
     47class USBFilterTreeWidgetItem : public QITreeWidgetItem, public UIDataUSBFilter
    4048{
    4149    Q_OBJECT;
     
    4351public:
    4452
    45     /** Format type. */
    46     enum FormatType
    47     {
    48         FormatType_Invalid,
    49         FormatType_EllipsisStart,
    50         FormatType_EllipsisMiddle,
    51         FormatType_EllipsisEnd,
    52         FormatType_EllipsisFile
    53     };
    54 
    55     /** Constructs shared folder type (root) item.
    56       * @param  pParent    Brings the item parent.
    57       * @param  enmFormat  Brings the item format type. */
    58     SFTreeViewItem(QITreeWidget *pParent, FormatType enmFormat);
    59     /** Constructs shared folder (child) item.
    60       * @param  pParent    Brings the item parent.
    61       * @param  enmFormat  Brings the item format type. */
    62     SFTreeViewItem(SFTreeViewItem *pParent, FormatType enmFormat);
    63 
    64     /** Returns whether this item is less than the @a other one. */
    65     bool operator<(const QTreeWidgetItem &other) const;
    66 
    67     /** Returns child item number @a iIndex. */
    68     SFTreeViewItem *child(int iIndex) const;
    69 
    70     /** Returns text of item number @a iIndex. */
    71     QString getText(int iIndex) const;
     53    /** Constructs USB filter type (root) item. */
     54    USBFilterTreeWidgetItem(QITreeWidget *pParent) : QITreeWidgetItem(pParent) {}
    7255
    7356    /** Updates item fields. */
    7457    void updateFields();
    7558
    76     /** Adjusts item layout. */
    77     void adjustText();
    78 
    7959protected:
    8060
    8161    /** Returns default text. */
    8262    virtual QString defaultText() const RT_OVERRIDE;
     63};
     64
     65
     66/** USB Filter popup menu. */
     67class UIUSBMenu : public QMenu
     68{
     69    Q_OBJECT;
     70
     71public:
     72
     73    /** Constructs USB Filter menu passing @a pParent to the base-class. */
     74    UIUSBMenu(QWidget *pParent);
     75
     76    /** Returns USB device related to passed action. */
     77    const CUSBDevice& getUSB(QAction *pAction);
     78
     79    /** Defines @a comConsole. */
     80    void setConsole(const CConsole &comConsole);
     81
     82protected:
     83
     84    /** Handles any @a pEvent handler. */
     85    virtual bool event(QEvent *pEvent) RT_OVERRIDE;
     86
     87private slots:
     88
     89    /** Prepares menu contents. */
     90    void processAboutToShow();
    8391
    8492private:
    8593
    86     /** Performs item @a iColumn processing. */
    87     void processColumn(int iColumn);
    88 
    89     /** Holds the item format type. */
    90     FormatType   m_enmFormat;
    91     /** Holds the item text fields. */
    92     QStringList  m_fields;
     94    /** Holds the USB device map. */
     95    QMap<QAction*, CUSBDevice>  m_usbDeviceMap;
     96
     97    /** Holds the console. */
     98    CConsole  m_comConsole;
    9399};
    94100
    95101
    96102/*********************************************************************************************************************************
    97 *   Class SFTreeViewItem implementation.                                                                                         *
     103*   Class USBFilterTreeWidgetItem implementation.                                                                                *
    98104*********************************************************************************************************************************/
    99105
    100 SFTreeViewItem::SFTreeViewItem(QITreeWidget *pParent, FormatType enmFormat)
    101     : QITreeWidgetItem(pParent)
    102     , m_enmFormat(enmFormat)
    103 {
    104     setFirstColumnSpanned(true);
    105     setFlags(flags() ^ Qt::ItemIsSelectable);
    106 }
    107 
    108 SFTreeViewItem::SFTreeViewItem(SFTreeViewItem *pParent, FormatType enmFormat)
    109     : QITreeWidgetItem(pParent)
    110     , m_enmFormat(enmFormat)
    111 {
    112 }
    113 
    114 bool SFTreeViewItem::operator<(const QTreeWidgetItem &other) const
    115 {
    116     /* Root items should always been sorted by type field: */
    117     return parentItem() ? text(0) < other.text(0) :
    118                           text(1) < other.text(1);
    119 }
    120 
    121 SFTreeViewItem *SFTreeViewItem::child(int iIndex) const
    122 {
    123     QTreeWidgetItem *pItem = QTreeWidgetItem::child(iIndex);
    124     return pItem ? static_cast<SFTreeViewItem*>(pItem) : 0;
    125 }
    126 
    127 QString SFTreeViewItem::getText(int iIndex) const
    128 {
    129     return iIndex >= 0 && iIndex < m_fields.size() ? m_fields.at(iIndex) : QString();
    130 }
    131 
    132 void SFTreeViewItem::updateFields()
    133 {
    134     /* Clear fields: */
    135     m_fields.clear();
    136 
    137     /* For root items: */
    138     if (!parentItem())
    139         m_fields << m_strName
    140                  << QString::number((int)m_enmType);
    141     /* For child items: */
     106void USBFilterTreeWidgetItem::updateFields()
     107{
     108    setText(0, m_strName);
     109}
     110
     111QString USBFilterTreeWidgetItem::defaultText() const
     112{
     113    return   checkState(0) == Qt::Checked
     114           ? tr("%1, Active", "col.1 text, col.1 state").arg(text(0))
     115           : tr("%1",         "col.1 text")             .arg(text(0));
     116}
     117
     118
     119/*********************************************************************************************************************************
     120*   Class UIUSBMenu implementation.                                                                                              *
     121*********************************************************************************************************************************/
     122
     123UIUSBMenu::UIUSBMenu(QWidget *)
     124{
     125    connect(this, &UIUSBMenu::aboutToShow,
     126            this, &UIUSBMenu::processAboutToShow);
     127}
     128
     129const CUSBDevice &UIUSBMenu::getUSB(QAction *pAction)
     130{
     131    return m_usbDeviceMap[pAction];
     132}
     133
     134void UIUSBMenu::setConsole(const CConsole &comConsole)
     135{
     136    m_comConsole = comConsole;
     137}
     138
     139bool UIUSBMenu::event(QEvent *pEvent)
     140{
     141    /* We provide dynamic tooltips for the usb devices: */
     142    if (pEvent->type() == QEvent::ToolTip)
     143    {
     144        QHelpEvent *pHelpEvent = static_cast<QHelpEvent*>(pEvent);
     145        QAction *pAction = actionAt(pHelpEvent->pos());
     146        if (pAction)
     147        {
     148            CUSBDevice usb = m_usbDeviceMap[pAction];
     149            if (!usb.isNull())
     150            {
     151                QToolTip::showText(pHelpEvent->globalPos(), uiCommon().usbToolTip(usb));
     152                return true;
     153            }
     154        }
     155    }
     156    /* Call to base-class: */
     157    return QMenu::event(pEvent);
     158}
     159
     160void UIUSBMenu::processAboutToShow()
     161{
     162    /* Clear lists initially: */
     163    clear();
     164    m_usbDeviceMap.clear();
     165
     166    /* Get host for further activities: */
     167    CHost comHost = uiCommon().host();
     168
     169    /* Check whether we have host USB devices at all: */
     170    bool fIsUSBEmpty = comHost.GetUSBDevices().size() == 0;
     171    if (fIsUSBEmpty)
     172    {
     173        /* Empty action for no USB device case: */
     174        QAction *pAction = addAction(tr("<no devices available>", "USB devices"));
     175        pAction->setEnabled(false);
     176        pAction->setToolTip(tr("No supported devices connected to the host PC", "USB device tooltip"));
     177    }
    142178    else
    143         m_fields << m_strName
    144                  << m_strPath
    145                  << (m_fWritable ? tr("Full") : tr("Read-only"))
    146                  << (m_fAutoMount ? tr("Yes") : "")
    147                  << m_strAutoMountPoint;
    148 
    149     /* Adjust item layout: */
    150     adjustText();
    151 }
    152 
    153 void SFTreeViewItem::adjustText()
    154 {
    155     for (int i = 0; i < treeWidget()->columnCount(); ++i)
    156         processColumn(i);
    157 }
    158 
    159 QString SFTreeViewItem::defaultText() const
    160 {
    161     return parentItem()
    162          ? tr("%1, %2: %3, %4: %5, %6: %7, %8: %9",
    163               "col.1 text, col.2 name: col.2 text, col.3 name: col.3 text, col.4 name: col.4 text, col.5 name: col.5 text")
    164               .arg(text(0))
    165               .arg(parentTree()->headerItem()->text(1)).arg(text(1))
    166               .arg(parentTree()->headerItem()->text(2)).arg(text(2))
    167               .arg(parentTree()->headerItem()->text(3)).arg(text(3))
    168               .arg(parentTree()->headerItem()->text(4)).arg(text(4))
    169          : text(0);
    170 }
    171 
    172 void SFTreeViewItem::processColumn(int iColumn)
    173 {
    174     QString strOneString = getText(iColumn);
    175     if (strOneString.isNull())
    176         return;
    177     const QFontMetrics fm = treeWidget()->fontMetrics();
    178 #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
    179     const int iOldSize = fm.horizontalAdvance(strOneString);
    180 #else
    181     const int iOldSize = fm.width(strOneString);
    182 #endif
    183     const int iItemIndent = parentItem() ? treeWidget()->indentation() * 2 : treeWidget()->indentation();
    184 #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
    185     int iIndentSize = fm.horizontalAdvance(" ... ");
    186 #else
    187     int iIndentSize = fm.width(" ... ");
    188 #endif
    189     if (iColumn == 0)
    190         iIndentSize += iItemIndent;
    191     const int cWidth = !parentItem() ? treeWidget()->viewport()->width() : treeWidget()->columnWidth(iColumn);
    192 
    193     /* Compress text: */
    194     int iStart = 0;
    195     int iFinish = 0;
    196     int iPosition = 0;
    197     int iTextWidth = 0;
    198     do
    199     {
    200 #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
    201         iTextWidth = fm.horizontalAdvance(strOneString);
    202 #else
    203         iTextWidth = fm.width(strOneString);
    204 #endif
    205         if (   iTextWidth
    206             && iTextWidth + iIndentSize > cWidth)
     179    {
     180        /* Action per each host USB device: */
     181        foreach (const CHostUSBDevice &comHostUsb, comHost.GetUSBDevices())
    207182        {
    208             iStart = 0;
    209             iFinish = strOneString.length();
    210 
    211             /* Selecting remove position: */
    212             switch (m_enmFormat)
     183            CUSBDevice comUsb(comHostUsb);
     184            QAction *pAction = addAction(uiCommon().usbDetails(comUsb));
     185            pAction->setCheckable(true);
     186            m_usbDeviceMap[pAction] = comUsb;
     187            /* Check if created item was already attached to this session: */
     188            if (!m_comConsole.isNull())
    213189            {
    214                 case FormatType_EllipsisStart:
    215                     iPosition = iStart;
    216                     break;
    217                 case FormatType_EllipsisMiddle:
    218                     iPosition = (iFinish - iStart) / 2;
    219                     break;
    220                 case FormatType_EllipsisEnd:
    221                     iPosition = iFinish - 1;
    222                     break;
    223                 case FormatType_EllipsisFile:
    224                 {
    225                     const QRegExp regExp("([\\\\/][^\\\\^/]+[\\\\/]?$)");
    226                     const int iNewFinish = regExp.indexIn(strOneString);
    227                     if (iNewFinish != -1)
    228                         iFinish = iNewFinish;
    229                     iPosition = (iFinish - iStart) / 2;
    230                     break;
    231                 }
    232                 default:
    233                     AssertMsgFailed(("Invalid format type\n"));
     190                CUSBDevice attachedUSB = m_comConsole.FindUSBDeviceById(comUsb.GetId());
     191                pAction->setChecked(!attachedUSB.isNull());
     192                pAction->setEnabled(comHostUsb.GetState() != KUSBDeviceState_Unavailable);
    234193            }
    235 
    236             if (iPosition == iFinish)
    237                break;
    238 
    239             strOneString.remove(iPosition, 1);
    240194        }
    241195    }
    242     while (   iTextWidth
    243            && (iTextWidth + iIndentSize > cWidth));
    244 
    245     if (iPosition || m_enmFormat == FormatType_EllipsisFile)
    246         strOneString.insert(iPosition, "...");
    247 #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
    248     const int iNewSize = fm.horizontalAdvance(strOneString);
    249 #else
    250     const int iNewSize = fm.width(strOneString);
    251 #endif
    252     setText(iColumn, iNewSize < iOldSize ? strOneString : m_fields.at(iColumn));
    253     setToolTip(iColumn, text(iColumn) == getText(iColumn) ? QString() : getText(iColumn));
    254 
    255     /* Calculate item's size-hint: */
    256 #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
    257     setSizeHint(iColumn, QSize(fm.horizontalAdvance(QString("  %1  ").arg(getText(iColumn))), fm.height()));
    258 #else
    259     setSizeHint(iColumn, QSize(fm.width(QString("  %1  ").arg(getText(iColumn))), fm.height()));
    260 #endif
    261196}
    262197
    263198
    264199/*********************************************************************************************************************************
    265 *   Class UISharedFoldersEditor implementation.                                                                                  *
     200*   Class UIUSBFiltersEditor implementation.                                                                                     *
    266201*********************************************************************************************************************************/
    267202
    268 UISharedFoldersEditor::UISharedFoldersEditor(QWidget *pParent /* = 0 */)
     203UIUSBFiltersEditor::UIUSBFiltersEditor(QWidget *pParent /* = 0 */)
    269204    : QIWithRetranslateUI<QWidget>(pParent)
    270205    , m_pLabelSeparator(0)
     206    , m_pLayoutTree(0)
    271207    , m_pTreeWidget(0)
     208    , m_pToolbar(0)
     209    , m_pActionNew(0)
     210    , m_pActionAdd(0)
     211    , m_pActionEdit(0)
     212    , m_pActionRemove(0)
     213    , m_pActionMoveUp(0)
     214    , m_pActionMoveDown(0)
     215    , m_pMenuUSBDevices(0)
    272216{
    273217    prepare();
    274218}
    275219
    276 void UISharedFoldersEditor::setValue(const QList<UIDataSharedFolder> &guiValue)
     220void UIUSBFiltersEditor::setValue(const QList<UIDataUSBFilter> &guiValue)
    277221{
    278222    /* Update cached value and
     
    285229}
    286230
    287 QList<UIDataSharedFolder> UISharedFoldersEditor::value() const
     231QList<UIDataUSBFilter> UIUSBFiltersEditor::value() const
    288232{
    289233    /* Sanity check: */
     
    292236
    293237    /* Prepare result: */
    294     QList<UIDataSharedFolder> result;
    295 
    296     /* For each folder type: */
     238    QList<UIDataUSBFilter> result;
     239
     240    /* For each filter: */
    297241    QTreeWidgetItem *pMainRootItem = m_pTreeWidget->invisibleRootItem();
    298     for (int iFolderTypeIndex = 0; iFolderTypeIndex < pMainRootItem->childCount(); ++iFolderTypeIndex)
    299     {
    300         /* Get folder root item: */
    301         const SFTreeViewItem *pFolderTypeRoot = static_cast<SFTreeViewItem*>(pMainRootItem->child(iFolderTypeIndex));
    302 
    303         /* For each folder of current type: */
    304         for (int iFolderIndex = 0; iFolderIndex < pFolderTypeRoot->childCount(); ++iFolderIndex)
    305         {
    306             /* Gather and cache new data: */
    307             const SFTreeViewItem *pItem = static_cast<SFTreeViewItem*>(pFolderTypeRoot->child(iFolderIndex));
    308             result << *pItem;
    309         }
     242    for (int iFilterIndex = 0; iFilterIndex < pMainRootItem->childCount(); ++iFilterIndex)
     243    {
     244        /* Gather and cache new data: */
     245        const USBFilterTreeWidgetItem *pItem = static_cast<USBFilterTreeWidgetItem*>(pMainRootItem->child(iFilterIndex));
     246        result << *pItem;
    310247    }
    311248
     
    314251}
    315252
    316 void UISharedFoldersEditor::setFeatureAvailable(bool fAvailable)
    317 {
    318     if (m_pLabelSeparator)
    319         m_pLabelSeparator->setEnabled(fAvailable);
    320     if (m_pTreeWidget)
    321         m_pTreeWidget->setEnabled(fAvailable);
    322     if (m_pToolbar)
    323         m_pToolbar->setEnabled(fAvailable);
    324 }
    325 
    326 void UISharedFoldersEditor::setFoldersAvailable(UISharedFolderType enmType, bool fAvailable)
    327 {
    328     m_foldersAvailable[enmType] = fAvailable;
    329     updateRootItemsVisibility();
    330 }
    331 
    332 void UISharedFoldersEditor::retranslateUi()
    333 {
     253void UIUSBFiltersEditor::retranslateUi()
     254{
     255    /* Tags: */
     256    m_strTrUSBFilterName = tr("New Filter %1", "usb");
     257
    334258    /* Translate separator label: */
    335259    if (m_pLabelSeparator)
    336         m_pLabelSeparator->setText(tr("Shared &Folders"));
     260        m_pLabelSeparator->setText(tr("USB Device &Filters"));
    337261
    338262    /* Translate tree-widget: */
    339263    if (m_pTreeWidget)
    340     {
    341         m_pTreeWidget->setWhatsThis(tr("Lists all shared folders accessible to this machine. Use 'net use x: \\\\vboxsvr\\share' "
    342                                        "to access a shared folder named <i>share</i> from a DOS-like OS, or 'mount -t vboxsf "
    343                                        "share mount_point' to access it from a Linux OS. This feature requires Guest Additions."));
    344 
    345         /* Translate tree-widget header: */
    346         QTreeWidgetItem *pTreeWidgetHeaderItem = m_pTreeWidget->headerItem();
    347         if (pTreeWidgetHeaderItem)
    348         {
    349             pTreeWidgetHeaderItem->setText(4, tr("At"));
    350             pTreeWidgetHeaderItem->setText(3, tr("Auto Mount"));
    351             pTreeWidgetHeaderItem->setText(2, tr("Access"));
    352             pTreeWidgetHeaderItem->setText(1, tr("Path"));
    353             pTreeWidgetHeaderItem->setText(0, tr("Name"));
    354         }
    355 
    356         /* Update tree-widget contents finally: */
    357         reloadTree();
    358     }
     264        m_pTreeWidget->setWhatsThis(tr("Lists all USB filters of this machine. The checkbox to the left defines whether the "
     265                                       "particular filter is enabled or not. Use the context menu or buttons to the right to "
     266                                       "add or remove USB filters."));
    359267
    360268    /* Translate actions: */
     269    if (m_pActionNew)
     270    {
     271        m_pActionNew->setText(tr("Add Empty Filter"));
     272        m_pActionNew->setToolTip(tr("Adds new USB filter with all fields initially set to empty strings. "
     273                                    "Note that such a filter will match any attached USB device."));
     274    }
    361275    if (m_pActionAdd)
    362276    {
    363         m_pActionAdd->setText(tr("Add Shared Folder"));
    364         m_pActionAdd->setToolTip(tr("Adds new shared folder."));
    365         m_pActionAdd->setToolTip(m_pActionAdd->whatsThis());
     277        m_pActionAdd->setText(tr("Add Filter From Device"));
     278        m_pActionAdd->setToolTip(tr("Adds new USB filter with all fields set to the values of the "
     279                                "selected USB device attached to the host PC."));
    366280    }
    367281    if (m_pActionEdit)
    368282    {
    369         m_pActionEdit->setText(tr("Edit Shared Folder"));
    370         m_pActionEdit->setToolTip(tr("Edits selected shared folder."));
    371         m_pActionEdit->setToolTip(m_pActionEdit->whatsThis());
     283        m_pActionEdit->setText(tr("Edit Filter"));
     284        m_pActionEdit->setToolTip(tr("Edits selected USB filter."));
    372285    }
    373286    if (m_pActionRemove)
    374287    {
    375         m_pActionRemove->setText(tr("Remove Shared Folder"));
    376         m_pActionRemove->setToolTip(tr("Removes selected shared folder."));
    377         m_pActionRemove->setToolTip(m_pActionRemove->whatsThis());
    378     }
    379 }
    380 
    381 void UISharedFoldersEditor::showEvent(QShowEvent *pEvent)
    382 {
    383     /* Call to base-class: */
    384     QIWithRetranslateUI<QWidget>::showEvent(pEvent);
    385 
    386     /* Connect header-resize signal just before widget is shown
    387      * after all the items properly loaded and initialized: */
    388     connect(m_pTreeWidget->header(), &QHeaderView::sectionResized,
    389             this, &UISharedFoldersEditor::sltAdjustTreeFields,
    390             Qt::UniqueConnection);
    391 
    392     /* Adjusting size after all pending show events are processed: */
    393     QTimer::singleShot(0, this, SLOT(sltAdjustTree()));
    394 }
    395 
    396 void UISharedFoldersEditor::resizeEvent(QResizeEvent * /* pEvent */)
    397 {
    398     sltAdjustTree();
    399 }
    400 
    401 void UISharedFoldersEditor::sltAdjustTree()
    402 {
    403     /*
    404      * Calculates required columns sizes to max out column 2
    405      * and let all other columns stay at their minimum sizes.
    406      *
    407      * Columns
    408      * 0 = Tree view / name
    409      * 1 = Path
    410      * 2 = Writable flag
    411      * 3 = Auto-mount flag
    412      * 4 = Auto mount point
    413      */
    414     QAbstractItemView *pItemView = m_pTreeWidget;
    415     QHeaderView *pItemHeader = m_pTreeWidget->header();
    416     const int iTotal = m_pTreeWidget->viewport()->width();
    417 
    418     const int mw0 = qMax(pItemView->sizeHintForColumn(0), pItemHeader->sectionSizeHint(0));
    419     const int mw2 = qMax(pItemView->sizeHintForColumn(2), pItemHeader->sectionSizeHint(2));
    420     const int mw3 = qMax(pItemView->sizeHintForColumn(3), pItemHeader->sectionSizeHint(3));
    421     const int mw4 = qMax(pItemView->sizeHintForColumn(4), pItemHeader->sectionSizeHint(4));
    422 #if 0 /** @todo Neither approach is perfect.  Short folder names, short paths, plenty of white space, but there is often '...' in column 0. */
    423 
    424     const int w0 = mw0 < iTotal / 5 ? mw0 : iTotal / 5;
    425     const int w2 = mw2 < iTotal / 5 ? mw2 : iTotal / 5;
    426     const int w3 = mw3 < iTotal / 5 ? mw3 : iTotal / 5;
    427     const int w4 = mw4 < iTotal / 5 ? mw4 : iTotal / 5;
    428 
    429     /* Giving 1st column all the available space. */
    430     const int w1 = iTotal - w0 - w2 - w3 - w4;
    431 #else
    432     const int mw1 = qMax(pItemView->sizeHintForColumn(1), pItemHeader->sectionSizeHint(1));
    433     const int iHintTotal = mw0 + mw1 + mw2 + mw3 + mw4;
    434     int w0, w1, w2, w3, w4;
    435     int cExcess = iTotal - iHintTotal;
    436     if (cExcess >= 0)
    437     {
    438         /* give excess width to column 1 (path) */
    439         w0 = mw0;
    440         w1 = mw1 + cExcess;
    441         w2 = mw2;
    442         w3 = mw3;
    443         w4 = mw4;
    444     }
    445     else
    446     {
    447         w0 = mw0 < iTotal / 5 ? mw0 : iTotal / 5;
    448         w2 = mw2 < iTotal / 5 ? mw2 : iTotal / 5;
    449         w3 = mw3 < iTotal / 5 ? mw3 : iTotal / 5;
    450         w4 = mw4 < iTotal / 5 ? mw4 : iTotal / 5;
    451         w1 = iTotal - w0 - w2 - w3 - w4;
    452     }
    453 #endif
    454     m_pTreeWidget->setColumnWidth(0, w0);
    455     m_pTreeWidget->setColumnWidth(1, w1);
    456     m_pTreeWidget->setColumnWidth(2, w2);
    457     m_pTreeWidget->setColumnWidth(3, w3);
    458     m_pTreeWidget->setColumnWidth(4, w4);
    459 }
    460 
    461 void UISharedFoldersEditor::sltAdjustTreeFields()
    462 {
    463     QTreeWidgetItem *pMainRoot = m_pTreeWidget->invisibleRootItem();
    464     for (int i = 0; i < pMainRoot->childCount(); ++i)
    465     {
    466         SFTreeViewItem *pSubRoot = static_cast<SFTreeViewItem*>(pMainRoot->child(i));
    467         pSubRoot->adjustText();
    468         for (int j = 0; j < pSubRoot->childCount(); ++j)
    469         {
    470             SFTreeViewItem *pItem = static_cast<SFTreeViewItem*>(pSubRoot->child(j));
    471             pItem->adjustText();
    472         }
    473     }
    474 }
    475 
    476 void UISharedFoldersEditor::sltHandleCurrentItemChange(QTreeWidgetItem *pCurrentItem)
    477 {
    478     if (pCurrentItem && pCurrentItem->parent() && !pCurrentItem->isSelected())
     288        m_pActionRemove->setText(tr("Remove Filter"));
     289        m_pActionRemove->setToolTip(tr("Removes selected USB filter."));
     290    }
     291    if (m_pActionMoveUp)
     292    {
     293        m_pActionMoveUp->setText(tr("Move Filter Up"));
     294        m_pActionMoveUp->setToolTip(tr("Moves selected USB filter up."));
     295    }
     296    if (m_pActionMoveDown)
     297    {
     298        m_pActionMoveDown->setText(tr("Move Filter Down"));
     299        m_pActionMoveDown->setToolTip(tr("Moves selected USB filter down."));
     300    }
     301}
     302
     303void UIUSBFiltersEditor::sltHandleCurrentItemChange(QTreeWidgetItem *pCurrentItem)
     304{
     305    if (pCurrentItem && !pCurrentItem->isSelected())
    479306        pCurrentItem->setSelected(true);
    480     const bool fAddEnabled = pCurrentItem;
    481     const bool fRemoveEnabled = fAddEnabled && pCurrentItem->parent();
    482     m_pActionAdd->setEnabled(fAddEnabled);
    483     m_pActionEdit->setEnabled(fRemoveEnabled);
    484     m_pActionRemove->setEnabled(fRemoveEnabled);
    485 }
    486 
    487 void UISharedFoldersEditor::sltHandleDoubleClick(QTreeWidgetItem *pItem)
    488 {
    489     const bool fEditEnabled = pItem && pItem->parent();
    490     if (fEditEnabled)
    491         sltEditFolder();
    492 }
    493 
    494 void UISharedFoldersEditor::sltHandleContextMenuRequest(const QPoint &position)
     307    m_pActionEdit->setEnabled(pCurrentItem);
     308    m_pActionRemove->setEnabled(pCurrentItem);
     309    m_pActionMoveUp->setEnabled(pCurrentItem && m_pTreeWidget->itemAbove(pCurrentItem));
     310    m_pActionMoveDown->setEnabled(pCurrentItem && m_pTreeWidget->itemBelow(pCurrentItem));
     311}
     312
     313void UIUSBFiltersEditor::sltHandleDoubleClick(QTreeWidgetItem *pItem)
     314{
     315    AssertPtrReturnVoid(pItem);
     316    sltEditFilter();
     317}
     318
     319void UIUSBFiltersEditor::sltHandleContextMenuRequest(const QPoint &position)
    495320{
    496321    QMenu menu;
     
    500325        menu.addAction(m_pActionEdit);
    501326        menu.addAction(m_pActionRemove);
     327        menu.addSeparator();
     328        menu.addAction(m_pActionMoveUp);
     329        menu.addAction(m_pActionMoveDown);
    502330    }
    503331    else
    504332    {
     333        menu.addAction(m_pActionNew);
    505334        menu.addAction(m_pActionAdd);
    506335    }
     
    509338}
    510339
    511 void UISharedFoldersEditor::sltAddFolder()
    512 {
    513     /* Configure shared folder details editor: */
    514     UISharedFolderDetailsEditor dlgFolderDetails(UISharedFolderDetailsEditor::EditorType_Add,
    515                                                  m_foldersAvailable.value(UISharedFolderType_Console),
    516                                                  usedList(true),
    517                                                  this);
    518 
    519     /* Run folder details dialog: */
     340void UIUSBFiltersEditor::sltCreateFilter()
     341{
     342    /* Search for the max available filter index: */
     343    int iMaxFilterIndex = 0;
     344    const QRegExp regExp(QString("^") + m_strTrUSBFilterName.arg("([0-9]+)") + QString("$"));
     345    QTreeWidgetItemIterator iterator(m_pTreeWidget);
     346    while (*iterator)
     347    {
     348        const QString filterName = (*iterator)->text(0);
     349        const int pos = regExp.indexIn(filterName);
     350        if (pos != -1)
     351            iMaxFilterIndex = regExp.cap(1).toInt() > iMaxFilterIndex ?
     352                              regExp.cap(1).toInt() : iMaxFilterIndex;
     353        ++iterator;
     354    }
     355
     356    /* Prepare new data: */
     357    UIDataUSBFilter newFilterData;
     358    newFilterData.m_fActive = true;
     359    newFilterData.m_strName = m_strTrUSBFilterName.arg(iMaxFilterIndex + 1);
     360
     361    /* Add new filter item: */
     362    addUSBFilterItem(newFilterData, true /* its new? */);
     363
     364    /* Notify listeners: */
     365    emit sigValueChanged();
     366}
     367
     368void UIUSBFiltersEditor::sltAddFilter()
     369{
     370    m_pMenuUSBDevices->exec(QCursor::pos());
     371}
     372
     373void UIUSBFiltersEditor::sltAddFilterConfirmed(QAction *pAction)
     374{
     375    /* Get USB device: */
     376    const CUSBDevice comUsb = m_pMenuUSBDevices->getUSB(pAction);
     377    if (comUsb.isNull())
     378        return;
     379
     380    /* Prepare new USB filter data: */
     381    UIDataUSBFilter newFilterData;
     382    newFilterData.m_fActive = true;
     383    newFilterData.m_strName = uiCommon().usbDetails(comUsb);
     384    newFilterData.m_strVendorId  = QString::number(comUsb.GetVendorId(),  16).toUpper().rightJustified(4, '0');
     385    newFilterData.m_strProductId = QString::number(comUsb.GetProductId(), 16).toUpper().rightJustified(4, '0');
     386    newFilterData.m_strRevision  = QString::number(comUsb.GetRevision(),  16).toUpper().rightJustified(4, '0');
     387    /* The port property depends on the host computer rather than on the USB
     388     * device itself; for this reason only a few people will want to use it
     389     * in the filter since the same device plugged into a different socket
     390     * will not match the filter in this case. */
     391#if 0
     392    newFilterData.m_strPort = QString().sprintf("%04hX", comUsb.GetPort());
     393#endif
     394    newFilterData.m_strManufacturer = comUsb.GetManufacturer();
     395    newFilterData.m_strProduct = comUsb.GetProduct();
     396    newFilterData.m_strSerialNumber = comUsb.GetSerialNumber();
     397    newFilterData.m_enmRemoteMode = comUsb.GetRemote() ? UIRemoteMode_On : UIRemoteMode_Off;
     398
     399    /* Add new USB filter item: */
     400    addUSBFilterItem(newFilterData, true /* its new? */);
     401
     402    /* Notify listeners: */
     403    emit sigValueChanged();
     404}
     405
     406void UIUSBFiltersEditor::sltEditFilter()
     407{
     408    /* Check current filter item: */
     409    USBFilterTreeWidgetItem *pItem = static_cast<USBFilterTreeWidgetItem*>(m_pTreeWidget->currentItem());
     410    AssertPtrReturnVoid(pItem);
     411
     412    /* Configure USB filter details editor: */
     413    UIUSBFilterDetailsEditor dlgFolderDetails(this); /// @todo convey usedList!
     414    dlgFolderDetails.setName(pItem->m_strName);
     415    dlgFolderDetails.setVendorID(pItem->m_strVendorId);
     416    dlgFolderDetails.setProductID(pItem->m_strProductId);
     417    dlgFolderDetails.setRevision(pItem->m_strRevision);
     418    dlgFolderDetails.setManufacturer(pItem->m_strManufacturer);
     419    dlgFolderDetails.setProduct(pItem->m_strProduct);
     420    dlgFolderDetails.setSerialNo(pItem->m_strSerialNumber);
     421    dlgFolderDetails.setPort(pItem->m_strPort);
     422    dlgFolderDetails.setRemoteMode(pItem->m_enmRemoteMode);
     423
     424    /* Run filter details dialog: */
    520425    if (dlgFolderDetails.exec() == QDialog::Accepted)
    521426    {
    522         const QString strName = dlgFolderDetails.name();
    523         const QString strPath = dlgFolderDetails.path();
    524         const UISharedFolderType enmType = dlgFolderDetails.isPermanent() ? UISharedFolderType_Machine : UISharedFolderType_Console;
    525         /* Shared folder's name & path could not be empty: */
    526         Assert(!strName.isEmpty() && !strPath.isEmpty());
    527 
    528427        /* Prepare new data: */
    529         UIDataSharedFolder newFolderData;
    530         newFolderData.m_enmType = enmType;
    531         newFolderData.m_strName = strName;
    532         newFolderData.m_strPath = strPath;
    533         newFolderData.m_fWritable = dlgFolderDetails.isWriteable();
    534         newFolderData.m_fAutoMount = dlgFolderDetails.isAutoMounted();
    535         newFolderData.m_strAutoMountPoint = dlgFolderDetails.autoMountPoint();
    536 
    537         /* Add new folder item: */
    538         addSharedFolderItem(newFolderData, true /* its new? */);
    539 
    540         /* Sort tree-widget before adjusting: */
    541         m_pTreeWidget->sortItems(0, Qt::AscendingOrder);
    542         /* Adjust tree-widget finally: */
    543         sltAdjustTree();
    544     }
    545 }
    546 
    547 void UISharedFoldersEditor::sltEditFolder()
    548 {
    549     /* Check current folder item: */
    550     SFTreeViewItem *pItem = static_cast<SFTreeViewItem*>(m_pTreeWidget->currentItem());
    551     AssertPtrReturnVoid(pItem);
    552     AssertPtrReturnVoid(pItem->parentItem());
    553 
    554     /* Configure shared folder details editor: */
    555     UISharedFolderDetailsEditor dlgFolderDetails(UISharedFolderDetailsEditor::EditorType_Edit,
    556                                                  m_foldersAvailable.value(UISharedFolderType_Console),
    557                                                  usedList(false),
    558                                                  this);
    559     dlgFolderDetails.setPath(pItem->m_strPath);
    560     dlgFolderDetails.setName(pItem->m_strName);
    561     dlgFolderDetails.setPermanent(pItem->m_enmType == UISharedFolderType_Machine);
    562     dlgFolderDetails.setWriteable(pItem->m_fWritable);
    563     dlgFolderDetails.setAutoMount(pItem->m_fAutoMount);
    564     dlgFolderDetails.setAutoMountPoint(pItem->m_strAutoMountPoint);
    565 
    566     /* Run folder details dialog: */
    567     if (dlgFolderDetails.exec() == QDialog::Accepted)
    568     {
    569         const QString strName = dlgFolderDetails.name();
    570         const QString strPath = dlgFolderDetails.path();
    571         const UISharedFolderType enmType = dlgFolderDetails.isPermanent() ? UISharedFolderType_Machine : UISharedFolderType_Console;
    572         /* Shared folder's name & path could not be empty: */
    573         Assert(!strName.isEmpty() && !strPath.isEmpty());
    574 
    575         /* Update edited tree-widget item: */
    576         pItem->m_enmType = enmType;
    577         pItem->m_strName = strName;
    578         pItem->m_strPath = strPath;
    579         pItem->m_fWritable = dlgFolderDetails.isWriteable();
    580         pItem->m_fAutoMount = dlgFolderDetails.isAutoMounted();
    581         pItem->m_strAutoMountPoint = dlgFolderDetails.autoMountPoint();
     428        pItem->m_strName = dlgFolderDetails.name();
     429        pItem->m_strVendorId = dlgFolderDetails.vendorID();
     430        pItem->m_strProductId = dlgFolderDetails.productID();
     431        pItem->m_strRevision = dlgFolderDetails.revision();
     432        pItem->m_strManufacturer = dlgFolderDetails.manufacturer();
     433        pItem->m_strProduct = dlgFolderDetails.product();
     434        pItem->m_strSerialNumber = dlgFolderDetails.serialNo();
     435        pItem->m_strPort = dlgFolderDetails.port();
     436        pItem->m_enmRemoteMode = dlgFolderDetails.remoteMode();
    582437        pItem->updateFields();
    583438
    584         /* Searching for a root of the edited tree-widget item: */
    585         SFTreeViewItem *pRoot = root(enmType);
    586         if (pItem->parentItem() != pRoot)
    587         {
    588             /* Move the tree-widget item to a new location: */
    589             pItem->parentItem()->takeChild(pItem->parentItem()->indexOfChild(pItem));
    590             pRoot->insertChild(pRoot->childCount(), pItem);
    591 
    592             /* Update tree-widget: */
    593             m_pTreeWidget->scrollToItem(pItem);
    594             m_pTreeWidget->setCurrentItem(pItem);
    595             sltHandleCurrentItemChange(pItem);
    596         }
    597 
    598         /* Sort tree-widget before adjusting: */
    599         m_pTreeWidget->sortItems(0, Qt::AscendingOrder);
    600         /* Adjust tree-widget finally: */
    601         sltAdjustTree();
    602     }
    603 }
    604 
    605 void UISharedFoldersEditor::sltRemoveFolder()
    606 {
    607     /* Check current folder item: */
     439        /* Notify listeners: */
     440        emit sigValueChanged();
     441    }
     442}
     443
     444void UIUSBFiltersEditor::sltRemoveFilter()
     445{
     446    /* Check current USB filter item: */
    608447    QTreeWidgetItem *pItem = m_pTreeWidget->currentItem();
    609448    AssertPtrReturnVoid(pItem);
     
    612451    delete pItem;
    613452
    614     /* Adjust tree-widget finally: */
    615     sltAdjustTree();
    616 }
    617 
    618 void UISharedFoldersEditor::prepare()
     453    /* Notify listeners: */
     454    emit sigValueChanged();
     455}
     456
     457void UIUSBFiltersEditor::sltMoveFilterUp()
     458{
     459    /* Check current USB filter item: */
     460    QTreeWidgetItem *pItem = m_pTreeWidget->currentItem();
     461    AssertPtrReturnVoid(pItem);
     462
     463    /* Move the item up: */
     464    const int iIndex = m_pTreeWidget->indexOfTopLevelItem(pItem);
     465    QTreeWidgetItem *pTakenItem = m_pTreeWidget->takeTopLevelItem(iIndex);
     466    Assert(pItem == pTakenItem);
     467    m_pTreeWidget->insertTopLevelItem(iIndex - 1, pTakenItem);
     468
     469    /* Make sure moved item still chosen: */
     470    m_pTreeWidget->setCurrentItem(pTakenItem);
     471}
     472
     473void UIUSBFiltersEditor::sltMoveFilterDown()
     474{
     475    /* Check current USB filter item: */
     476    QTreeWidgetItem *pItem = m_pTreeWidget->currentItem();
     477    AssertPtrReturnVoid(pItem);
     478
     479    /* Move the item down: */
     480    const int iIndex = m_pTreeWidget->indexOfTopLevelItem(pItem);
     481    QTreeWidgetItem *pTakenItem = m_pTreeWidget->takeTopLevelItem(iIndex);
     482    Assert(pItem == pTakenItem);
     483    m_pTreeWidget->insertTopLevelItem(iIndex + 1, pTakenItem);
     484
     485    /* Make sure moved item still chosen: */
     486    m_pTreeWidget->setCurrentItem(pTakenItem);
     487}
     488
     489void UIUSBFiltersEditor::sltHandleActivityStateChange(QTreeWidgetItem *pChangedItem)
     490{
     491    /* Check changed USB filter item: */
     492    USBFilterTreeWidgetItem *pItem = static_cast<USBFilterTreeWidgetItem*>(pChangedItem);
     493    AssertPtrReturnVoid(pItem);
     494
     495    /* Update corresponding item: */
     496    pItem->m_fActive = pItem->checkState(0) == Qt::Checked;
     497}
     498
     499void UIUSBFiltersEditor::prepare()
    619500{
    620501    /* Prepare everything: */
     
    626507}
    627508
    628 void UISharedFoldersEditor::prepareWidgets()
     509void UIUSBFiltersEditor::prepareWidgets()
    629510{
    630511    /* Prepare main layout: */
     
    651532            prepareToolbar();
    652533
     534            /* Update action availability: */
     535            sltHandleCurrentItemChange(m_pTreeWidget->currentItem());
     536
    653537            pLayout->addLayout(m_pLayoutTree);
    654538        }
     
    656540}
    657541
    658 void UISharedFoldersEditor::prepareTreeWidget()
     542void UIUSBFiltersEditor::prepareTreeWidget()
    659543{
    660544    /* Prepare shared folders tree-widget: */
     
    664548        if (m_pLabelSeparator)
    665549            m_pLabelSeparator->setBuddy(m_pTreeWidget);
    666         m_pTreeWidget->header()->setSectionsMovable(false);
    667         m_pTreeWidget->setMinimumSize(QSize(0, 200));
     550        m_pTreeWidget->header()->hide();
     551        m_pTreeWidget->setRootIsDecorated(false);
     552        m_pTreeWidget->setUniformRowHeights(true);
    668553        m_pTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
    669         m_pTreeWidget->setUniformRowHeights(true);
    670         m_pTreeWidget->setAllColumnsShowFocus(true);
    671554
    672555        m_pLayoutTree->addWidget(m_pTreeWidget);
     
    674557}
    675558
    676 void UISharedFoldersEditor::prepareToolbar()
     559void UIUSBFiltersEditor::prepareToolbar()
    677560{
    678561    /* Prepare shared folders toolbar: */
     
    684567        m_pToolbar->setOrientation(Qt::Vertical);
    685568
    686         /* Prepare 'add shared folder' action: */
    687         m_pActionAdd = m_pToolbar->addAction(UIIconPool::iconSet(":/sf_add_16px.png",
    688                                                                  ":/sf_add_disabled_16px.png"),
    689                                              QString(), this, SLOT(sltAddFolder()));
     569        /* Prepare 'New USB Filter' action: */
     570        m_pActionNew = m_pToolbar->addAction(UIIconPool::iconSet(":/usb_new_16px.png",
     571                                                                 ":/usb_new_disabled_16px.png"),
     572                                             QString(), this, SLOT(sltCreateFilter()));
     573        if (m_pActionNew)
     574            m_pActionNew->setShortcuts(QList<QKeySequence>() << QKeySequence("Ins") << QKeySequence("Ctrl+N"));
     575
     576        /* Prepare 'Add USB Filter' action: */
     577        m_pActionAdd = m_pToolbar->addAction(UIIconPool::iconSet(":/usb_add_16px.png",
     578                                                                 ":/usb_add_disabled_16px.png"),
     579                                             QString(), this, SLOT(sltAddFilter()));
    690580        if (m_pActionAdd)
    691             m_pActionAdd->setShortcuts(QList<QKeySequence>() << QKeySequence("Ins") << QKeySequence("Ctrl+N"));
    692 
    693         /* Prepare 'edit shared folder' action: */
    694         m_pActionEdit = m_pToolbar->addAction(UIIconPool::iconSet(":/sf_edit_16px.png",
    695                                                                   ":/sf_edit_disabled_16px.png"),
    696                                               QString(), this, SLOT(sltEditFolder()));
     581            m_pActionAdd->setShortcuts(QList<QKeySequence>() << QKeySequence("Alt+Ins") << QKeySequence("Ctrl+A"));
     582
     583        /* Prepare 'Edit USB Filter' action: */
     584        m_pActionEdit = m_pToolbar->addAction(UIIconPool::iconSet(":/usb_filter_edit_16px.png",
     585                                                                  ":/usb_filter_edit_disabled_16px.png"),
     586                                              QString(), this, SLOT(sltEditFilter()));
    697587        if (m_pActionEdit)
    698             m_pActionEdit->setShortcuts(QList<QKeySequence>() << QKeySequence("Space") << QKeySequence("F2"));
    699 
    700         /* Prepare 'remove shared folder' action: */
    701         m_pActionRemove = m_pToolbar->addAction(UIIconPool::iconSet(":/sf_remove_16px.png",
    702                                                                     ":/sf_remove_disabled_16px.png"),
    703                                                 QString(), this, SLOT(sltRemoveFolder()));
     588            m_pActionEdit->setShortcuts(QList<QKeySequence>() << QKeySequence("Alt+Return") << QKeySequence("Ctrl+Return"));
     589
     590        /* Prepare 'Remove USB Filter' action: */
     591        m_pActionRemove = m_pToolbar->addAction(UIIconPool::iconSet(":/usb_remove_16px.png",
     592                                                                    ":/usb_remove_disabled_16px.png"),
     593                                                QString(), this, SLOT(sltRemoveFilter()));
    704594        if (m_pActionRemove)
    705595            m_pActionRemove->setShortcuts(QList<QKeySequence>() << QKeySequence("Del") << QKeySequence("Ctrl+R"));
    706596
     597        /* Prepare 'Move USB Filter Up' action: */
     598        m_pActionMoveUp = m_pToolbar->addAction(UIIconPool::iconSet(":/usb_moveup_16px.png",
     599                                                                    ":/usb_moveup_disabled_16px.png"),
     600                                                QString(), this, SLOT(sltMoveFilterUp()));
     601        if (m_pActionMoveUp)
     602            m_pActionMoveUp->setShortcuts(QList<QKeySequence>() << QKeySequence("Alt+Up") << QKeySequence("Ctrl+Up"));
     603
     604        /* Prepare 'Move USB Filter Down' action: */
     605        m_pActionMoveDown = m_pToolbar->addAction(UIIconPool::iconSet(":/usb_movedown_16px.png",
     606                                                                      ":/usb_movedown_disabled_16px.png"),
     607                                                  QString(), this, SLOT(sltMoveFilterDown()));
     608        if (m_pActionMoveDown)
     609            m_pActionMoveDown->setShortcuts(QList<QKeySequence>() << QKeySequence("Alt+Down") << QKeySequence("Ctrl+Down"));
     610
     611        /* Prepare USB devices menu: */
     612        m_pMenuUSBDevices = new UIUSBMenu(this);
     613
    707614        m_pLayoutTree->addWidget(m_pToolbar);
    708615    }
    709616}
    710617
    711 void UISharedFoldersEditor::prepareConnections()
     618void UIUSBFiltersEditor::prepareConnections()
    712619{
    713620    /* Configure tree-widget connections: */
    714     connect(m_pTreeWidget, &QITreeWidget::currentItemChanged,
    715             this, &UISharedFoldersEditor::sltHandleCurrentItemChange);
    716     connect(m_pTreeWidget, &QITreeWidget::itemDoubleClicked,
    717             this, &UISharedFoldersEditor::sltHandleDoubleClick);
    718     connect(m_pTreeWidget, &QITreeWidget::customContextMenuRequested,
    719             this, &UISharedFoldersEditor::sltHandleContextMenuRequest);
    720 }
    721 
    722 QStringList UISharedFoldersEditor::usedList(bool fIncludeSelected)
    723 {
    724     /* Make the used names list: */
    725     QStringList list;
    726     QTreeWidgetItemIterator it(m_pTreeWidget);
    727     while (*it)
    728     {
    729         if ((*it)->parent() && (fIncludeSelected || !(*it)->isSelected()))
    730             list << static_cast<SFTreeViewItem*>(*it)->getText(0);
    731         ++it;
    732     }
    733     return list;
    734 }
    735 
    736 SFTreeViewItem *UISharedFoldersEditor::root(UISharedFolderType enmSharedFolderType)
    737 {
    738     /* Search for the corresponding root item among all the top-level items: */
    739     SFTreeViewItem *pRootItem = 0;
    740     QTreeWidgetItem *pMainRootItem = m_pTreeWidget->invisibleRootItem();
    741     for (int iFolderTypeIndex = 0; iFolderTypeIndex < pMainRootItem->childCount(); ++iFolderTypeIndex)
    742     {
    743         /* Get iterated item: */
    744         SFTreeViewItem *pIteratedItem = static_cast<SFTreeViewItem*>(pMainRootItem->child(iFolderTypeIndex));
    745         /* If iterated item type is what we are looking for: */
    746         if (pIteratedItem->m_enmType == enmSharedFolderType)
    747         {
    748             /* Remember the item: */
    749             pRootItem = static_cast<SFTreeViewItem*>(pIteratedItem);
    750             /* And break further search: */
    751             break;
    752         }
    753     }
    754     /* Return root item: */
    755     return pRootItem;
    756 }
    757 
    758 void UISharedFoldersEditor::setRootItemVisible(UISharedFolderType enmSharedFolderType, bool fVisible)
    759 {
    760     /* Search for the corresponding root item among all the top-level items: */
    761     SFTreeViewItem *pRootItem = root(enmSharedFolderType);
    762     /* If root item, we are looking for, still not found: */
    763     if (!pRootItem)
    764     {
    765         /* Create new shared folder type item: */
    766         pRootItem = new SFTreeViewItem(m_pTreeWidget, SFTreeViewItem::FormatType_EllipsisEnd);
    767         if (pRootItem)
    768         {
    769             /* Configure item: */
    770             pRootItem->m_enmType = enmSharedFolderType;
    771             switch (enmSharedFolderType)
    772             {
    773                 case UISharedFolderType_Machine: pRootItem->m_strName = tr(" Machine Folders"); break;
    774                 case UISharedFolderType_Console: pRootItem->m_strName = tr(" Transient Folders"); break;
    775                 default: break;
    776             }
    777             pRootItem->updateFields();
    778         }
    779     }
    780     /* Expand/collaps it if necessary: */
    781     pRootItem->setExpanded(fVisible);
    782     /* And hide/show it if necessary: */
    783     pRootItem->setHidden(!fVisible);
    784 }
    785 
    786 void UISharedFoldersEditor::updateRootItemsVisibility()
    787 {
    788     /* Update (show/hide) machine (permanent) root item: */
    789     setRootItemVisible(UISharedFolderType_Machine, m_foldersAvailable.value(UISharedFolderType_Machine));
    790     /* Update (show/hide) console (temporary) root item: */
    791     setRootItemVisible(UISharedFolderType_Console, m_foldersAvailable.value(UISharedFolderType_Console));
    792 }
    793 
    794 void UISharedFoldersEditor::addSharedFolderItem(const UIDataSharedFolder &sharedFolderData, bool fChoose)
    795 {
    796     /* Create shared folder item: */
    797     SFTreeViewItem *pItem = new SFTreeViewItem(root(sharedFolderData.m_enmType), SFTreeViewItem::FormatType_EllipsisFile);
     621    if (m_pTreeWidget)
     622    {
     623        connect(m_pTreeWidget, &QITreeWidget::currentItemChanged,
     624                this, &UIUSBFiltersEditor::sltHandleCurrentItemChange);
     625        connect(m_pTreeWidget, &QITreeWidget::itemDoubleClicked,
     626                this, &UIUSBFiltersEditor::sltHandleDoubleClick);
     627        connect(m_pTreeWidget, &QITreeWidget::customContextMenuRequested,
     628                this, &UIUSBFiltersEditor::sltHandleContextMenuRequest);
     629        connect(m_pTreeWidget, &QITreeWidget::itemChanged,
     630                this, &UIUSBFiltersEditor::sltHandleActivityStateChange);
     631    }
     632
     633    /* Configure USB device menu connections: */
     634    if (m_pMenuUSBDevices)
     635        connect(m_pMenuUSBDevices, &UIUSBMenu::triggered,
     636                this, &UIUSBFiltersEditor::sltAddFilterConfirmed);
     637}
     638
     639void UIUSBFiltersEditor::addUSBFilterItem(const UIDataUSBFilter &data, bool fChoose)
     640{
     641    /* Create USB filter item: */
     642    USBFilterTreeWidgetItem *pItem = new USBFilterTreeWidgetItem(m_pTreeWidget);
    798643    if (pItem)
    799644    {
    800645        /* Configure item: */
    801         pItem->m_enmType = sharedFolderData.m_enmType;
    802         pItem->m_strName = sharedFolderData.m_strName;
    803         pItem->m_strPath = sharedFolderData.m_strPath;
    804         pItem->m_fWritable = sharedFolderData.m_fWritable;
    805         pItem->m_fAutoMount = sharedFolderData.m_fAutoMount;
    806         pItem->m_strAutoMountPoint = sharedFolderData.m_strAutoMountPoint;
     646        pItem->setCheckState(0, data.m_fActive ? Qt::Checked : Qt::Unchecked);
     647        pItem->m_fActive = data.m_fActive;
     648        pItem->m_strName = data.m_strName;
     649        pItem->m_strVendorId = data.m_strVendorId;
     650        pItem->m_strProductId = data.m_strProductId;
     651        pItem->m_strRevision = data.m_strRevision;
     652        pItem->m_strManufacturer = data.m_strManufacturer;
     653        pItem->m_strProduct = data.m_strProduct;
     654        pItem->m_strSerialNumber = data.m_strSerialNumber;
     655        pItem->m_strPort = data.m_strPort;
     656        pItem->m_enmRemoteMode = data.m_enmRemoteMode;
    807657        pItem->updateFields();
    808658
     
    817667}
    818668
    819 void UISharedFoldersEditor::reloadTree()
     669void UIUSBFiltersEditor::reloadTree()
    820670{
    821671    /* Sanity check: */
     
    826676    m_pTreeWidget->clear();
    827677
    828     /* Update root items visibility: */
    829     updateRootItemsVisibility();
    830 
    831     /* For each folder => load it from cache: */
    832     foreach (const UIDataSharedFolder &guiData, m_guiValue)
    833         addSharedFolderItem(guiData, false /* its new? */);
    834 
    835     /* Choose first folder as current: */
     678    /* For each filter => load it from cache: */
     679    foreach (const UIDataUSBFilter &guiData, m_guiValue)
     680        addUSBFilterItem(guiData, false /* its new? */);
     681
     682    /* Choose first filter as current: */
    836683    m_pTreeWidget->setCurrentItem(m_pTreeWidget->topLevelItem(0));
    837684    sltHandleCurrentItemChange(m_pTreeWidget->currentItem());
     
    839686
    840687
    841 #include "UISharedFoldersEditor.moc"
     688#include "UIUSBFiltersEditor.moc"
  • trunk/src/VBox/Frontends/VirtualBox/src/settings/editors/UIUSBFiltersEditor.h

    r95276 r95277  
    11/* $Id$ */
    22/** @file
    3  * VBox Qt GUI - UISharedFoldersEditor class declaration.
     3 * VBox Qt GUI - UIUSBFiltersEditor class declaration.
    44 */
    55
     
    1616 */
    1717
    18 #ifndef FEQT_INCLUDED_SRC_settings_editors_UISharedFoldersEditor_h
    19 #define FEQT_INCLUDED_SRC_settings_editors_UISharedFoldersEditor_h
     18#ifndef FEQT_INCLUDED_SRC_settings_editors_UIUSBFiltersEditor_h
     19#define FEQT_INCLUDED_SRC_settings_editors_UIUSBFiltersEditor_h
    2020#ifndef RT_WITHOUT_PRAGMA_ONCE
    2121# pragma once
     
    3232class QIToolBar;
    3333class QITreeWidget;
    34 class SFTreeViewItem;
     34class UIUSBMenu;
    3535
    36 /** Shared Folder data. */
    37 struct UIDataSharedFolder
     36/** USB Filter data. */
     37struct UIDataUSBFilter
    3838{
    3939    /** Constructs data. */
    40     UIDataSharedFolder()
    41         : m_enmType(UISharedFolderType_Machine)
    42         , m_strName()
    43         , m_strPath()
    44         , m_fWritable(false)
    45         , m_fAutoMount(false)
    46         , m_strAutoMountPoint()
     40    UIDataUSBFilter()
     41        : m_fActive(true)
     42        , m_enmRemoteMode(UIRemoteMode_Any)
    4743    {}
    4844
    4945    /** Returns whether the @a other passed data is equal to this one. */
    50     bool equal(const UIDataSharedFolder &other) const
     46    bool equal(const UIDataUSBFilter &other) const
    5147    {
    5248        return true
    53                && m_enmType == other.m_enmType
     49               && m_fActive == other.m_fActive
    5450               && m_strName == other.m_strName
    55                && m_strPath == other.m_strPath
    56                && m_fWritable == other.m_fWritable
    57                && m_fAutoMount == other.m_fAutoMount
    58                && m_strAutoMountPoint == other.m_strAutoMountPoint
     51               && m_strVendorId == other.m_strVendorId
     52               && m_strProductId == other.m_strProductId
     53               && m_strRevision == other.m_strRevision
     54               && m_strManufacturer == other.m_strManufacturer
     55               && m_strProduct == other.m_strProduct
     56               && m_strSerialNumber == other.m_strSerialNumber
     57               && m_strPort == other.m_strPort
     58               && m_enmRemoteMode == other.m_enmRemoteMode
    5959               ;
    6060    }
    6161
    6262    /** Returns whether the @a other passed data is equal to this one. */
    63     bool operator==(const UIDataSharedFolder &other) const { return equal(other); }
     63    bool operator==(const UIDataUSBFilter &other) const { return equal(other); }
    6464    /** Returns whether the @a other passed data is different from this one. */
    65     bool operator!=(const UIDataSharedFolder &other) const { return !equal(other); }
     65    bool operator!=(const UIDataUSBFilter &other) const { return !equal(other); }
    6666
    67     /** Holds the shared folder type. */
    68     UISharedFolderType  m_enmType;
    69     /** Holds the shared folder name. */
    70     QString             m_strName;
    71     /** Holds the shared folder path. */
    72     QString             m_strPath;
    73     /** Holds whether the shared folder should be writeable. */
    74     bool                m_fWritable;
    75     /** Holds whether the shared folder should be auto-mounted at startup. */
    76     bool                m_fAutoMount;
    77     /** Where in the guest to try auto mount the shared folder (drive for
    78      * Windows & OS/2, path for unixy guests). */
    79     QString             m_strAutoMountPoint;
     67    /** Holds whether USB filter is active. */
     68    bool          m_fActive;
     69    /** Holds the USB filter name. */
     70    QString       m_strName;
     71    /** Holds the USB filter vendor ID. */
     72    QString       m_strVendorId;
     73    /** Holds the USB filter product ID. */
     74    QString       m_strProductId;
     75    /** Holds the USB filter revision. */
     76    QString       m_strRevision;
     77    /** Holds the USB filter manufacturer. */
     78    QString       m_strManufacturer;
     79    /** Holds the USB filter product. */
     80    QString       m_strProduct;
     81    /** Holds the USB filter serial number. */
     82    QString       m_strSerialNumber;
     83    /** Holds the USB filter port. */
     84    QString       m_strPort;
     85    /** Holds the USB filter remote. */
     86    UIRemoteMode  m_enmRemoteMode;
    8087};
    8188
    82 /** QWidget subclass used as a shared folders editor. */
    83 class SHARED_LIBRARY_STUFF UISharedFoldersEditor : public QIWithRetranslateUI<QWidget>
     89/** QWidget subclass used as a USB filters editor. */
     90class SHARED_LIBRARY_STUFF UIUSBFiltersEditor : public QIWithRetranslateUI<QWidget>
    8491{
    8592    Q_OBJECT;
     93
     94signals:
     95
     96    /** Notifies listeners about value change. */
     97    void sigValueChanged();
    8698
    8799public:
    88100
    89101    /** Constructs editor passing @a pParent to the base-class. */
    90     UISharedFoldersEditor(QWidget *pParent = 0);
     102    UIUSBFiltersEditor(QWidget *pParent = 0);
    91103
    92104    /** Defines editor @a strValue. */
    93     void setValue(const QList<UIDataSharedFolder> &guiValue);
     105    void setValue(const QList<UIDataUSBFilter> &guiValue);
    94106    /** Returns editor value. */
    95     QList<UIDataSharedFolder> value() const;
    96 
    97     /** Defines whether feature @a fAvailable. */
    98     void setFeatureAvailable(bool fAvailable);
    99     /** Defines whether folders of certain @a enmType are @a fAvailable. */
    100     void setFoldersAvailable(UISharedFolderType enmType, bool fAvailable);
     107    QList<UIDataUSBFilter> value() const;
    101108
    102109protected:
     
    105112    virtual void retranslateUi() RT_OVERRIDE;
    106113
    107     /** Handles show @a pEvent. */
    108     virtual void showEvent(QShowEvent *pEvent) RT_OVERRIDE;
    109 
    110     /** Handles resize @a pEvent. */
    111     virtual void resizeEvent(QResizeEvent *pEvent) RT_OVERRIDE;
    112 
    113114private slots:
    114 
    115     /** Performs request to adjust tree. */
    116     void sltAdjustTree();
    117     /** Performs request to adjust tree fields. */
    118     void sltAdjustTreeFields();
    119115
    120116    /** Handles @a pCurrentItem change. */
     
    125121    void sltHandleContextMenuRequest(const QPoint &position);
    126122
    127     /** Handles command to add shared folder. */
    128     void sltAddFolder();
    129     /** Handles command to edit shared folder. */
    130     void sltEditFolder();
    131     /** Handles command to remove shared folder. */
    132     void sltRemoveFolder();
     123    /** Handles command to create USB filter. */
     124    void sltCreateFilter();
     125    /** Handles command to add USB filter. */
     126    void sltAddFilter();
     127    /** Handles command to confirm add of existing USB filter defined by @a pAction. */
     128    void sltAddFilterConfirmed(QAction *pAction);
     129    /** Handles command to edit USB filter. */
     130    void sltEditFilter();
     131    /** Handles command to remove USB filter. */
     132    void sltRemoveFilter();
     133    /** Handles command to move chosen USB filter up. */
     134    void sltMoveFilterUp();
     135    /** Handles command to move chosen USB filter down. */
     136    void sltMoveFilterDown();
     137
     138    /** Handles USB filter tree activity state change for @a pChangedItem. */
     139    void sltHandleActivityStateChange(QTreeWidgetItem *pChangedItem);
    133140
    134141private:
     
    145152    void prepareConnections();
    146153
    147     /** Returns a list of used shared folder names. */
    148     QStringList usedList(bool fIncludeSelected);
    149 
    150     /** Returns the tree-view root item for corresponding shared folder @a type. */
    151     SFTreeViewItem *root(UISharedFolderType type);
    152     /** Defines whether the root item of @a enmFoldersType is @a fVisible. */
    153     void setRootItemVisible(UISharedFolderType enmFoldersType, bool fVisible);
    154     /** Updates root item visibility. */
    155     void updateRootItemsVisibility();
    156     /** Creates shared folder item based on passed @a data. */
    157     void addSharedFolderItem(const UIDataSharedFolder &sharedFolderData, bool fChoose);
     154    /** Creates USB filter item based on passed @a data. */
     155    void addUSBFilterItem(const UIDataUSBFilter &data, bool fChoose);
    158156    /** Reloads tree. */
    159157    void reloadTree();
    160158
    161159    /** Holds the value to be set. */
    162     QList<UIDataSharedFolder>  m_guiValue;
     160    QList<UIDataUSBFilter>  m_guiValue;
    163161
    164     /** Holds whether folders of certain type are available. */
    165     QMap<UISharedFolderType, bool>  m_foldersAvailable;
     162    /** @name Internal
     163     * @{ */
     164        /** Holds the "New Filter %1" translation tag. */
     165        QString  m_strTrUSBFilterName;
     166    /** @} */
    166167
    167168    /** @name Widgets
     
    175176        /** Holds the toolbar instance. */
    176177        QIToolBar        *m_pToolbar;
    177         /** Holds the 'add shared folder' action instance. */
     178        /** Holds the 'new USB filter' action instance. */
     179        QAction          *m_pActionNew;
     180        /** Holds the 'add USB filter' action instance. */
    178181        QAction          *m_pActionAdd;
    179         /** Holds the 'edit shared folder' action instance. */
     182        /** Holds the 'edit USB filter' action instance. */
    180183        QAction          *m_pActionEdit;
    181         /** Holds the 'remove shared folder' action instance. */
     184        /** Holds the 'remove USB filter' action instance. */
    182185        QAction          *m_pActionRemove;
     186        /** Holds the Move Up action instance. */
     187        QAction          *m_pActionMoveUp;
     188        /** Holds the Move Down action instance. */
     189        QAction          *m_pActionMoveDown;
     190        /** Holds the USB devices menu instance. */
     191        UIUSBMenu        *m_pMenuUSBDevices;
    183192    /** @} */
    184193};
    185194
    186 #endif /* !FEQT_INCLUDED_SRC_settings_editors_UISharedFoldersEditor_h */
     195#endif /* !FEQT_INCLUDED_SRC_settings_editors_UIUSBFiltersEditor_h */
  • trunk/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSB.cpp

    r95247 r95277  
    2626#include <QRegExp>
    2727#include <QSpacerItem>
    28 #include <QToolTip>
    2928#include <QVBoxLayout>
    3029
     
    4140#include "UIUSBControllerEditor.h"
    4241#include "UIUSBFilterDetailsEditor.h"
     42#include "UIUSBFiltersEditor.h"
    4343
    4444/* COM includes: */
    45 #include "CConsole.h"
    4645#include "CExtPack.h"
    4746#include "CExtPackManager.h"
    48 #include "CHostUSBDevice.h"
    49 #include "CHostUSBDeviceFilter.h"
    5047#include "CUSBController.h"
    51 #include "CUSBDevice.h"
    5248#include "CUSBDeviceFilter.h"
    5349#include "CUSBDeviceFilters.h"
    5450
    55 /* VirtualBox interface declarations: */
    56 #include <VBox/com/VirtualBox.h>
    57 
    5851
    5952/** Machine settings: USB filter data structure. */
     
    6154{
    6255    /** Constructs data. */
    63     UIDataSettingsMachineUSBFilter()
    64         : m_fActive(false)
    65         , m_strName(QString())
    66         , m_strVendorId(QString())
    67         , m_strProductId(QString())
    68         , m_strRevision(QString())
    69         , m_strManufacturer(QString())
    70         , m_strProduct(QString())
    71         , m_strSerialNumber(QString())
    72         , m_strPort(QString())
    73         , m_strRemote(QString())
    74         , m_enmAction(KUSBDeviceFilterAction_Null)
    75         , m_enmHostUSBDeviceState(KUSBDeviceState_NotSupported)
    76         , m_fHostUSBDevice(false)
    77     {}
     56    UIDataSettingsMachineUSBFilter() {}
    7857
    7958    /** Returns whether the @a other passed data is equal to this one. */
     
    8160    {
    8261        return true
    83                && (m_fActive == other.m_fActive)
    84                && (m_strName == other.m_strName)
    85                && (m_strVendorId == other.m_strVendorId)
    86                && (m_strProductId == other.m_strProductId)
    87                && (m_strRevision == other.m_strRevision)
    88                && (m_strManufacturer == other.m_strManufacturer)
    89                && (m_strProduct == other.m_strProduct)
    90                && (m_strSerialNumber == other.m_strSerialNumber)
    91                && (m_strPort == other.m_strPort)
    92                && (m_strRemote == other.m_strRemote)
    93                && (m_enmAction == other.m_enmAction)
    94                && (m_enmHostUSBDeviceState == other.m_enmHostUSBDeviceState)
     62               && (m_guiData == other.m_guiData)
    9563               ;
    9664    }
     
    10169    bool operator!=(const UIDataSettingsMachineUSBFilter &other) const { return !equal(other); }
    10270
    103     /** Holds whether the USB filter is enabled. */
    104     bool     m_fActive;
    105     /** Holds the USB filter name. */
    106     QString  m_strName;
    107     /** Holds the USB filter vendor ID. */
    108     QString  m_strVendorId;
    109     /** Holds the USB filter product ID. */
    110     QString  m_strProductId;
    111     /** Holds the USB filter revision. */
    112     QString  m_strRevision;
    113     /** Holds the USB filter manufacturer. */
    114     QString  m_strManufacturer;
    115     /** Holds the USB filter product. */
    116     QString  m_strProduct;
    117     /** Holds the USB filter serial number. */
    118     QString  m_strSerialNumber;
    119     /** Holds the USB filter port. */
    120     QString  m_strPort;
    121     /** Holds the USB filter remote. */
    122     QString  m_strRemote;
    123 
    124     /** Holds the USB filter action. */
    125     KUSBDeviceFilterAction  m_enmAction;
    126     /** Holds the USB device state. */
    127     KUSBDeviceState         m_enmHostUSBDeviceState;
    128     /** Holds whether the USB filter is host USB device. */
    129     bool                    m_fHostUSBDevice;
     71    /** Holds the USB filter data. */
     72    UIDataUSBFilter  m_guiData;
    13073};
    13174
     
    161104
    162105
    163 /** Machine settings: USB Filter popup menu. */
    164 class VBoxUSBMenu : public QMenu
    165 {
    166     Q_OBJECT;
    167 
    168 public:
    169 
    170     /* Constructor: */
    171     VBoxUSBMenu(QWidget *)
    172     {
    173         connect(this, &VBoxUSBMenu::aboutToShow, this, &VBoxUSBMenu::processAboutToShow);
    174     }
    175 
    176     /* Returns USB device related to passed action: */
    177     const CUSBDevice& getUSB(QAction *pAction)
    178     {
    179         return m_usbDeviceMap[pAction];
    180     }
    181 
    182     /* Console setter: */
    183     void setConsole(const CConsole &console)
    184     {
    185         m_console = console;
    186     }
    187 
    188 private slots:
    189 
    190     /* Prepare menu appearance: */
    191     void processAboutToShow()
    192     {
    193         clear();
    194         m_usbDeviceMap.clear();
    195 
    196         CHost host = uiCommon().host();
    197 
    198         bool fIsUSBEmpty = host.GetUSBDevices().size() == 0;
    199 
    200         if (fIsUSBEmpty)
    201         {
    202             QAction *pAction = addAction(tr("<no devices available>", "USB devices"));
    203             pAction->setEnabled(false);
    204             pAction->setToolTip(tr("No supported devices connected to the host PC", "USB device tooltip"));
    205         }
    206         else
    207         {
    208             CHostUSBDeviceVector devvec = host.GetUSBDevices();
    209             for (int i = 0; i < devvec.size(); ++i)
    210             {
    211                 CHostUSBDevice dev = devvec[i];
    212                 CUSBDevice usb(dev);
    213                 QAction *pAction = addAction(uiCommon().usbDetails(usb));
    214                 pAction->setCheckable(true);
    215                 m_usbDeviceMap[pAction] = usb;
    216                 /* Check if created item was already attached to this session: */
    217                 if (!m_console.isNull())
    218                 {
    219                     CUSBDevice attachedUSB = m_console.FindUSBDeviceById(usb.GetId());
    220                     pAction->setChecked(!attachedUSB.isNull());
    221                     pAction->setEnabled(dev.GetState() != KUSBDeviceState_Unavailable);
    222                 }
    223             }
    224         }
    225     }
    226 
    227 private:
    228 
    229     /* Event handler: */
    230     bool event(QEvent *pEvent)
    231     {
    232         /* We provide dynamic tooltips for the usb devices: */
    233         if (pEvent->type() == QEvent::ToolTip)
    234         {
    235             QHelpEvent *pHelpEvent = static_cast<QHelpEvent*>(pEvent);
    236             QAction *pAction = actionAt(pHelpEvent->pos());
    237             if (pAction)
    238             {
    239                 CUSBDevice usb = m_usbDeviceMap[pAction];
    240                 if (!usb.isNull())
    241                 {
    242                     QToolTip::showText(pHelpEvent->globalPos(), uiCommon().usbToolTip(usb));
    243                     return true;
    244                 }
    245             }
    246         }
    247         /* Call to base-class: */
    248         return QMenu::event(pEvent);
    249     }
    250 
    251     QMap<QAction*, CUSBDevice> m_usbDeviceMap;
    252     CConsole m_console;
    253 };
    254 
    255 
    256 /** Machine settings: USB Filter tree-widget item. */
    257 class UIUSBFilterItem : public QITreeWidgetItem, public UIDataSettingsMachineUSBFilter
    258 {
    259     Q_OBJECT;
    260 
    261 public:
    262 
    263     /** Constructs USB filter (root) item.
    264       * @param  pParent  Brings the item parent. */
    265     UIUSBFilterItem(QITreeWidget *pParent)
    266         : QITreeWidgetItem(pParent)
    267     {
    268     }
    269 
    270     /** Updates item fields. */
    271     void updateFields()
    272     {
    273         setText(0, m_strName);
    274         setToolTip(0, toolTipFor());
    275     }
    276 
    277 protected:
    278 
    279     /** Returns default text. */
    280     virtual QString defaultText() const RT_OVERRIDE
    281     {
    282         return checkState(0) == Qt::Checked ?
    283                tr("%1, Active", "col.1 text, col.1 state").arg(text(0)) :
    284                tr("%1",         "col.1 text")             .arg(text(0));
    285     }
    286 
    287 private:
    288 
    289     /** Returns tool-tip generated from item data. */
    290     QString toolTipFor()
    291     {
    292         /* Prepare tool-tip: */
    293         QString strToolTip;
    294 
    295         const QString strVendorId = m_strVendorId;
    296         if (!strVendorId.isEmpty())
    297             strToolTip += tr("<nobr>Vendor ID: %1</nobr>", "USB filter tooltip").arg(strVendorId);
    298 
    299         const QString strProductId = m_strProductId;
    300         if (!strProductId.isEmpty())
    301             strToolTip += strToolTip.isEmpty() ? "":"<br/>" + tr("<nobr>Product ID: %2</nobr>", "USB filter tooltip").arg(strProductId);
    302 
    303         const QString strRevision = m_strRevision;
    304         if (!strRevision.isEmpty())
    305             strToolTip += strToolTip.isEmpty() ? "":"<br/>" + tr("<nobr>Revision: %3</nobr>", "USB filter tooltip").arg(strRevision);
    306 
    307         const QString strProduct = m_strProduct;
    308         if (!strProduct.isEmpty())
    309             strToolTip += strToolTip.isEmpty() ? "":"<br/>" + tr("<nobr>Product: %4</nobr>", "USB filter tooltip").arg(strProduct);
    310 
    311         const QString strManufacturer = m_strManufacturer;
    312         if (!strManufacturer.isEmpty())
    313             strToolTip += strToolTip.isEmpty() ? "":"<br/>" + tr("<nobr>Manufacturer: %5</nobr>", "USB filter tooltip").arg(strManufacturer);
    314 
    315         const QString strSerial = m_strSerialNumber;
    316         if (!strSerial.isEmpty())
    317             strToolTip += strToolTip.isEmpty() ? "":"<br/>" + tr("<nobr>Serial No.: %1</nobr>", "USB filter tooltip").arg(strSerial);
    318 
    319         const QString strPort = m_strPort;
    320         if (!strPort.isEmpty())
    321             strToolTip += strToolTip.isEmpty() ? "":"<br/>" + tr("<nobr>Port: %1</nobr>", "USB filter tooltip").arg(strPort);
    322 
    323         /* Add the state field if it's a host USB device: */
    324         if (m_fHostUSBDevice)
    325         {
    326             strToolTip += strToolTip.isEmpty() ? "":"<br/>" + tr("<nobr>State: %1</nobr>", "USB filter tooltip")
    327                                                                  .arg(gpConverter->toString(m_enmHostUSBDeviceState));
    328         }
    329 
    330         /* Return tool-tip: */
    331         return strToolTip;
    332     }
    333 };
    334 
    335 
    336106UIMachineSettingsUSB::UIMachineSettingsUSB()
    337107    : m_pCache(0)
     
    339109    , m_pWidgetUSBSettings(0)
    340110    , m_pEditorController(0)
    341     , m_pLabelSeparatorFilters(0)
    342     , m_pLayoutFilters(0)
    343     , m_pTreeWidgetFilters(0)
    344     , m_pToolbarFilters(0)
    345     , m_pActionNew(0)
    346     , m_pActionAdd(0)
    347     , m_pActionEdit(0)
    348     , m_pActionRemove(0)
    349     , m_pActionMoveUp(0)
    350     , m_pActionMoveDown(0)
    351     , m_pMenuUSBDevices(0)
     111    , m_pEditorFilters(0)
    352112{
    353113    prepare();
     
    407167            {
    408168                /* Gather old data: */
    409                 oldFilterData.m_fActive = filter.GetActive();
    410                 oldFilterData.m_strName = filter.GetName();
    411                 oldFilterData.m_strVendorId = filter.GetVendorId();
    412                 oldFilterData.m_strProductId = filter.GetProductId();
    413                 oldFilterData.m_strRevision = filter.GetRevision();
    414                 oldFilterData.m_strManufacturer = filter.GetManufacturer();
    415                 oldFilterData.m_strProduct = filter.GetProduct();
    416                 oldFilterData.m_strSerialNumber = filter.GetSerialNumber();
    417                 oldFilterData.m_strPort = filter.GetPort();
    418                 oldFilterData.m_strRemote = filter.GetRemote();
     169                oldFilterData.m_guiData.m_fActive = filter.GetActive();
     170                oldFilterData.m_guiData.m_strName = filter.GetName();
     171                oldFilterData.m_guiData.m_strVendorId = filter.GetVendorId();
     172                oldFilterData.m_guiData.m_strProductId = filter.GetProductId();
     173                oldFilterData.m_guiData.m_strRevision = filter.GetRevision();
     174                oldFilterData.m_guiData.m_strManufacturer = filter.GetManufacturer();
     175                oldFilterData.m_guiData.m_strProduct = filter.GetProduct();
     176                oldFilterData.m_guiData.m_strSerialNumber = filter.GetSerialNumber();
     177                oldFilterData.m_guiData.m_strPort = filter.GetPort();
     178                const QString strRemote = filter.GetRemote();
     179                UIRemoteMode enmRemoteMode = UIRemoteMode_Any;
     180                if (strRemote == "true" || strRemote == "yes" || strRemote == "1")
     181                    enmRemoteMode = UIRemoteMode_On;
     182                else if (strRemote == "false" || strRemote == "no" || strRemote == "0")
     183                    enmRemoteMode = UIRemoteMode_Off;
     184                oldFilterData.m_guiData.m_enmRemoteMode = enmRemoteMode;
    419185            }
    420186
     
    434200{
    435201    /* Sanity check: */
    436     if (   !m_pCache
    437         || !m_pTreeWidgetFilters)
     202    if (!m_pCache)
    438203        return;
    439 
    440     /* Clear list initially: */
    441     m_pTreeWidgetFilters->clear();
    442204
    443205    /* Get old USB data from cache: */
     
    449211    if (m_pEditorController)
    450212        m_pEditorController->setValue(oldUsbData.m_enmUSBControllerType);
    451 
    452     /* For each filter => load it from cache: */
    453     for (int iFilterIndex = 0; iFilterIndex < m_pCache->childCount(); ++iFilterIndex)
    454         addUSBFilterItem(m_pCache->child(iFilterIndex).base(), false /* its new? */);
    455 
    456     /* Choose first filter as current: */
    457     m_pTreeWidgetFilters->setCurrentItem(m_pTreeWidgetFilters->topLevelItem(0));
     213    if (m_pEditorFilters)
     214    {
     215        /* For each filter => load it from cache: */
     216        QList<UIDataUSBFilter> filters;
     217        for (int iFilterIndex = 0; iFilterIndex < m_pCache->childCount(); ++iFilterIndex)
     218        {
     219            const UIDataSettingsMachineUSBFilter &oldUsbFilterData = m_pCache->child(iFilterIndex).base();
     220            UIDataUSBFilter filter;
     221            filter.m_fActive = oldUsbFilterData.m_guiData.m_fActive;
     222            filter.m_strName = oldUsbFilterData.m_guiData.m_strName;
     223            filter.m_strVendorId = oldUsbFilterData.m_guiData.m_strVendorId;
     224            filter.m_strProductId = oldUsbFilterData.m_guiData.m_strProductId;
     225            filter.m_strRevision = oldUsbFilterData.m_guiData.m_strRevision;
     226            filter.m_strManufacturer = oldUsbFilterData.m_guiData.m_strManufacturer;
     227            filter.m_strProduct = oldUsbFilterData.m_guiData.m_strProduct;
     228            filter.m_strSerialNumber = oldUsbFilterData.m_guiData.m_strSerialNumber;
     229            filter.m_strPort = oldUsbFilterData.m_guiData.m_strPort;
     230            filter.m_enmRemoteMode = oldUsbFilterData.m_guiData.m_enmRemoteMode;
     231            filters << filter;
     232        }
     233        m_pEditorFilters->setValue(filters);
     234    }
     235
     236    /* Update widget availability: */
    458237    if (m_pCheckBoxUSB)
    459238        sltHandleUsbAdapterToggle(m_pCheckBoxUSB->isChecked());
     
    470249    /* Sanity check: */
    471250    if (   !m_pCache
    472         || !m_pTreeWidgetFilters)
     251        || !m_pEditorFilters)
    473252        return;
    474253
     
    481260    if (m_pEditorController)
    482261        newUsbData.m_enmUSBControllerType = newUsbData.m_fUSBEnabled ? m_pEditorController->value() : KUSBControllerType_Null;
    483 
    484     /* For each filter: */
    485     QTreeWidgetItem *pMainRootItem = m_pTreeWidgetFilters->invisibleRootItem();
    486     for (int iFilterIndex = 0; iFilterIndex < pMainRootItem->childCount(); ++iFilterIndex)
    487     {
    488         /* Gather and cache new data: */
    489         const UIUSBFilterItem *pItem = static_cast<UIUSBFilterItem*>(pMainRootItem->child(iFilterIndex));
    490         m_pCache->child(iFilterIndex).cacheCurrentData(*pItem);
     262    if (m_pEditorFilters)
     263    {
     264        /* For each filter => save it to cache: */
     265        const QList<UIDataUSBFilter> filters = m_pEditorFilters->value();
     266        for (int iFilterIndex = 0; iFilterIndex < filters.size(); ++iFilterIndex)
     267        {
     268            /* Gather and cache new data: */
     269            UIDataUSBFilter filter = filters.at(iFilterIndex);
     270            UIDataSettingsMachineUSBFilter newUsbFilterData;
     271            newUsbFilterData.m_guiData.m_fActive = filter.m_fActive;
     272            newUsbFilterData.m_guiData.m_strName = filter.m_strName;
     273            newUsbFilterData.m_guiData.m_strVendorId = filter.m_strVendorId;
     274            newUsbFilterData.m_guiData.m_strProductId = filter.m_strProductId;
     275            newUsbFilterData.m_guiData.m_strRevision = filter.m_strRevision;
     276            newUsbFilterData.m_guiData.m_strManufacturer = filter.m_strManufacturer;
     277            newUsbFilterData.m_guiData.m_strProduct = filter.m_strProduct;
     278            newUsbFilterData.m_guiData.m_strSerialNumber = filter.m_strSerialNumber;
     279            newUsbFilterData.m_guiData.m_enmRemoteMode = filter.m_enmRemoteMode;
     280            m_pCache->child(iFilterIndex).cacheCurrentData(newUsbFilterData);
     281        }
    491282    }
    492283
     
    543334    setTabOrder(pWidget, m_pCheckBoxUSB);
    544335    setTabOrder(m_pCheckBoxUSB, m_pEditorController);
    545     setTabOrder(m_pEditorController, m_pTreeWidgetFilters);
     336    setTabOrder(m_pEditorController, m_pEditorFilters);
    546337}
    547338
     
    550341    m_pCheckBoxUSB->setToolTip(tr("When checked, enables the virtual USB controller of this machine."));
    551342    m_pCheckBoxUSB->setText(tr("Enable &USB Controller"));
    552     m_pLabelSeparatorFilters->setText(tr("USB Device &Filters"));
    553     QTreeWidgetItem *pQtreewidgetitem = m_pTreeWidgetFilters->headerItem();
    554     pQtreewidgetitem->setText(0, tr("[filter]"));
    555     m_pTreeWidgetFilters->setWhatsThis(tr("Lists all USB filters of this machine. The checkbox "
    556                                           "to the left defines whether the particular filter is enabled or not. Use the "
    557                                           "context menu or buttons to the right to add or remove USB filters."));
    558 
    559     m_pActionNew->setText(tr("Add Empty Filter"));
    560     m_pActionAdd->setText(tr("Add Filter From Device"));
    561     m_pActionEdit->setText(tr("Edit Filter"));
    562     m_pActionRemove->setText(tr("Remove Filter"));
    563     m_pActionMoveUp->setText(tr("Move Filter Up"));
    564     m_pActionMoveDown->setText(tr("Move Filter Down"));
    565 
    566     m_pActionNew->setToolTip(tr("Adds new USB filter with all fields initially set to empty strings. "
    567                                 "Note that such a filter will match any attached USB device."));
    568     m_pActionAdd->setToolTip(tr("Adds new USB filter with all fields set to the values of the "
    569                                 "selected USB device attached to the host PC."));
    570     m_pActionEdit->setToolTip(tr("Edits selected USB filter."));
    571     m_pActionRemove->setToolTip(tr("Removes selected USB filter."));
    572     m_pActionMoveUp->setToolTip(tr("Moves selected USB filter up."));
    573     m_pActionMoveDown->setToolTip(tr("Moves selected USB filter down."));
    574 
    575     m_pActionNew->setToolTip(m_pActionNew->whatsThis());
    576     m_pActionAdd->setToolTip(m_pActionAdd->whatsThis());
    577     m_pActionEdit->setToolTip(m_pActionEdit->whatsThis());
    578     m_pActionRemove->setToolTip(m_pActionRemove->whatsThis());
    579     m_pActionMoveUp->setToolTip(m_pActionMoveUp->whatsThis());
    580     m_pActionMoveDown->setToolTip(m_pActionMoveDown->whatsThis());
    581 
    582     m_strTrUSBFilterName = tr("New Filter %1", "usb");
    583343}
    584344
     
    596356    m_pWidgetUSBSettings->setEnabled(isMachineInValidMode() && fEnabled);
    597357    m_pEditorController->setEnabled(isMachineOffline() && fEnabled);
    598     if (fEnabled)
    599     {
    600         /* If there is no chosen item but there is something to choose => choose it: */
    601         if (m_pTreeWidgetFilters->currentItem() == 0 && m_pTreeWidgetFilters->topLevelItemCount() != 0)
    602             m_pTreeWidgetFilters->setCurrentItem(m_pTreeWidgetFilters->topLevelItem(0));
    603     }
    604     /* Update current item: */
    605     sltHandleCurrentItemChange(m_pTreeWidgetFilters->currentItem());
    606 }
    607 
    608 void UIMachineSettingsUSB::sltHandleCurrentItemChange(QTreeWidgetItem *pCurrentItem)
    609 {
    610     /* Get selected items: */
    611     QList<QTreeWidgetItem*> selectedItems = m_pTreeWidgetFilters->selectedItems();
    612     /* Deselect all selected items first: */
    613     for (int iItemIndex = 0; iItemIndex < selectedItems.size(); ++iItemIndex)
    614         selectedItems[iItemIndex]->setSelected(false);
    615 
    616     /* If tree-widget is NOT enabled => we should NOT select anything: */
    617     if (!m_pTreeWidgetFilters->isEnabled())
    618         return;
    619 
    620     /* Select item if requested: */
    621     if (pCurrentItem)
    622         pCurrentItem->setSelected(true);
    623 
    624     /* Update corresponding action states: */
    625     m_pActionEdit->setEnabled(pCurrentItem);
    626     m_pActionRemove->setEnabled(pCurrentItem);
    627     m_pActionMoveUp->setEnabled(pCurrentItem && m_pTreeWidgetFilters->itemAbove(pCurrentItem));
    628     m_pActionMoveDown->setEnabled(pCurrentItem && m_pTreeWidgetFilters->itemBelow(pCurrentItem));
    629 }
    630 
    631 void UIMachineSettingsUSB::sltHandleContextMenuRequest(const QPoint &pos)
    632 {
    633     QMenu menu;
    634     if (m_pTreeWidgetFilters->isEnabled())
    635     {
    636         menu.addAction(m_pActionNew);
    637         menu.addAction(m_pActionAdd);
    638         menu.addSeparator();
    639         menu.addAction(m_pActionEdit);
    640         menu.addSeparator();
    641         menu.addAction(m_pActionRemove);
    642         menu.addSeparator();
    643         menu.addAction(m_pActionMoveUp);
    644         menu.addAction(m_pActionMoveDown);
    645     }
    646     if (!menu.isEmpty())
    647         menu.exec(m_pTreeWidgetFilters->mapToGlobal(pos));
    648 }
    649 
    650 void UIMachineSettingsUSB::sltHandleActivityStateChange(QTreeWidgetItem *pChangedItem)
    651 {
    652     /* Check changed USB filter item: */
    653     UIUSBFilterItem *pItem = static_cast<UIUSBFilterItem*>(pChangedItem);
    654     AssertPtrReturnVoid(pItem);
    655 
    656     /* Update corresponding item: */
    657     pItem->m_fActive = pItem->checkState(0) == Qt::Checked;
    658 }
    659 
    660 void UIMachineSettingsUSB::sltNewFilter()
    661 {
    662     /* Search for the max available filter index: */
    663     int iMaxFilterIndex = 0;
    664     const QRegExp regExp(QString("^") + m_strTrUSBFilterName.arg("([0-9]+)") + QString("$"));
    665     QTreeWidgetItemIterator iterator(m_pTreeWidgetFilters);
    666     while (*iterator)
    667     {
    668         const QString filterName = (*iterator)->text(0);
    669         const int pos = regExp.indexIn(filterName);
    670         if (pos != -1)
    671             iMaxFilterIndex = regExp.cap(1).toInt() > iMaxFilterIndex ?
    672                               regExp.cap(1).toInt() : iMaxFilterIndex;
    673         ++iterator;
    674     }
    675 
    676     /* Prepare new USB filter data: */
    677     UIDataSettingsMachineUSBFilter filterData;
    678     filterData.m_fActive = true;
    679     filterData.m_strName = m_strTrUSBFilterName.arg(iMaxFilterIndex + 1);
    680     filterData.m_fHostUSBDevice = false;
    681 
    682     /* Add new USB filter item: */
    683     addUSBFilterItem(filterData, true /* its new? */);
    684 
    685     /* Revalidate: */
    686     revalidate();
    687 }
    688 
    689 void UIMachineSettingsUSB::sltAddFilter()
    690 {
    691     m_pMenuUSBDevices->exec(QCursor::pos());
    692 }
    693 
    694 void UIMachineSettingsUSB::sltAddFilterConfirmed(QAction *pAction)
    695 {
    696     /* Get USB device: */
    697     const CUSBDevice usb = m_pMenuUSBDevices->getUSB(pAction);
    698     if (usb.isNull())
    699         return;
    700 
    701     /* Prepare new USB filter data: */
    702     UIDataSettingsMachineUSBFilter filterData;
    703     filterData.m_fActive = true;
    704     filterData.m_strName = uiCommon().usbDetails(usb);
    705     filterData.m_fHostUSBDevice = false;
    706     filterData.m_strVendorId  = QString::number(usb.GetVendorId(),  16).toUpper().rightJustified(4, '0');
    707     filterData.m_strProductId = QString::number(usb.GetProductId(), 16).toUpper().rightJustified(4, '0');
    708     filterData.m_strRevision  = QString::number(usb.GetRevision(),  16).toUpper().rightJustified(4, '0');
    709     /* The port property depends on the host computer rather than on the USB
    710      * device itself; for this reason only a few people will want to use it
    711      * in the filter since the same device plugged into a different socket
    712      * will not match the filter in this case. */
    713 #if 0
    714     filterData.m_strPort = QString().sprintf("%04hX", usb.GetPort());
    715 #endif
    716     filterData.m_strManufacturer = usb.GetManufacturer();
    717     filterData.m_strProduct = usb.GetProduct();
    718     filterData.m_strSerialNumber = usb.GetSerialNumber();
    719     filterData.m_strRemote = QString::number(usb.GetRemote());
    720 
    721     /* Add new USB filter item: */
    722     addUSBFilterItem(filterData, true /* its new? */);
    723 
    724     /* Revalidate: */
    725     revalidate();
    726 }
    727 
    728 void UIMachineSettingsUSB::sltEditFilter()
    729 {
    730     /* Check current USB filter item: */
    731     UIUSBFilterItem *pItem = static_cast<UIUSBFilterItem*>(m_pTreeWidgetFilters->currentItem());
    732     AssertPtrReturnVoid(pItem);
    733 
    734     /* Configure USB filter details dialog: */
    735     UIUSBFilterDetailsEditor dlgFilterDetails(this);
    736     dlgFilterDetails.setName(pItem->m_strName);
    737     dlgFilterDetails.setVendorID(pItem->m_strVendorId);
    738     dlgFilterDetails.setProductID(pItem->m_strProductId);
    739     dlgFilterDetails.setRevision(pItem->m_strRevision);
    740     dlgFilterDetails.setManufacturer(pItem->m_strManufacturer);
    741     dlgFilterDetails.setProduct(pItem->m_strProduct);
    742     dlgFilterDetails.setSerialNo(pItem->m_strSerialNumber);
    743     dlgFilterDetails.setPort(pItem->m_strPort);
    744     const QString strRemote = pItem->m_strRemote.toLower();
    745     UIRemoteMode enmRemoteMode = UIRemoteMode_Any;
    746     if (strRemote == "yes" || strRemote == "true" || strRemote == "1")
    747         enmRemoteMode = UIRemoteMode_On;
    748     else if (strRemote == "no" || strRemote == "false" || strRemote == "0")
    749         enmRemoteMode = UIRemoteMode_Off;
    750     dlgFilterDetails.setRemoteMode(enmRemoteMode);
    751 
    752     /* Run USB filter details dialog: */
    753     if (dlgFilterDetails.exec() == QDialog::Accepted)
    754     {
    755         /* Update edited tree-widget item: */
    756         pItem->m_strName = dlgFilterDetails.name();
    757         pItem->m_strVendorId = dlgFilterDetails.vendorID();
    758         pItem->m_strProductId = dlgFilterDetails.productID();
    759         pItem->m_strRevision = dlgFilterDetails.revision();
    760         pItem->m_strManufacturer = dlgFilterDetails.manufacturer();
    761         pItem->m_strProduct = dlgFilterDetails.product();
    762         pItem->m_strSerialNumber = dlgFilterDetails.serialNo();
    763         pItem->m_strPort = dlgFilterDetails.port();
    764         switch (dlgFilterDetails.remoteMode())
    765         {
    766             case UIRemoteMode_Any: pItem->m_strRemote = QString(); break;
    767             case UIRemoteMode_On:  pItem->m_strRemote = QString::number(1); break;
    768             case UIRemoteMode_Off: pItem->m_strRemote = QString::number(0); break;
    769             default: break;
    770         }
    771         pItem->updateFields();
    772     }
    773 }
    774 
    775 void UIMachineSettingsUSB::sltRemoveFilter()
    776 {
    777     /* Check current USB filter item: */
    778     QTreeWidgetItem *pItem = m_pTreeWidgetFilters->currentItem();
    779     AssertPtrReturnVoid(pItem);
    780 
    781     /* Delete corresponding item: */
    782     delete pItem;
    783 
    784     /* Update current item: */
    785     sltHandleCurrentItemChange(m_pTreeWidgetFilters->currentItem());
    786 
    787     /* Revalidate: */
    788     revalidate();
    789 }
    790 
    791 void UIMachineSettingsUSB::sltMoveFilterUp()
    792 {
    793     /* Check current USB filter item: */
    794     QTreeWidgetItem *pItem = m_pTreeWidgetFilters->currentItem();
    795     AssertPtrReturnVoid(pItem);
    796 
    797     /* Move the item up: */
    798     const int iIndex = m_pTreeWidgetFilters->indexOfTopLevelItem(pItem);
    799     QTreeWidgetItem *pTakenItem = m_pTreeWidgetFilters->takeTopLevelItem(iIndex);
    800     Assert(pItem == pTakenItem);
    801     m_pTreeWidgetFilters->insertTopLevelItem(iIndex - 1, pTakenItem);
    802 
    803     /* Make sure moved item still chosen: */
    804     m_pTreeWidgetFilters->setCurrentItem(pTakenItem);
    805 }
    806 
    807 void UIMachineSettingsUSB::sltMoveFilterDown()
    808 {
    809     /* Check current USB filter item: */
    810     QTreeWidgetItem *pItem = m_pTreeWidgetFilters->currentItem();
    811     AssertPtrReturnVoid(pItem);
    812 
    813     /* Move the item down: */
    814     const int iIndex = m_pTreeWidgetFilters->indexOfTopLevelItem(pItem);
    815     QTreeWidgetItem *pTakenItem = m_pTreeWidgetFilters->takeTopLevelItem(iIndex);
    816     Assert(pItem == pTakenItem);
    817     m_pTreeWidgetFilters->insertTopLevelItem(iIndex + 1, pTakenItem);
    818 
    819     /* Make sure moved item still chosen: */
    820     m_pTreeWidgetFilters->setCurrentItem(pTakenItem);
    821358}
    822359
     
    869406                    pLayoutUSBSettings->addWidget(m_pEditorController);
    870407
    871                 /* Prepare separator: */
    872                 m_pLabelSeparatorFilters = new QILabelSeparator(m_pWidgetUSBSettings);
    873                 if (m_pLabelSeparatorFilters)
    874                     pLayoutUSBSettings->addWidget(m_pLabelSeparatorFilters);
    875 
    876                 /* Prepare USB filters layout: */
    877                 m_pLayoutFilters = new QHBoxLayout;
    878                 if (m_pLayoutFilters)
    879                 {
    880                     m_pLayoutFilters->setContentsMargins(0, 0, 0, 0);
    881                     m_pLayoutFilters->setSpacing(3);
    882 
    883                     /* Prepare USB filters tree-widget: */
    884                     prepareFiltersTreeWidget();
    885                     /* Prepare USB filters toolbar: */
    886                     prepareFiltersToolbar();
    887 
    888                     pLayoutUSBSettings->addLayout(m_pLayoutFilters);
    889                 }
     408                /* Prepare USB filters editor: */
     409                m_pEditorFilters = new UIUSBFiltersEditor(m_pWidgetUSBSettings);
     410                if (m_pEditorFilters)
     411                    pLayoutUSBSettings->addWidget(m_pEditorFilters);
    890412            }
    891413
    892414            pLayoutMain->addWidget(m_pWidgetUSBSettings, 1, 1, 1, 2);
    893415        }
    894     }
    895 }
    896 
    897 void UIMachineSettingsUSB::prepareFiltersTreeWidget()
    898 {
    899     /* Prepare USB filters tree-widget: */
    900     m_pTreeWidgetFilters = new QITreeWidget(m_pWidgetUSBSettings);
    901     if (m_pTreeWidgetFilters)
    902     {
    903         if (m_pLabelSeparatorFilters)
    904             m_pLabelSeparatorFilters->setBuddy(m_pTreeWidgetFilters);
    905         m_pTreeWidgetFilters->header()->hide();
    906         m_pTreeWidgetFilters->setRootIsDecorated(false);
    907         m_pTreeWidgetFilters->setContextMenuPolicy(Qt::CustomContextMenu);
    908 
    909         m_pLayoutFilters->addWidget(m_pTreeWidgetFilters);
    910     }
    911 }
    912 
    913 void UIMachineSettingsUSB::prepareFiltersToolbar()
    914 {
    915     /* Prepare USB filters toolbar: */
    916     m_pToolbarFilters = new QIToolBar(m_pWidgetUSBSettings);
    917     if (m_pToolbarFilters)
    918     {
    919         const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
    920         m_pToolbarFilters->setIconSize(QSize(iIconMetric, iIconMetric));
    921         m_pToolbarFilters->setOrientation(Qt::Vertical);
    922 
    923         /* Prepare 'New USB Filter' action: */
    924         m_pActionNew = m_pToolbarFilters->addAction(UIIconPool::iconSet(":/usb_new_16px.png",
    925                                                                         ":/usb_new_disabled_16px.png"),
    926                                                     QString(), this, SLOT(sltNewFilter()));
    927         if (m_pActionNew)
    928             m_pActionNew->setShortcuts(QList<QKeySequence>() << QKeySequence("Ins") << QKeySequence("Ctrl+N"));
    929 
    930         /* Prepare 'Add USB Filter' action: */
    931         m_pActionAdd = m_pToolbarFilters->addAction(UIIconPool::iconSet(":/usb_add_16px.png",
    932                                                                         ":/usb_add_disabled_16px.png"),
    933                                                     QString(), this, SLOT(sltAddFilter()));
    934         if (m_pActionAdd)
    935             m_pActionAdd->setShortcuts(QList<QKeySequence>() << QKeySequence("Alt+Ins") << QKeySequence("Ctrl+A"));
    936 
    937         /* Prepare 'Edit USB Filter' action: */
    938         m_pActionEdit = m_pToolbarFilters->addAction(UIIconPool::iconSet(":/usb_filter_edit_16px.png",
    939                                                                          ":/usb_filter_edit_disabled_16px.png"),
    940                                                      QString(), this, SLOT(sltEditFilter()));
    941         if (m_pActionEdit)
    942             m_pActionEdit->setShortcuts(QList<QKeySequence>() << QKeySequence("Alt+Return") << QKeySequence("Ctrl+Return"));
    943 
    944         /* Prepare 'Remove USB Filter' action: */
    945         m_pActionRemove = m_pToolbarFilters->addAction(UIIconPool::iconSet(":/usb_remove_16px.png",
    946                                                                            ":/usb_remove_disabled_16px.png"),
    947                                                        QString(), this, SLOT(sltRemoveFilter()));
    948         if (m_pActionRemove)
    949             m_pActionRemove->setShortcuts(QList<QKeySequence>() << QKeySequence("Del") << QKeySequence("Ctrl+R"));
    950 
    951         /* Prepare 'Move USB Filter Up' action: */
    952         m_pActionMoveUp = m_pToolbarFilters->addAction(UIIconPool::iconSet(":/usb_moveup_16px.png",
    953                                                                            ":/usb_moveup_disabled_16px.png"),
    954                                                        QString(), this, SLOT(sltMoveFilterUp()));
    955         if (m_pActionMoveUp)
    956             m_pActionMoveUp->setShortcuts(QList<QKeySequence>() << QKeySequence("Alt+Up") << QKeySequence("Ctrl+Up"));
    957 
    958         /* Prepare 'Move USB Filter Down' action: */
    959         m_pActionMoveDown = m_pToolbarFilters->addAction(UIIconPool::iconSet(":/usb_movedown_16px.png",
    960                                                                              ":/usb_movedown_disabled_16px.png"),
    961                                                          QString(), this, SLOT(sltMoveFilterDown()));
    962         if (m_pActionMoveDown)
    963             m_pActionMoveDown->setShortcuts(QList<QKeySequence>() << QKeySequence("Alt+Down") << QKeySequence("Ctrl+Down"));
    964 
    965         /* Prepare USB devices menu: */
    966         m_pMenuUSBDevices = new VBoxUSBMenu(this);
    967 
    968         m_pLayoutFilters->addWidget(m_pToolbarFilters);
    969416    }
    970417}
     
    977424    connect(m_pEditorController, &UIUSBControllerEditor::sigValueChanged,
    978425            this, &UIMachineSettingsUSB::revalidate);
     426    connect(m_pEditorFilters, &UIUSBFiltersEditor::sigValueChanged,
     427            this, &UIMachineSettingsUSB::revalidate);
    979428
    980429    /* Configure widget connections: */
    981430    connect(m_pCheckBoxUSB, &QCheckBox::toggled,
    982431            this, &UIMachineSettingsUSB::sltHandleUsbAdapterToggle);
    983     connect(m_pTreeWidgetFilters, &QITreeWidget::currentItemChanged,
    984             this, &UIMachineSettingsUSB::sltHandleCurrentItemChange);
    985     connect(m_pTreeWidgetFilters, &QITreeWidget::customContextMenuRequested,
    986             this, &UIMachineSettingsUSB::sltHandleContextMenuRequest);
    987     connect(m_pTreeWidgetFilters, &QITreeWidget::itemDoubleClicked,
    988             this, &UIMachineSettingsUSB::sltEditFilter);
    989     connect(m_pTreeWidgetFilters, &QITreeWidget::itemChanged,
    990             this, &UIMachineSettingsUSB::sltHandleActivityStateChange);
    991 
    992     /* Configure USB device menu connections: */
    993     connect(m_pMenuUSBDevices, &VBoxUSBMenu::triggered,
    994             this, &UIMachineSettingsUSB::sltAddFilterConfirmed);
    995432}
    996433
    997434void UIMachineSettingsUSB::cleanup()
    998435{
    999     /* Cleanup USB devices menu: */
    1000     delete m_pMenuUSBDevices;
    1001     m_pMenuUSBDevices = 0;
    1002 
    1003436    /* Cleanup cache: */
    1004437    delete m_pCache;
    1005438    m_pCache = 0;
    1006 }
    1007 
    1008 void UIMachineSettingsUSB::addUSBFilterItem(const UIDataSettingsMachineUSBFilter &filterData, bool fChoose)
    1009 {
    1010     /* Create USB filter item: */
    1011     UIUSBFilterItem *pItem = new UIUSBFilterItem(m_pTreeWidgetFilters);
    1012     AssertPtrReturnVoid(pItem);
    1013     {
    1014         /* Configure item: */
    1015         pItem->setCheckState(0, filterData.m_fActive ? Qt::Checked : Qt::Unchecked);
    1016         pItem->m_strName = filterData.m_strName;
    1017         pItem->m_strVendorId = filterData.m_strVendorId;
    1018         pItem->m_strProductId = filterData.m_strProductId;
    1019         pItem->m_strRevision = filterData.m_strRevision;
    1020         pItem->m_strManufacturer = filterData.m_strManufacturer;
    1021         pItem->m_strProduct = filterData.m_strProduct;
    1022         pItem->m_strSerialNumber = filterData.m_strSerialNumber;
    1023         pItem->m_strPort = filterData.m_strPort;
    1024         pItem->m_strRemote = filterData.m_strRemote;
    1025         pItem->m_enmAction = filterData.m_enmAction;
    1026         pItem->m_fHostUSBDevice = filterData.m_fHostUSBDevice;
    1027         pItem->m_enmHostUSBDeviceState = filterData.m_enmHostUSBDeviceState;
    1028         pItem->updateFields();
    1029 
    1030         /* Select this item if it's new: */
    1031         if (fChoose)
    1032         {
    1033             m_pTreeWidgetFilters->scrollToItem(pItem);
    1034             m_pTreeWidgetFilters->setCurrentItem(pItem);
    1035             sltHandleCurrentItemChange(pItem);
    1036         }
    1037     }
    1038439}
    1039440
     
    1310711    {
    1311712        /* Create filter: */
    1312         CUSBDeviceFilter comFilter = comFiltersObject.CreateDeviceFilter(filterData.m_strName);
     713        CUSBDeviceFilter comFilter = comFiltersObject.CreateDeviceFilter(filterData.m_guiData.m_strName);
    1313714        fSuccess = comFiltersObject.isOk() && comFilter.isNotNull();
    1314715
     
    1321722            if (fSuccess)
    1322723            {
    1323                 comFilter.SetActive(filterData.m_fActive);
     724                comFilter.SetActive(filterData.m_guiData.m_fActive);
    1324725                fSuccess = comFilter.isOk();
    1325726            }
     
    1327728            if (fSuccess)
    1328729            {
    1329                 comFilter.SetVendorId(filterData.m_strVendorId);
     730                comFilter.SetVendorId(filterData.m_guiData.m_strVendorId);
    1330731                fSuccess = comFilter.isOk();
    1331732            }
     
    1333734            if (fSuccess)
    1334735            {
    1335                 comFilter.SetProductId(filterData.m_strProductId);
     736                comFilter.SetProductId(filterData.m_guiData.m_strProductId);
    1336737                fSuccess = comFilter.isOk();
    1337738            }
     
    1339740            if (fSuccess)
    1340741            {
    1341                 comFilter.SetRevision(filterData.m_strRevision);
     742                comFilter.SetRevision(filterData.m_guiData.m_strRevision);
    1342743                fSuccess = comFilter.isOk();
    1343744            }
     
    1345746            if (fSuccess)
    1346747            {
    1347                 comFilter.SetManufacturer(filterData.m_strManufacturer);
     748                comFilter.SetManufacturer(filterData.m_guiData.m_strManufacturer);
    1348749                fSuccess = comFilter.isOk();
    1349750            }
     
    1351752            if (fSuccess)
    1352753            {
    1353                 comFilter.SetProduct(filterData.m_strProduct);
     754                comFilter.SetProduct(filterData.m_guiData.m_strProduct);
    1354755                fSuccess = comFilter.isOk();
    1355756            }
     
    1357758            if (fSuccess)
    1358759            {
    1359                 comFilter.SetSerialNumber(filterData.m_strSerialNumber);
     760                comFilter.SetSerialNumber(filterData.m_guiData.m_strSerialNumber);
    1360761                fSuccess = comFilter.isOk();
    1361762            }
     
    1363764            if (fSuccess)
    1364765            {
    1365                 comFilter.SetPort(filterData.m_strPort);
     766                comFilter.SetPort(filterData.m_guiData.m_strPort);
    1366767                fSuccess = comFilter.isOk();
    1367768            }
     
    1369770            if (fSuccess)
    1370771            {
    1371                 comFilter.SetRemote(filterData.m_strRemote);
     772                QString strRemote;
     773                switch (filterData.m_guiData.m_enmRemoteMode)
     774                {
     775                    case UIRemoteMode_On: strRemote = "1"; break;
     776                    case UIRemoteMode_Off: strRemote = "0"; break;
     777                    default: break;
     778                }
     779                comFilter.SetRemote(strRemote);
    1372780                fSuccess = comFilter.isOk();
    1373781            }
     
    1391799    return fSuccess;
    1392800}
    1393 
    1394 
    1395 #include "UIMachineSettingsUSB.moc"
  • trunk/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSB.h

    r95247 r95277  
    2727/* Forward declarations: */
    2828class QCheckBox;
    29 class QHBoxLayout;
    30 class QTreeWidgetItem;
    31 class QILabelSeparator;
    32 class QIToolBar;
    33 class QITreeWidget;
    34 class VBoxUSBMenu;
    3529class UIUSBControllerEditor;
     30class UIUSBFiltersEditor;
    3631struct UIDataSettingsMachineUSB;
    3732struct UIDataSettingsMachineUSBFilter;
     
    9085    void sltHandleUsbAdapterToggle(bool fEnabled);
    9186
    92     /** Handles USB filter tree @a pCurrentItem change. */
    93     void sltHandleCurrentItemChange(QTreeWidgetItem *pCurrentItem);
    94     /** Handles context menu request for @a position of USB filter tree. */
    95     void sltHandleContextMenuRequest(const QPoint &position);
    96     /** Handles USB filter tree activity state change for @a pChangedItem. */
    97     void sltHandleActivityStateChange(QTreeWidgetItem *pChangedItem);
    98 
    99     /** Handles command to add new USB filter. */
    100     void sltNewFilter();
    101     /** Handles command to add existing USB filter. */
    102     void sltAddFilter();
    103     /** Handles command to edit USB filter. */
    104     void sltEditFilter();
    105     /** Handles command to confirm add of existing USB filter defined by @a pAction. */
    106     void sltAddFilterConfirmed(QAction *pAction);
    107     /** Handles command to remove chosen USB filter. */
    108     void sltRemoveFilter();
    109     /** Handles command to move chosen USB filter up. */
    110     void sltMoveFilterUp();
    111     /** Handles command to move chosen USB filter down. */
    112     void sltMoveFilterDown();
    113 
    11487private:
    11588
     
    11891    /** Prepares widgets. */
    11992    void prepareWidgets();
    120     /** Prepares filters tree-widget. */
    121     void prepareFiltersTreeWidget();
    122     /** Prepares filters toolbar. */
    123     void prepareFiltersToolbar();
    12493    /** Prepares connections. */
    12594    void prepareConnections();
    12695    /** Cleanups all. */
    12796    void cleanup();
    128 
    129     /** Adds USB filter item based on a given @a filterData, fChoose if requested. */
    130     void addUSBFilterItem(const UIDataSettingsMachineUSBFilter &filterData, bool fChoose);
    13197
    13298    /** Saves existing data from cache. */
     
    141107    bool createUSBFilter(CUSBDeviceFilters &comFiltersObject, int iPosition, const UIDataSettingsMachineUSBFilter &filterData);
    142108
    143     /** Holds the "New Filter %1" translation tag. */
    144     QString  m_strTrUSBFilterName;
    145 
    146109    /** Holds the page data cache instance. */
    147110    UISettingsCacheMachineUSB *m_pCache;
     
    155118        /** Holds the USB controller editor instance. */
    156119        UIUSBControllerEditor *m_pEditorController;
    157         /** Holds the USB widget separator instance. */
    158         QILabelSeparator      *m_pLabelSeparatorFilters;
    159         /** Holds the USB filters layout instance. */
    160         QHBoxLayout           *m_pLayoutFilters;
    161         /** Holds the USB filters tree-widget instance. */
    162         QITreeWidget          *m_pTreeWidgetFilters;
    163         /** Holds the USB filters toolbar instance. */
    164         QIToolBar             *m_pToolbarFilters;
    165         /** Holds the New action instance. */
    166         QAction               *m_pActionNew;
    167         /** Holds the Add action instance. */
    168         QAction               *m_pActionAdd;
    169         /** Holds the Edit action instance. */
    170         QAction               *m_pActionEdit;
    171         /** Holds the Remove action instance. */
    172         QAction               *m_pActionRemove;
    173         /** Holds the Move Up action instance. */
    174         QAction               *m_pActionMoveUp;
    175         /** Holds the Move Down action instance. */
    176         QAction               *m_pActionMoveDown;
    177         /** Holds the USB devices menu instance. */
    178         VBoxUSBMenu           *m_pMenuUSBDevices;
     120        /** Holds the USB filters editor instance. */
     121        UIUSBFiltersEditor    *m_pEditorFilters;
    179122    /** @} */
    180123};
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette