~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsPortForwardingDlg.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: UIMachineSettingsPortForwardingDlg.cpp 33882 2010-11-09 09:32:27Z vboxsync $ */
 
2
/** @file
 
3
 *
 
4
 * VBox frontends: Qt4 GUI ("VirtualBox"):
 
5
 * UIMachineSettingsPortForwardingDlg class implementation
 
6
 */
 
7
 
 
8
/*
 
9
 * Copyright (C) 2010 Oracle Corporation
 
10
 *
 
11
 * This file is part of VirtualBox Open Source Edition (OSE), as
 
12
 * available from http://www.virtualbox.org. This file is free software;
 
13
 * you can redistribute it and/or modify it under the terms of the GNU
 
14
 * General Public License (GPL) as published by the Free Software
 
15
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 
16
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 
17
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 
18
 */
 
19
 
 
20
/* Global includes */
 
21
#include <QAction>
 
22
#include <QHeaderView>
 
23
#include <QPushButton>
 
24
#include <QStyledItemDelegate>
 
25
#include <QItemEditorFactory>
 
26
#include <QComboBox>
 
27
#include <QLineEdit>
 
28
#include <QSpinBox>
 
29
#include <QTimer>
 
30
 
 
31
/* Local includes */
 
32
#include "UIMachineSettingsPortForwardingDlg.h"
 
33
#include "VBoxGlobal.h"
 
34
#include "VBoxProblemReporter.h"
 
35
#include "UIToolBar.h"
 
36
#include "QITableView.h"
 
37
#include "QIDialogButtonBox.h"
 
38
#include "UIIconPool.h"
 
39
#include <iprt/cidr.h>
 
40
#include <math.h>
 
41
 
 
42
/* IP validator: */
 
43
class IPValidator : public QValidator
 
44
{
 
45
    Q_OBJECT;
 
46
 
 
47
public:
 
48
 
 
49
    IPValidator(QObject *pParent) : QValidator(pParent) {}
 
50
    ~IPValidator() {}
 
51
 
 
52
    QValidator::State validate(QString &strInput, int & /* iPos */) const
 
53
    {
 
54
        QString strStringToValidate(strInput);
 
55
        strStringToValidate.remove(' ');
 
56
        QString strDot("\\.");
 
57
        QString strDigits("(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)");
 
58
        QRegExp intRegExp(QString("^(%1?(%2(%1?(%2(%1?(%2%1?)?)?)?)?)?)?$").arg(strDigits).arg(strDot));
 
59
        uint uNetwork, uMask;
 
60
        if (strStringToValidate == "..." || RTCidrStrToIPv4(strStringToValidate.toLatin1().constData(), &uNetwork, &uMask) == VINF_SUCCESS)
 
61
            return QValidator::Acceptable;
 
62
        else if (intRegExp.indexIn(strStringToValidate) != -1)
 
63
            return QValidator::Intermediate;
 
64
        else
 
65
            return QValidator::Invalid;
 
66
    }
 
67
};
 
68
 
 
69
/* Name editor: */
 
70
class NameEditor : public QLineEdit
 
71
{
 
72
    Q_OBJECT;
 
73
    Q_PROPERTY(NameData name READ name WRITE setName USER true);
 
74
 
 
75
public:
 
76
 
 
77
    NameEditor(QWidget *pParent = 0) : QLineEdit(pParent)
 
78
    {
 
79
        setFrame(false);
 
80
        setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
 
81
        setValidator(new QRegExpValidator(QRegExp("[^,]*"), this));
 
82
    }
 
83
 
 
84
private:
 
85
 
 
86
    void setName(NameData name)
 
87
    {
 
88
        setText(name);
 
89
    }
 
90
 
 
91
    NameData name() const
 
92
    {
 
93
        return text();
 
94
    }
 
95
};
 
96
 
 
97
/* Protocol editor: */
 
98
class ProtocolEditor : public QComboBox
 
