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 |
|
---|