99
{
 
100
    Q_OBJECT;
 
101
    Q_PROPERTY(KNATProtocol protocol READ protocol WRITE setProtocol USER true);
 
102
 
 
103
public:
 
104
 
 
105
    ProtocolEditor(QWidget *pParent = 0) : QComboBox(pParent)
 
106
    {
 
107
        addItem(vboxGlobal().toString(KNATProtocol_UDP), QVariant::fromValue(KNATProtocol_UDP));
 
108
        addItem(vboxGlobal().toString(KNATProtocol_TCP), QVariant::fromValue(KNATProtocol_TCP));
 
109
    }
 
110
 
 
111
private:
 
112
 
 
113
    void setProtocol(KNATProtocol p)
 
114
    {
 
115
        for (int i = 0; i < count(); ++i)
 
116
        {
 
117
            if (itemData(i).value<KNATProtocol>() == p)
 
118
            {
 
119
                setCurrentIndex(i);
 
120
                break;
 
121
            }
 
122
        }
 
123
    }
 
124
 
 
125
    KNATProtocol protocol() const
 
126
    {
 
127
        return itemData(currentIndex()).value<KNATProtocol>();
 
128
    }
 
129
};
 
130
 
 
131
/* IP editor: */
 
132
class IPEditor : public QLineEdit
 
133
{
 
134
    Q_OBJECT;
 
135
    Q_PROPERTY(IpData ip READ ip WRITE setIp USER true);
 
136
 
 
137
public:
 
138
 
 
139
    IPEditor(QWidget *pParent = 0) : QLineEdit(pParent)
 
140
    {
 
141
        setFrame(false);
 
142
        setAlignment(Qt::AlignCenter);
 
143
        setValidator(new IPValidator(this));
 
144
        setInputMask("000.000.000.000");
 
145
    }
 
146
 
 
147
private:
 
148
 
 
149
    void setIp(IpData ip)
 
150
    {
 
151
        setText(ip);
 
152
    }
 
153
 
 
154
    IpData ip() const
 
155
    {
 
156
        return text() == "..." ? QString() : text();
 
157
    }
 
158
};
 
159
 
 
160
/* Port editor: */
 
161
class PortEditor : public QSpinBox
 
162
{
 
163
    Q_OBJECT;
 
164
    Q_PROPERTY(PortData port READ port WRITE setPort USER true);
 
165
 
 
166
public:
 
167
 
 
168
    PortEditor(QWidget *pParent = 0) : QSpinBox(pParent)
 
169
    {
 
170
        setFrame(false);
 
171
        setRange(0, (1 << (8 * sizeof(ushort))) - 1);
 
172
    }
 
173
 
 
174
private:
 
175
 
 
176
    void setPort(PortData port)
 
177
    {
 
178
        setValue(port.value());
 
179
    }
 
180
 
 
181
    PortData port() const
 
182
    {
 
183
        return value();
 
184
    }
 
185
};
 
186
 
 
187
/* Port forwarding data model: */
 
188
class UIPortForwardingModel : public QAbstractTableModel
 
189
{
 
190
    Q_OBJECT;
 
191
 
 
192
public:
 
193
 
 
194
    /* Column names: */
 
195
    enum UIPortForwardingDataType
 
196
    {
 
197
        UIPortForwardingDataType_Name,
 
198
        UIPortForwardingDataType_Protocol,
 
199
        UIPortForwardingDataType_HostIp,
 
200
        UIPortForwardingDataType_HostPort,
 
201
        UIPortForwardingDataType_GuestIp,
 
202
        UIPortForwardingDataType_GuestPort,
 
203
        UIPortForwardingDataType_Max
 
204
    };
 
205
 
 
206
    /* Port forwarding model constructor: */
 
207
    UIPortForwardingModel(QObject *pParent = 0, const UIPortForwardingDataList &rules = UIPortForwardingDataList())
 
208
        : QAbstractTableModel(pParent), m_dataList(rules) {}
 
209
    /* Port forwarding model destructor: */
 
210
    ~UIPortForwardingModel() {}
 
211
 
 
212
    /* The list of chosen rules: */
 
213
    const UIPortForwardingDataList& rules() const
 
214
    {
 
215
        return m_dataList;
 
216
    }
 
217
 
 
218
    /* Flags for model indexes: */
 
219
    Qt::ItemFlags flags(const QModelIndex &index) const
 
220
    {
 
221
        /* Check index validness: */
 
222
        if (!index.isValid())
 
223
            return Qt::NoItemFlags;
 
224
        /* All columns have similar flags: */
 
225
        return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
 
226
    }
 
227
 
 
228
    /* Row count getter: */
 
229
    int rowCount(const QModelIndex & parent = QModelIndex()) const
 
230
    {
 
231
        Q_UNUSED(parent);
 
232
        return m_dataList.size();
 
233
    }
 
234
 
 
235
    /* Column count getter: */
 
236
    int columnCount(const QModelIndex & parent = QModelIndex()) const
 
237
    {
 
238
        Q_UNUSED(parent);
 
239
        return UIPortForwardingDataType_Max;
 
240
    }
 
241
 
 
242
    /* Get header data: */
 
243
    QVariant headerData(int iSection, Qt::Orientation orientation, int iRole) const
 
244
    {
 
245
        /* Display role for horizontal header: */
 
246
        if (iRole == Qt::DisplayRole && orientation == Qt::Horizontal)
 
247
        {
 
248
            /* Switch for different columns: */
 
249
            switch (iSection)
 
250
            {
 
251
                case UIPortForwardingDataType_Name: return tr("Name");
 
252
                case UIPortForwardingDataType_Protocol: return tr("Protocol");
 
253
                case UIPortForwardingDataType_HostIp: return tr("Host IP");
 
254
                case UIPortForwardingDataType_HostPort: return tr("Host Port");
 
255
                case UIPortForwardingDataType_GuestIp: return tr("Guest IP");
 
256
                case UIPortForwardingDataType_GuestPort: return tr("Guest Port");
 
257
                default: break;
 
258
            }
 
259
        }
 
260
        /* Return wrong value: */
 
261
        return QVariant();
 
262
    }
 
263
 
 
264
    /* Get index data: */
 
265
    QVariant data(const QModelIndex &index, int iRole) const
 
266
    {
 
267
        /* Check index validness: */
 
268
        if (!index.isValid())
 
269
            return QVariant();
 
270
        /* Switch for different roles: */
 
271
        switch (iRole)
 
272
        {
 
273
            /* Display role: */
 
274
            case Qt::DisplayRole:
 
275
            {
 
276
                /* Switch for different columns: */
 
277
                switch (index.column())
 
278
                {
 
279
                    case UIPortForwardingDataType_Name: return m_dataList[index.row()].name;
 
280
                    case UIPortForwardingDataType_Protocol: return vboxGlobal().toString(m_dataList[index.row()].protocol);
 
281
                    case UIPortForwardingDataType_HostIp: return m_dataList[index.row()].hostIp;
 
282
                    case UIPortForwardingDataType_HostPort: return m_dataList[index.row()].hostPort.value();
 
283
                    case UIPortForwardingDataType_GuestIp: return m_dataList[index.row()].guestIp;
 
284
                    case UIPortForwardingDataType_GuestPort: return m_dataList[index.row()].guestPort.value();
 
285
                    default: return QVariant();
 
286
                }
 
287
            }
 
288
            /* Edit role: */
 
289
            case Qt::EditRole:
 
290
            {
 
291
                /* Switch for different columns: */
 
292
                switch (index.column())
 
293
                {
 
294
                    case UIPortForwardingDataType_Name: return QVariant::fromValue(m_dataList[index.row()].name);
 
295
                    case UIPortForwardingDataType_Protocol: return QVariant::fromValue(m_dataList[index.row()].protocol);
 
296
                    case UIPortForwardingDataType_HostIp: return QVariant::fromValue(m_dataList[index.row()].hostIp);
 
297
                    case UIPortForwardingDataType_HostPort: return QVariant::fromValue(m_dataList[index.row()].hostPort);
 
298
                    case UIPortForwardingDataType_GuestIp: return QVariant::fromValue(m_dataList[index.row()].guestIp);
 
299
                    case UIPortForwardingDataType_GuestPort: return QVariant::fromValue(m_dataList[index.row()].guestPort);
 
300
                    default: return QVariant();
 
301
                }
 
302
            }
 
303
            /* Alignment role: */
 
304
            case Qt::TextAlignmentRole:
 
305
            {
 
306
                /* Switch for different columns: */
 
307
                switch (index.column())
 
308
                {
 
309
                    case UIPortForwardingDataType_Name:
 
310
                    case UIPortForwardingDataType_Protocol:
 
311
                    case UIPortForwardingDataType_HostPort:
 
312
                    case UIPortForwardingDataType_GuestPort:
 
313
                        return (int)(Qt::AlignLeft | Qt::AlignVCenter);
 
314
                    case UIPortForwardingDataType_HostIp:
 
315
                    case UIPortForwardingDataType_GuestIp:
 
316
                        return Qt::AlignCenter;
 
317
                    default: return QVariant();
 
318
                }
 
319
            }
 
320
            case Qt::SizeHintRole:
 
321
            {
 
322
                /* Switch for different columns: */
 
323
                switch (index.column())
 
324
                {
 
325
                    case UIPortForwardingDataType_HostIp:
 
326
                    case UIPortForwardingDataType_GuestIp:
 
327
                        return QSize(QApplication::fontMetrics().width(" 888.888.888.888 "), QApplication::fontMetrics().height());
 
328
                    default: return QVariant();
 
329
                }
 
330
            }
 
331
            default: break;
 
332
        }
 
333
        /* Return wrong value: */
 
334
        return QVariant();
 
335
    }
 
336
 
 
337
    /* Set index data: */
 
338
    bool setData(const QModelIndex &index, const QVariant &value, int iRole = Qt::EditRole)
 
339
    {
 
340
        /* Check index validness: */
 
341
        if (!index.isValid() || iRole != Qt::EditRole)
 
342
            return false;
 
343
        /* Switch for different columns: */
 
344
        switch (index.column())
 
345
        {
 
346
            case UIPortForwardingDataType_Name:
 
347
                m_dataList[index.row()].name = value.value<NameData>();
 
348
                emit dataChanged(index, index);
 
349
                return true;
 
350
            case UIPortForwardingDataType_Protocol:
 
351
                m_dataList[index.row()].protocol = value.value<KNATProtocol>();
 
352
                emit dataChanged(index, index);
 
353
                return true;
 
354
            case UIPortForwardingDataType_HostIp:
 
355
                m_dataList[index.row()].hostIp = value.value<IpData>();
 
356
                emit dataChanged(index, index);
 
357
                return true;
 
358
            case UIPortForwardingDataType_HostPort:
 
359
                m_dataList[index.row()].hostPort = value.value<PortData>();
 
360
                emit dataChanged(index, index);
 
361
                return true;
 
362
            case UIPortForwardingDataType_GuestIp:
 
363
                m_dataList[index.row()].guestIp = value.value<IpData>();
 
364
                emit dataChanged(index, index);
 
365
                return true;
 
366
            case UIPortForwardingDataType_GuestPort:
 
367
                m_dataList[index.row()].guestPort = value.value<PortData>();
 
368
                emit dataChanged(index, index);
 
369
                return true;
 
370
            default: return false;
 
371
        }
 
372
        /* Return false value: */
 
373
        return false;
 
374
    }
 
375
 
 
376
    /* Add/Copy rule: */
 
377
    void addRule(const QModelIndex &index)
 
378
    {
 
379
        beginInsertRows(QModelIndex(), m_dataList.size(), m_dataList.size());
 
380
        /* Search for existing "Rule [NUMBER]" record: */
 
381
        uint uMaxIndex = 0;
 
382
        QString strTemplate("Rule %1");
 
383
        QRegExp regExp(strTemplate.arg("(\\d+)"));
 
384
        for (int i = 0; i < m_dataList.size(); ++i)
 
385
            if (regExp.indexIn(m_dataList[i].name) > -1)
 
386
                uMaxIndex = regExp.cap(1).toUInt() > uMaxIndex ? regExp.cap(1).toUInt() : uMaxIndex;
 
387
        /* If index is valid => copy data: */
 
388
        if (index.isValid())
 
389
            m_dataList << UIPortForwardingData(strTemplate.arg(++uMaxIndex), m_dataList[index.row()].protocol,
 
390
                                               m_dataList[index.row()].hostIp, m_dataList[index.row()].hostPort,
 
391
                                               m_dataList[index.row()].guestIp, m_dataList[index.row()].guestPort);
 
392
        /* If index is NOT valid => use default values: */
 
393
        else
 
394
            m_dataList << UIPortForwardingData(strTemplate.arg(++uMaxIndex), KNATProtocol_TCP,
 
395
                                               QString(""), 0, QString(""), 0);
 
396
        endInsertRows();
 
397
    }
 
398
 
 
399
    /* Delete rule: */
 
400
    void delRule(const QModelIndex &index)
 
401
    {
 
402
        if (!index.isValid())
 
403
            return;
 
404
        beginRemoveRows(QModelIndex(), index.row(), index.row());
 
405
        m_dataList.removeAt(index.row());
 
406
        endRemoveRows();
 
407
    }
 
408
 
 
409
private:
 
410
 
 
411
    /* Data container: */
 
412
    UIPortForwardingDataList m_dataList;
 
413
};
 
414
 
 
415
/* Port forwarding dialog constructor: */
 
416
UIMachineSettingsPortForwardingDlg::UIMachineSettingsPortForwardingDlg(QWidget *pParent,
 
417
                                                                 const UIPortForwardingDataList &rules)
 
418
    : QIWithRetranslateUI<QIDialog>(pParent)
 
419
    , fIsTableDataChanged(false)
 
420
    , m_pTableView(0)
 
421
    , m_pToolBar(0)
 
422
    , m_pButtonBox(0)
 
423
    , m_pModel(0)
 
424
    , m_pAddAction(0)
 
425
    , m_pCopyAction(0)
 
426
    , m_pDelAction(0)
 
427
{
 
428
#ifdef Q_WS_MAC
 
429
    setWindowFlags(Qt::Sheet);
 
430
#endif /* Q_WS_MAC */
 
431
 
 
432
    /* Set dialog icon: */
 
433
    setWindowIcon(UIIconPool::iconSetFull(QSize(32, 32), QSize(16, 16), ":/nw_32px.png", ":/nw_16px.png"));
 
434
 
 
435
    /* Create table: */
 
436
    m_pTableView = new QITableView(this);
 
437
    m_pTableView->setTabKeyNavigation(false);
 
438
    m_pTableView->verticalHeader()->hide();
 
439
    m_pTableView->verticalHeader()->setDefaultSectionSize((int)m_pTableView->verticalHeader()->minimumSectionSize() * 1.33);
 
440
    m_pTableView->setSelectionMode(QAbstractItemView::SingleSelection);
 
441
    m_pTableView->setContextMenuPolicy(Qt::CustomContextMenu);
 
442
    m_pTableView->installEventFilter(this);
 
443
    connect(m_pTableView, SIGNAL(sigCurrentChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(sltCurrentChanged()));
 
444
    connect(m_pTableView, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(sltShowTableContexMenu(const QPoint &)));
 
445
 
 
446
    /* Create actions: */
 
447
    m_pAddAction = new QAction(this);
 
448
    m_pCopyAction = new QAction(this);
 
449
    m_pDelAction = new QAction(this);
 
450
    m_pAddAction->setShortcut(QKeySequence("Ins"));
 
451
    m_pDelAction->setShortcut(QKeySequence("Del"));
 
452
    m_pAddAction->setIcon(UIIconPool::iconSet(":/controller_add_16px.png", ":/controller_add_disabled_16px.png"));
 
453
    m_pCopyAction->setIcon(UIIconPool::iconSet(":/controller_add_16px.png", ":/controller_add_disabled_16px.png"));
 
454
    m_pDelAction->setIcon(UIIconPool::iconSet(":/controller_remove_16px.png", ":/controller_remove_disabled_16px.png"));
 
455
    connect(m_pAddAction, SIGNAL(triggered(bool)), this, SLOT(sltAddRule()));
 
456
    connect(m_pCopyAction, SIGNAL(triggered(bool)), this, SLOT(sltCopyRule()));
 
457
    connect(m_pDelAction, SIGNAL(triggered(bool)), this, SLOT(sltDelRule()));
 
458
 
 
459
    /* Create toolbar: */
 
460
    m_pToolBar = new UIToolBar(this);
 
461
    m_pToolBar->setIconSize(QSize(16, 16));
 
462
    m_pToolBar->setOrientation(Qt::Vertical);
 
463
    m_pToolBar->addAction(m_pAddAction);
 
464
    m_pToolBar->addAction(m_pDelAction);
 
465
 
 
466
    /* Create table & toolbar layout: */
 
467
    QHBoxLayout *pTableAndToolbarLayout = new QHBoxLayout;
 
468
    pTableAndToolbarLayout->setSpacing(1);
 
469
    pTableAndToolbarLayout->addWidget(m_pTableView);
 
470
    pTableAndToolbarLayout->addWidget(m_pToolBar);
 
471
 
 
472
    /* Create buttonbox: */
 
473
    m_pButtonBox = new QIDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this);
 
474
    connect(m_pButtonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(accept()));
 
475
    connect(m_pButtonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(reject()));
 
476
 
 
477
    /* Create main layout: */
 
478
    QVBoxLayout *pMainLayout = new QVBoxLayout;
 
479
    this->setLayout(pMainLayout);
 
480
    pMainLayout->addLayout(pTableAndToolbarLayout);
 
481
    pMainLayout->addWidget(m_pButtonBox);
 
482
 
 
483
    /* Create model: */
 
484
    m_pModel = new UIPortForwardingModel(this, rules);
 
485
    connect(m_pModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(sltTableDataChanged()));
 
486
    connect(m_pModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(sltTableDataChanged()));
 
487
    connect(m_pModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), this, SLOT(sltTableDataChanged()));
 
488
    m_pTableView->setModel(m_pModel);
 
489
 
 
490
    /* Register delegates editors: */
 
491
    if (QAbstractItemDelegate *pAbstractItemDelegate = m_pTableView->itemDelegate())
 
492
    {
 
493
        if (QStyledItemDelegate *pStyledItemDelegate = qobject_cast<QStyledItemDelegate*>(pAbstractItemDelegate))
 
494
        {
 
495
            /* Create new item editor factory: */
 
496
            QItemEditorFactory *pNewItemEditorFactory = new QItemEditorFactory;
 
497
 
 
498
            /* Register name type: */
 
499
            int iNameId = qRegisterMetaType<NameData>();
 
500
            /* Register name editor: */
 
501
            QStandardItemEditorCreator<NameEditor> *pNameEditorItemCreator = new QStandardItemEditorCreator<NameEditor>();
 
502
            /* Link name type & editor: */
 
503
            pNewItemEditorFactory->registerEditor((QVariant::Type)iNameId, pNameEditorItemCreator);
 
504
 
 
505
            /* Register protocol type: */
 
506
            int iProtocolId = qRegisterMetaType<KNATProtocol>();
 
507
            /* Register protocol editor: */
 
508
            QStandardItemEditorCreator<ProtocolEditor> *pProtocolEditorItemCreator = new QStandardItemEditorCreator<ProtocolEditor>();
 
509
            /* Link protocol type & editor: */
 
510
            pNewItemEditorFactory->registerEditor((QVariant::Type)iProtocolId, pProtocolEditorItemCreator);
 
511
 
 
512
            /* Register ip type: */
 
513
            int iIpId = qRegisterMetaType<IpData>();
 
514
            /* Register ip editor: */
 
515
            QStandardItemEditorCreator<IPEditor> *pIpEditorItemCreator = new QStandardItemEditorCreator<IPEditor>();
 
516
            /* Link ip type & editor: */
 
517
            pNewItemEditorFactory->registerEditor((QVariant::Type)iIpId, pIpEditorItemCreator);
 
518
 
 
519
            /* Register port type: */
 
520
            int iPortId = qRegisterMetaType<PortData>();
 
521
            /* Register port editor: */
 
522
            QStandardItemEditorCreator<PortEditor> *pPortEditorItemCreator = new QStandardItemEditorCreator<PortEditor>();
 
523
            /* Link port type & editor: */
 
524
            pNewItemEditorFactory->registerEditor((QVariant::Type)iPortId, pPortEditorItemCreator);
 
525
 
 
526
            /* Set newly created item editor factory for table delegate: */
 
527
            pStyledItemDelegate->setItemEditorFactory(pNewItemEditorFactory);
 
528
        }
 
529
    }
 
530
 
 
531
    /* Retranslate dialog: */
 
532
    retranslateUi();
 
533
 
 
534
    /* Minimum Size: */
 
535
    setMinimumSize(600, 300);
 
536
}
 
537
 
 
538
/* Port forwarding dialog destructor: */
 
539
UIMachineSettingsPortForwardingDlg::~UIMachineSettingsPortForwardingDlg()
 
540
{
 
541
}
 
542
 
 
543
const UIPortForwardingDataList& UIMachineSettingsPortForwardingDlg::rules() const
 
544
{
 
545
    return m_pModel->rules();
 
546
}
 
547
 
 
548
/* Add rule slot: */
 
549
void UIMachineSettingsPortForwardingDlg::sltAddRule()
 
550
{
 
551
    m_pModel->addRule(QModelIndex());
 
552
    m_pTableView->setFocus();
 
553
    m_pTableView->setCurrentIndex(m_pModel->index(m_pModel->rowCount() - 1, 0));
 
554
    sltCurrentChanged();
 
555
    sltAdjustTable();
 
556
}
 
557
 
 
558
/* Copy rule slot: */
 
559
void UIMachineSettingsPortForwardingDlg::sltCopyRule()
 
560
{
 
561
    m_pModel->addRule(m_pTableView->currentIndex());
 
562
    m_pTableView->setFocus();
 
563
    m_pTableView->setCurrentIndex(m_pModel->index(m_pModel->rowCount() - 1, 0));
 
564
    sltCurrentChanged();
 
565
    sltAdjustTable();
 
566
}
 
567
 
 
568
/* Del rule slot: */
 
569
void UIMachineSettingsPortForwardingDlg::sltDelRule()
 
570
{
 
571
    m_pModel->delRule(m_pTableView->currentIndex());
 
572
    m_pTableView->setFocus();
 
573
    sltCurrentChanged();
 
574
    sltAdjustTable();
 
575
}
 
576
 
 
577
/* Table data change handler: */
 
578
void UIMachineSettingsPortForwardingDlg::sltTableDataChanged()
 
579
{
 
580
    fIsTableDataChanged = true;
 
581
}
 
582
 
 
583
/* Table index-change handler: */
 
584
void UIMachineSettingsPortForwardingDlg::sltCurrentChanged()
 
585
{
 
586
    bool fTableFocused = m_pTableView->hasFocus();
 
587
    bool fTableChildrenFocused = m_pTableView->findChildren<QWidget*>().contains(QApplication::focusWidget());
 
588
    bool fTableOrChildrenFocused = fTableFocused || fTableChildrenFocused;
 
589
    m_pCopyAction->setEnabled(m_pTableView->currentIndex().isValid() && fTableOrChildrenFocused);
 
590
    m_pDelAction->setEnabled(m_pTableView->currentIndex().isValid() && fTableOrChildrenFocused);
 
591
}
 
592
 
 
593
/* Table context-menu handler: */
 
594
void UIMachineSettingsPortForwardingDlg::sltShowTableContexMenu(const QPoint &pos)
 
595
{
 
596
    /* Prepare context menu: */
 
597
    QMenu menu(m_pTableView);
 
598
    /* If some index is currently selected: */
 
599
    if (m_pTableView->indexAt(pos).isValid())
 
600
    {
 
601
        menu.addAction(m_pCopyAction);
 
602
        menu.addAction(m_pDelAction);
 
603
    }
 
604
    /* If no valid index selected: */
 
605
    else
 
606
    {
 
607
        menu.addAction(m_pAddAction);
 
608
    }
 
609
    menu.exec(m_pTableView->viewport()->mapToGlobal(pos));
 
610
}
 
611
 
 
612
/* Adjusts table column's sizes: */
 
613
void UIMachineSettingsPortForwardingDlg::sltAdjustTable()
 
614
{
 
615
    m_pTableView->horizontalHeader()->setStretchLastSection(false);
 
616
    /* If table is NOT empty: */
 
617
    if (m_pModel->rowCount())
 
618
    {
 
619
        /* Resize table to contents size-hint and emit a spare place for first column: */
 
620
        m_pTableView->resizeColumnsToContents();
 
621
        uint uFullWidth = m_pTableView->viewport()->width();
 
622
        for (uint u = 1; u < UIPortForwardingModel::UIPortForwardingDataType_Max; ++u)
 
623
            uFullWidth -= m_pTableView->horizontalHeader()->sectionSize(u);
 
624
        m_pTableView->horizontalHeader()->resizeSection(UIPortForwardingModel::UIPortForwardingDataType_Name, uFullWidth);
 
625
    }
 
626
    /* If table is empty: */
 
627
    else
 
628
    {
 
629
        /* Resize table columns to be equal in size: */
 
630
        uint uFullWidth = m_pTableView->viewport()->width();
 
631
        for (uint u = 0; u < UIPortForwardingModel::UIPortForwardingDataType_Max; ++u)
 
632
            m_pTableView->horizontalHeader()->resizeSection(u, uFullWidth / UIPortForwardingModel::UIPortForwardingDataType_Max);
 
633
    }
 
634
    m_pTableView->horizontalHeader()->setStretchLastSection(true);
 
635
}
 
636
 
 
637
void UIMachineSettingsPortForwardingDlg::accept()
 
638
{
 
639
    /* Validate table: */
 
640
    for (int i = 0; i < m_pModel->rowCount(); ++i)
 
641
    {
 
642
        if (m_pModel->data(m_pModel->index(i, UIPortForwardingModel::UIPortForwardingDataType_HostPort), Qt::EditRole).value<PortData>().value() == 0 ||
 
643
            m_pModel->data(m_pModel->index(i, UIPortForwardingModel::UIPortForwardingDataType_GuestPort), Qt::EditRole).value<PortData>().value() == 0)
 
644
        {
 
645
            vboxProblem().warnAboutIncorrectPort(this);
 
646
            return;
 
647
        }
 
648
    }
 
649
    /* Base class accept() slot: */
 
650
    QIWithRetranslateUI<QIDialog>::accept();
 
651
}
 
652
 
 
653
void UIMachineSettingsPortForwardingDlg::reject()
 
654
{
 
655
    /* Check if table data was changed: */
 
656
    if (fIsTableDataChanged && !vboxProblem().confirmCancelingPortForwardingDialog(this))
 
657
        return;
 
658
    /* Base class reject() slot: */
 
659
    QIWithRetranslateUI<QIDialog>::reject();
 
660
}
 
661
 
 
662
/* UI Retranslation slot: */
 
663
void UIMachineSettingsPortForwardingDlg::retranslateUi()
 
664
{
 
665
    /* Set window title: */
 
666
    setWindowTitle(tr("Port Forwarding Rules"));
 
667
 
 
668
    /* Table translations: */
 
669
    m_pTableView->setWhatsThis(tr("This table contains a list of port forwarding rules."));
 
670
 
 
671
    /* Set action's text: */
 
672
    m_pAddAction->setText(tr("Insert new rule"));
 
673
    m_pCopyAction->setText(tr("Copy selected rule"));
 
674
    m_pDelAction->setText(tr("Delete selected rule"));
 
675
    m_pAddAction->setWhatsThis(tr("This button adds new port forwarding rule."));
 
676
    m_pDelAction->setWhatsThis(tr("This button deletes selected port forwarding rule."));
 
677
    m_pAddAction->setToolTip(QString("%1 (%2)").arg(m_pAddAction->text()).arg(m_pAddAction->shortcut().toString()));
 
678
    m_pDelAction->setToolTip(QString("%1 (%2)").arg(m_pDelAction->text()).arg(m_pDelAction->shortcut().toString()));
 
679
}
 
680
 
 
681
/* Extended event-handler: */
 
682
bool UIMachineSettingsPortForwardingDlg::eventFilter(QObject *pObj, QEvent *pEvent)
 
683
{
 
684
    /* Process table: */
 
685
    if (pObj == m_pTableView)
 
686
    {
 
687
        /* Switch for different event-types: */
 
688
        switch (pEvent->type())
 
689
        {
 
690
            case QEvent::FocusIn:
 
691
            case QEvent::FocusOut:
 
692
                /* Update actions: */
 
693
                sltCurrentChanged();
 
694
                break;
 
695
            case QEvent::Show:
 
696
            case QEvent::Resize:
 
697
            {
 
698
                /* Instant table adjusting: */
 
699
                sltAdjustTable();
 
700
                /* Delayed table adjusting: */
 
701
                QTimer::singleShot(0, this, SLOT(sltAdjustTable()));
 
702
                break;
 
703
            }
 
704
            default:
 
705
                break;
 
706
        }
 
707
    }
 
708
    /* Continue with base-class processing: */
 
709
    return QIWithRetranslateUI<QIDialog>::eventFilter(pObj, pEvent);
 
710
}
 
711
 
 
712
#include "UIMachineSettingsPortForwardingDlg.moc"
 
713