VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/widgets/UIPortForwardingTable.cpp@ 82781

Last change on this file since 82781 was 80955, checked in by vboxsync, 5 years ago

FE/Qt: bugref:8938. Changing connection syntax under the widget subfolder.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.8 KB
Line 
1/* $Id: UIPortForwardingTable.cpp 80955 2019-09-23 17:27:06Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIPortForwardingTable class implementation.
4 */
5
6/*
7 * Copyright (C) 2010-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/* Qt includes: */
19#include <QAction>
20#include <QComboBox>
21#include <QHBoxLayout>
22#include <QHeaderView>
23#include <QItemEditorFactory>
24#include <QLineEdit>
25#include <QMenu>
26#include <QSpinBox>
27#include <QStyledItemDelegate>
28
29/* GUI includes: */
30#include "QITableView.h"
31#include "UIDesktopWidgetWatchdog.h"
32#include "UIConverter.h"
33#include "UIIconPool.h"
34#include "UIMessageCenter.h"
35#include "UIPortForwardingTable.h"
36#include "UIToolBar.h"
37
38/* Other VBox includes: */
39#include <iprt/cidr.h>
40
41/* External includes: */
42#include <math.h>
43
44
45/** Port Forwarding data types. */
46enum UIPortForwardingDataType
47{
48 UIPortForwardingDataType_Name,
49 UIPortForwardingDataType_Protocol,
50 UIPortForwardingDataType_HostIp,
51 UIPortForwardingDataType_HostPort,
52 UIPortForwardingDataType_GuestIp,
53 UIPortForwardingDataType_GuestPort,
54 UIPortForwardingDataType_Max
55};
56
57
58/** QLineEdit extension used as name editor. */
59class NameEditor : public QLineEdit
60{
61 Q_OBJECT;
62 Q_PROPERTY(NameData name READ name WRITE setName USER true);
63
64public:
65
66 /** Constructs name editor passing @a pParent to the base-class. */
67 NameEditor(QWidget *pParent = 0) : QLineEdit(pParent)
68 {
69 setFrame(false);
70 setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
71 setValidator(new QRegExpValidator(QRegExp("[^,:]*"), this));
72 }
73
74private:
75
76 /** Defines the @a strName. */
77 void setName(NameData strName)
78 {
79 setText(strName);
80 }
81
82 /** Returns the name. */
83 NameData name() const
84 {
85 return text();
86 }
87};
88
89
90/** QComboBox extension used as protocol editor. */
91class ProtocolEditor : public QComboBox
92{
93 Q_OBJECT;
94 Q_PROPERTY(KNATProtocol protocol READ protocol WRITE setProtocol USER true);
95
96public:
97
98 /** Constructs protocol editor passing @a pParent to the base-class. */
99 ProtocolEditor(QWidget *pParent = 0) : QComboBox(pParent)
100 {
101 addItem(gpConverter->toString(KNATProtocol_UDP), QVariant::fromValue(KNATProtocol_UDP));
102 addItem(gpConverter->toString(KNATProtocol_TCP), QVariant::fromValue(KNATProtocol_TCP));
103 }
104
105private:
106
107 /** Defines the @a enmProtocol. */
108 void setProtocol(KNATProtocol enmProtocol)
109 {
110 for (int i = 0; i < count(); ++i)
111 {
112 if (itemData(i).value<KNATProtocol>() == enmProtocol)
113 {
114 setCurrentIndex(i);
115 break;
116 }
117 }
118 }
119
120 /** Returns the protocol. */
121 KNATProtocol protocol() const
122 {
123 return itemData(currentIndex()).value<KNATProtocol>();
124 }
125};
126
127
128/** QLineEdit extension used as IPv4 editor. */
129class IPv4Editor : public QLineEdit
130{
131 Q_OBJECT;
132 Q_PROPERTY(IpData ip READ ip WRITE setIp USER true);
133
134public:
135
136 /** Constructs IPv4-editor passing @a pParent to the base-class. */
137 IPv4Editor(QWidget *pParent = 0) : QLineEdit(pParent)
138 {
139 setFrame(false);
140 setAlignment(Qt::AlignCenter);
141 // Decided to not use it for now:
142 // setValidator(new IPv4Validator(this));
143 }
144
145private:
146
147 /** Defines the @a strIp. */
148 void setIp(IpData strIp)
149 {
150 setText(strIp);
151 }
152
153 /** Returns the ip. */
154 IpData ip() const
155 {
156 return text() == "..." ? QString() : text();
157 }
158};
159
160
161/** QLineEdit extension used as IPv6 editor. */
162class IPv6Editor : public QLineEdit
163{
164 Q_OBJECT;
165 Q_PROPERTY(IpData ip READ ip WRITE setIp USER true);
166
167public:
168
169 /** Constructs IPv6-editor passing @a pParent to the base-class. */
170 IPv6Editor(QWidget *pParent = 0) : QLineEdit(pParent)
171 {
172 setFrame(false);
173 setAlignment(Qt::AlignCenter);
174 // Decided to not use it for now:
175 // setValidator(new IPv6Validator(this));
176 }
177
178private:
179
180 /** Defines the @a strIp. */
181 void setIp(IpData strIp)
182 {
183 setText(strIp);
184 }
185
186 /** Returns the ip. */
187 IpData ip() const
188 {
189 return text() == "..." ? QString() : text();
190 }
191};
192
193
194/** QSpinBox extension used as Port editor. */
195class PortEditor : public QSpinBox
196{
197 Q_OBJECT;
198 Q_PROPERTY(PortData port READ port WRITE setPort USER true);
199
200public:
201
202 /** Constructs Port-editor passing @a pParent to the base-class. */
203 PortEditor(QWidget *pParent = 0) : QSpinBox(pParent)
204 {
205 setFrame(false);
206 setRange(0, (1 << (8 * sizeof(ushort))) - 1);
207 }
208
209private:
210
211 /** Defines the @a port. */
212 void setPort(PortData port)
213 {
214 setValue(port.value());
215 }
216
217 /** Returns the port. */
218 PortData port() const
219 {
220 return value();
221 }
222};
223
224
225/** QITableViewCell extension used as Port Forwarding table-view cell. */
226class UIPortForwardingCell : public QITableViewCell
227{
228 Q_OBJECT;
229
230public:
231
232 /** Constructs table cell passing @a pParent to the base-class.
233 * @param strName Brings the name. */
234 UIPortForwardingCell(QITableViewRow *pParent, const NameData &strName)
235 : QITableViewCell(pParent)
236 , m_strText(strName)
237 {}
238
239 /** Constructs table cell passing @a pParent to the base-class.
240 * @param enmProtocol Brings the protocol type. */
241 UIPortForwardingCell(QITableViewRow *pParent, KNATProtocol enmProtocol)
242 : QITableViewCell(pParent)
243 , m_strText(gpConverter->toString(enmProtocol))
244 {}
245
246 /** Constructs table cell passing @a pParent to the base-class.
247 * @param strIp Brings the IP address. */
248 UIPortForwardingCell(QITableViewRow *pParent, const IpData &strIp)
249 : QITableViewCell(pParent)
250 , m_strText(strIp)
251 {}
252
253 /** Constructs table cell passing @a pParent to the base-class.
254 * @param port Brings the port. */
255 UIPortForwardingCell(QITableViewRow *pParent, PortData port)
256 : QITableViewCell(pParent)
257 , m_strText(QString::number(port.value()))
258 {}
259
260 /** Returns the cell text. */
261 virtual QString text() const /* override */ { return m_strText; }
262
263private:
264
265 /** Holds the cell text. */
266 QString m_strText;
267};
268
269
270/** QITableViewRow extension used as Port Forwarding table-view row. */
271class UIPortForwardingRow : public QITableViewRow
272{
273 Q_OBJECT;
274
275public:
276
277 /** Constructs table row passing @a pParent to the base-class.
278 * @param strName Brings the unique rule name.
279 * @param enmProtocol Brings the rule protocol type.
280 * @param strHostIp Brings the rule host IP address.
281 * @param hostPort Brings the rule host port.
282 * @param strGuestIp Brings the rule guest IP address.
283 * @param guestPort Brings the rule guest port. */
284 UIPortForwardingRow(QITableView *pParent,
285 const NameData &strName, KNATProtocol enmProtocol,
286 const IpData &strHostIp, PortData hostPort,
287 const IpData &strGuestIp, PortData guestPort)
288 : QITableViewRow(pParent)
289 , m_strName(strName), m_enmProtocol(enmProtocol)
290 , m_strHostIp(strHostIp), m_hostPort(hostPort)
291 , m_strGuestIp(strGuestIp), m_guestPort(guestPort)
292 {
293 /* Create cells: */
294 createCells();
295 }
296
297 /** Destructs table row. */
298 ~UIPortForwardingRow()
299 {
300 /* Destroy cells: */
301 destroyCells();
302 }
303
304 /** Returns the unique rule name. */
305 NameData name() const { return m_strName; }
306 /** Defines the unique rule name. */
307 void setName(const NameData &strName)
308 {
309 m_strName = strName;
310 delete m_cells[UIPortForwardingDataType_Name];
311 m_cells[UIPortForwardingDataType_Name] = new UIPortForwardingCell(this, m_strName);
312 }
313
314 /** Returns the rule protocol type. */
315 KNATProtocol protocol() const { return m_enmProtocol; }
316 /** Defines the rule protocol type. */
317 void setProtocol(KNATProtocol enmProtocol)
318 {
319 m_enmProtocol = enmProtocol;
320 delete m_cells[UIPortForwardingDataType_Protocol];
321 m_cells[UIPortForwardingDataType_Protocol] = new UIPortForwardingCell(this, m_enmProtocol);
322 }
323
324 /** Returns the rule host IP address. */
325 IpData hostIp() const { return m_strHostIp; }
326 /** Defines the rule host IP address. */
327 void setHostIp(const IpData &strHostIp)
328 {
329 m_strHostIp = strHostIp;
330 delete m_cells[UIPortForwardingDataType_HostIp];
331 m_cells[UIPortForwardingDataType_HostIp] = new UIPortForwardingCell(this, m_strHostIp);
332 }
333
334 /** Returns the rule host port. */
335 PortData hostPort() const { return m_hostPort; }
336 /** Defines the rule host port. */
337 void setHostPort(PortData hostPort)
338 {
339 m_hostPort = hostPort;
340 delete m_cells[UIPortForwardingDataType_HostPort];
341 m_cells[UIPortForwardingDataType_HostPort] = new UIPortForwardingCell(this, m_hostPort);
342 }
343
344 /** Returns the rule guest IP address. */
345 IpData guestIp() const { return m_strGuestIp; }
346 /** Defines the rule guest IP address. */
347 void setGuestIp(const IpData &strGuestIp)
348 {
349 m_strGuestIp = strGuestIp;
350 delete m_cells[UIPortForwardingDataType_GuestIp];
351 m_cells[UIPortForwardingDataType_GuestIp] = new UIPortForwardingCell(this, m_strGuestIp);
352 }
353
354 /** Returns the rule guest port. */
355 PortData guestPort() const { return m_guestPort; }
356 /** Defines the rule guest port. */
357 void setGuestPort(PortData guestPort)
358 {
359 m_guestPort = guestPort;
360 delete m_cells[UIPortForwardingDataType_GuestPort];
361 m_cells[UIPortForwardingDataType_GuestPort] = new UIPortForwardingCell(this, m_guestPort);
362 }
363
364protected:
365
366 /** Returns the number of children. */
367 virtual int childCount() const /* override */
368 {
369 /* Return cell count: */
370 return UIPortForwardingDataType_Max;
371 }
372
373 /** Returns the child item with @a iIndex. */
374 virtual QITableViewCell *childItem(int iIndex) const /* override */
375 {
376 /* Make sure index within the bounds: */
377 AssertReturn(iIndex >= 0 && iIndex < m_cells.size(), 0);
378 /* Return corresponding cell: */
379 return m_cells[iIndex];
380 }
381
382private:
383
384 /** Creates cells. */
385 void createCells()
386 {
387 /* Create cells on the basis of variables we have: */
388 m_cells.resize(UIPortForwardingDataType_Max);
389 m_cells[UIPortForwardingDataType_Name] = new UIPortForwardingCell(this, m_strName);
390 m_cells[UIPortForwardingDataType_Protocol] = new UIPortForwardingCell(this, m_enmProtocol);
391 m_cells[UIPortForwardingDataType_HostIp] = new UIPortForwardingCell(this, m_strHostIp);
392 m_cells[UIPortForwardingDataType_HostPort] = new UIPortForwardingCell(this, m_hostPort);
393 m_cells[UIPortForwardingDataType_GuestIp] = new UIPortForwardingCell(this, m_strGuestIp);
394 m_cells[UIPortForwardingDataType_GuestPort] = new UIPortForwardingCell(this, m_guestPort);
395 }
396
397 /** Destroys cells. */
398 void destroyCells()
399 {
400 /* Destroy cells: */
401 qDeleteAll(m_cells);
402 m_cells.clear();
403 }
404
405 /** Holds the unique rule name. */
406 NameData m_strName;
407 /** Holds the rule protocol type. */
408 KNATProtocol m_enmProtocol;
409 /** Holds the rule host IP address. */
410 IpData m_strHostIp;
411 /** Holds the rule host port. */
412 PortData m_hostPort;
413 /** Holds the rule guest IP address. */
414 IpData m_strGuestIp;
415 /** Holds the rule guest port. */
416 PortData m_guestPort;
417
418 /** Holds the cell instances. */
419 QVector<UIPortForwardingCell*> m_cells;
420};
421
422
423/** QAbstractTableModel subclass used as port forwarding data model. */
424class UIPortForwardingModel : public QAbstractTableModel
425{
426 Q_OBJECT;
427
428public:
429
430 /** Constructs Port Forwarding model passing @a pParent to the base-class.
431 * @param rules Brings the list of port forwarding rules to load initially. */
432 UIPortForwardingModel(QITableView *pParent, const UIPortForwardingDataList &rules = UIPortForwardingDataList());
433 /** Destructs Port Forwarding model. */
434 ~UIPortForwardingModel();
435
436 /** Returns the number of children. */
437 int childCount() const;
438 /** Returns the child item with @a iIndex. */
439 QITableViewRow *childItem(int iIndex) const;
440
441 /** Returns the list of port forwarding rules. */
442 const UIPortForwardingDataList rules() const;
443 /** Adds empty port forwarding rule for certain @a index. */
444 void addRule(const QModelIndex &index);
445 /** Removes port forwarding rule with certain @a index. */
446 void removeRule(const QModelIndex &index);
447
448 /** Returns flags for item with certain @a index. */
449 Qt::ItemFlags flags(const QModelIndex &index) const;
450
451 /** Returns row count of certain @a parent. */
452 int rowCount(const QModelIndex &parent = QModelIndex()) const;
453
454 /** Returns column count of certain @a parent. */
455 int columnCount(const QModelIndex &parent = QModelIndex()) const;
456
457 /** Returns header data.
458 * @param iSection Brings the number of section we aquire data for.
459 * @param enmOrientation Brings the orientation of header we aquire data for.
460 * @param iRole Brings the role we aquire data for. */
461 QVariant headerData(int iSection, Qt::Orientation enmOrientation, int iRole) const;
462
463 /** Defines the @a iRole data for item with @a index as @a value. */
464 bool setData(const QModelIndex &index, const QVariant &value, int iRole = Qt::EditRole);
465 /** Returns the @a iRole data for item with @a index. */
466 QVariant data(const QModelIndex &index, int iRole) const;
467
468private:
469
470 /** Return the parent table-view reference. */
471 QITableView *parentTable() const;
472
473 /** Holds the port forwarding row list. */
474 QList<UIPortForwardingRow*> m_dataList;
475};
476
477
478/** QITableView extension used as Port Forwarding table-view. */
479class UIPortForwardingView : public QITableView
480{
481 Q_OBJECT;
482
483public:
484
485 /** Constructs Port Forwarding table-view. */
486 UIPortForwardingView() {}
487
488protected:
489
490 /** Returns the number of children. */
491 virtual int childCount() const /* override */;
492 /** Returns the child item with @a iIndex. */
493 virtual QITableViewRow *childItem(int iIndex) const /* override */;
494};
495
496
497/*********************************************************************************************************************************
498* Class UIPortForwardingModel implementation. *
499*********************************************************************************************************************************/
500
501UIPortForwardingModel::UIPortForwardingModel(QITableView *pParent,
502 const UIPortForwardingDataList &rules /* = UIPortForwardingDataList() */)
503 : QAbstractTableModel(pParent)
504{
505 /* Fetch the incoming data: */
506 foreach (const UIDataPortForwardingRule &rule, rules)
507 m_dataList << new UIPortForwardingRow(pParent,
508 rule.name, rule.protocol,
509 rule.hostIp, rule.hostPort,
510 rule.guestIp, rule.guestPort);
511}
512
513UIPortForwardingModel::~UIPortForwardingModel()
514{
515 /* Delete the cached data: */
516 qDeleteAll(m_dataList);
517 m_dataList.clear();
518}
519
520int UIPortForwardingModel::childCount() const
521{
522 /* Return row count: */
523 return rowCount();
524}
525
526QITableViewRow *UIPortForwardingModel::childItem(int iIndex) const
527{
528 /* Make sure index within the bounds: */
529 AssertReturn(iIndex >= 0 && iIndex < m_dataList.size(), 0);
530 /* Return corresponding row: */
531 return m_dataList[iIndex];
532}
533
534const UIPortForwardingDataList UIPortForwardingModel::rules() const
535{
536 /* Return the cached data: */
537 UIPortForwardingDataList data;
538 foreach (const UIPortForwardingRow *pRow, m_dataList)
539 data << UIDataPortForwardingRule(pRow->name(), pRow->protocol(),
540 pRow->hostIp(), pRow->hostPort(),
541 pRow->guestIp(), pRow->guestPort());
542 return data;
543}
544
545void UIPortForwardingModel::addRule(const QModelIndex &index)
546{
547 beginInsertRows(QModelIndex(), m_dataList.size(), m_dataList.size());
548 /* Search for existing "Rule [NUMBER]" record: */
549 uint uMaxIndex = 0;
550 QString strTemplate("Rule %1");
551 QRegExp regExp(strTemplate.arg("(\\d+)"));
552 for (int i = 0; i < m_dataList.size(); ++i)
553 if (regExp.indexIn(m_dataList[i]->name()) > -1)
554 uMaxIndex = regExp.cap(1).toUInt() > uMaxIndex ? regExp.cap(1).toUInt() : uMaxIndex;
555 /* If index is valid => copy data: */
556 if (index.isValid())
557 m_dataList << new UIPortForwardingRow(parentTable(),
558 strTemplate.arg(++uMaxIndex), m_dataList[index.row()]->protocol(),
559 m_dataList[index.row()]->hostIp(), m_dataList[index.row()]->hostPort(),
560 m_dataList[index.row()]->guestIp(), m_dataList[index.row()]->guestPort());
561 /* If index is NOT valid => use default values: */
562 else
563 m_dataList << new UIPortForwardingRow(parentTable(),
564 strTemplate.arg(++uMaxIndex), KNATProtocol_TCP,
565 QString(""), 0, QString(""), 0);
566 endInsertRows();
567}
568
569void UIPortForwardingModel::removeRule(const QModelIndex &index)
570{
571 if (!index.isValid())
572 return;
573 beginRemoveRows(QModelIndex(), index.row(), index.row());
574 delete m_dataList.at(index.row());
575 m_dataList.removeAt(index.row());
576 endRemoveRows();
577}
578
579Qt::ItemFlags UIPortForwardingModel::flags(const QModelIndex &index) const
580{
581 /* Check index validness: */
582 if (!index.isValid())
583 return Qt::NoItemFlags;
584 /* All columns have similar flags: */
585 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
586}
587
588int UIPortForwardingModel::rowCount(const QModelIndex &) const
589{
590 return m_dataList.size();
591}
592
593int UIPortForwardingModel::columnCount(const QModelIndex &) const
594{
595 return UIPortForwardingDataType_Max;
596}
597
598QVariant UIPortForwardingModel::headerData(int iSection, Qt::Orientation enmOrientation, int iRole) const
599{
600 /* Display role for horizontal header: */
601 if (iRole == Qt::DisplayRole && enmOrientation == Qt::Horizontal)
602 {
603 /* Switch for different columns: */
604 switch (iSection)
605 {
606 case UIPortForwardingDataType_Name: return UIPortForwardingTable::tr("Name");
607 case UIPortForwardingDataType_Protocol: return UIPortForwardingTable::tr("Protocol");
608 case UIPortForwardingDataType_HostIp: return UIPortForwardingTable::tr("Host IP");
609 case UIPortForwardingDataType_HostPort: return UIPortForwardingTable::tr("Host Port");
610 case UIPortForwardingDataType_GuestIp: return UIPortForwardingTable::tr("Guest IP");
611 case UIPortForwardingDataType_GuestPort: return UIPortForwardingTable::tr("Guest Port");
612 default: break;
613 }
614 }
615 /* Return wrong value: */
616 return QVariant();
617}
618
619bool UIPortForwardingModel::setData(const QModelIndex &index, const QVariant &value, int iRole /* = Qt::EditRole */)
620{
621 /* Check index validness: */
622 if (!index.isValid() || iRole != Qt::EditRole)
623 return false;
624 /* Switch for different columns: */
625 switch (index.column())
626 {
627 case UIPortForwardingDataType_Name:
628 m_dataList[index.row()]->setName(value.value<NameData>());
629 emit dataChanged(index, index);
630 return true;
631 case UIPortForwardingDataType_Protocol:
632 m_dataList[index.row()]->setProtocol(value.value<KNATProtocol>());
633 emit dataChanged(index, index);
634 return true;
635 case UIPortForwardingDataType_HostIp:
636 m_dataList[index.row()]->setHostIp(value.value<IpData>());
637 emit dataChanged(index, index);
638 return true;
639 case UIPortForwardingDataType_HostPort:
640 m_dataList[index.row()]->setHostPort(value.value<PortData>());
641 emit dataChanged(index, index);
642 return true;
643 case UIPortForwardingDataType_GuestIp:
644 m_dataList[index.row()]->setGuestIp(value.value<IpData>());
645 emit dataChanged(index, index);
646 return true;
647 case UIPortForwardingDataType_GuestPort:
648 m_dataList[index.row()]->setGuestPort(value.value<PortData>());
649 emit dataChanged(index, index);
650 return true;
651 default: return false;
652 }
653 /* not reached! */
654}
655
656QVariant UIPortForwardingModel::data(const QModelIndex &index, int iRole) const
657{
658 /* Check index validness: */
659 if (!index.isValid())
660 return QVariant();
661 /* Switch for different roles: */
662 switch (iRole)
663 {
664 /* Display role: */
665 case Qt::DisplayRole:
666 {
667 /* Switch for different columns: */
668 switch (index.column())
669 {
670 case UIPortForwardingDataType_Name: return m_dataList[index.row()]->name();
671 case UIPortForwardingDataType_Protocol: return gpConverter->toString(m_dataList[index.row()]->protocol());
672 case UIPortForwardingDataType_HostIp: return m_dataList[index.row()]->hostIp();
673 case UIPortForwardingDataType_HostPort: return m_dataList[index.row()]->hostPort().value();
674 case UIPortForwardingDataType_GuestIp: return m_dataList[index.row()]->guestIp();
675 case UIPortForwardingDataType_GuestPort: return m_dataList[index.row()]->guestPort().value();
676 default: return QVariant();
677 }
678 }
679 /* Edit role: */
680 case Qt::EditRole:
681 {
682 /* Switch for different columns: */
683 switch (index.column())
684 {
685 case UIPortForwardingDataType_Name: return QVariant::fromValue(m_dataList[index.row()]->name());
686 case UIPortForwardingDataType_Protocol: return QVariant::fromValue(m_dataList[index.row()]->protocol());
687 case UIPortForwardingDataType_HostIp: return QVariant::fromValue(m_dataList[index.row()]->hostIp());
688 case UIPortForwardingDataType_HostPort: return QVariant::fromValue(m_dataList[index.row()]->hostPort());
689 case UIPortForwardingDataType_GuestIp: return QVariant::fromValue(m_dataList[index.row()]->guestIp());
690 case UIPortForwardingDataType_GuestPort: return QVariant::fromValue(m_dataList[index.row()]->guestPort());
691 default: return QVariant();
692 }
693 }
694 /* Alignment role: */
695 case Qt::TextAlignmentRole:
696 {
697 /* Switch for different columns: */
698 switch (index.column())
699 {
700 case UIPortForwardingDataType_Name:
701 case UIPortForwardingDataType_Protocol:
702 case UIPortForwardingDataType_HostPort:
703 case UIPortForwardingDataType_GuestPort:
704 return (int)(Qt::AlignLeft | Qt::AlignVCenter);
705 case UIPortForwardingDataType_HostIp:
706 case UIPortForwardingDataType_GuestIp:
707 return Qt::AlignCenter;
708 default: return QVariant();
709 }
710 }
711 case Qt::SizeHintRole:
712 {
713 /* Switch for different columns: */
714 switch (index.column())
715 {
716 case UIPortForwardingDataType_HostIp:
717 case UIPortForwardingDataType_GuestIp:
718 return QSize(QApplication::fontMetrics().width(" 888.888.888.888 "), QApplication::fontMetrics().height());
719 default: return QVariant();
720 }
721 }
722 default: break;
723 }
724 /* Return wrong value: */
725 return QVariant();
726}
727
728QITableView *UIPortForwardingModel::parentTable() const
729{
730 return qobject_cast<QITableView*>(parent());
731}
732
733
734/*********************************************************************************************************************************
735* Class UIPortForwardingView implementation. *
736*********************************************************************************************************************************/
737
738int UIPortForwardingView::childCount() const
739{
740 /* Redirect request to table model: */
741 return qobject_cast<UIPortForwardingModel*>(model())->childCount();
742}
743
744QITableViewRow *UIPortForwardingView::childItem(int iIndex) const
745{
746 /* Redirect request to table model: */
747 return qobject_cast<UIPortForwardingModel*>(model())->childItem(iIndex);
748}
749
750
751/*********************************************************************************************************************************
752* Class UIPortForwardingTable implementation. *
753*********************************************************************************************************************************/
754
755UIPortForwardingTable::UIPortForwardingTable(const UIPortForwardingDataList &rules, bool fIPv6, bool fAllowEmptyGuestIPs)
756 : m_rules(rules)
757 , m_fIPv6(fIPv6)
758 , m_fAllowEmptyGuestIPs(fAllowEmptyGuestIPs)
759 , m_fTableDataChanged(false)
760 , m_pLayout(0)
761 , m_pTableView(0)
762 , m_pToolBar(0)
763 , m_pTableModel(0)
764 , m_pActionAdd(0)
765 , m_pActionCopy(0)
766 , m_pActionRemove(0)
767{
768 /* Prepare: */
769 prepare();
770}
771
772const UIPortForwardingDataList UIPortForwardingTable::rules() const
773{
774 return m_pTableModel->rules();
775}
776
777bool UIPortForwardingTable::validate() const
778{
779 /* Validate table: */
780 QList<NameData> names;
781 QList<UIPortForwardingDataUnique> rules;
782 for (int i = 0; i < m_pTableModel->rowCount(); ++i)
783 {
784 /* Some of variables: */
785 const NameData strName = m_pTableModel->data(m_pTableModel->index(i, UIPortForwardingDataType_Name), Qt::EditRole).value<NameData>();
786 const KNATProtocol enmProtocol = m_pTableModel->data(m_pTableModel->index(i, UIPortForwardingDataType_Protocol), Qt::EditRole).value<KNATProtocol>();
787 const PortData hostPort = m_pTableModel->data(m_pTableModel->index(i, UIPortForwardingDataType_HostPort), Qt::EditRole).value<PortData>().value();
788 const PortData guestPort = m_pTableModel->data(m_pTableModel->index(i, UIPortForwardingDataType_GuestPort), Qt::EditRole).value<PortData>().value();
789 const IpData strHostIp = m_pTableModel->data(m_pTableModel->index(i, UIPortForwardingDataType_HostIp), Qt::EditRole).value<IpData>();
790 const IpData strGuestIp = m_pTableModel->data(m_pTableModel->index(i, UIPortForwardingDataType_GuestIp), Qt::EditRole).value<IpData>();
791
792 /* If at least one port is 'zero': */
793 if (hostPort.value() == 0 || guestPort.value() == 0)
794 return msgCenter().warnAboutIncorrectPort(window());
795 /* If at least one address is incorrect: */
796 if (!( strHostIp.trimmed().isEmpty()
797 || RTNetIsIPv4AddrStr(strHostIp.toUtf8().constData())
798 || RTNetIsIPv6AddrStr(strHostIp.toUtf8().constData())
799 || RTNetStrIsIPv4AddrAny(strHostIp.toUtf8().constData())
800 || RTNetStrIsIPv6AddrAny(strHostIp.toUtf8().constData())))
801 return msgCenter().warnAboutIncorrectAddress(window());
802 if (!( strGuestIp.trimmed().isEmpty()
803 || RTNetIsIPv4AddrStr(strGuestIp.toUtf8().constData())
804 || RTNetIsIPv6AddrStr(strGuestIp.toUtf8().constData())
805 || RTNetStrIsIPv4AddrAny(strGuestIp.toUtf8().constData())
806 || RTNetStrIsIPv6AddrAny(strGuestIp.toUtf8().constData())))
807 return msgCenter().warnAboutIncorrectAddress(window());
808 /* If empty guest address is not allowed: */
809 if ( !m_fAllowEmptyGuestIPs
810 && strGuestIp.isEmpty())
811 return msgCenter().warnAboutEmptyGuestAddress(window());
812
813 /* Make sure non of the names were previosly used: */
814 if (!names.contains(strName))
815 names << strName;
816 else
817 return msgCenter().warnAboutNameShouldBeUnique(window());
818
819 /* Make sure non of the rules were previosly used: */
820 UIPortForwardingDataUnique rule(enmProtocol, hostPort, strHostIp);
821 if (!rules.contains(rule))
822 rules << rule;
823 else
824 return msgCenter().warnAboutRulesConflict(window());
825 }
826 /* True by default: */
827 return true;
828}
829
830void UIPortForwardingTable::makeSureEditorDataCommitted()
831{
832 m_pTableView->makeSureEditorDataCommitted();
833}
834
835bool UIPortForwardingTable::eventFilter(QObject *pObject, QEvent *pEvent)
836{
837 /* Process table: */
838 if (pObject == m_pTableView)
839 {
840 /* Process different event-types: */
841 switch (pEvent->type())
842 {
843 case QEvent::Show:
844 case QEvent::Resize:
845 {
846 /* Adjust table: */
847 sltAdjustTable();
848 break;
849 }
850 case QEvent::FocusIn:
851 case QEvent::FocusOut:
852 {
853 /* Update actions: */
854 sltCurrentChanged();
855 break;
856 }
857 default:
858 break;
859 }
860 }
861 /* Call to base-class: */
862 return QIWithRetranslateUI<QWidget>::eventFilter(pObject, pEvent);
863}
864
865void UIPortForwardingTable::retranslateUi()
866{
867 /* Table translations: */
868 m_pTableView->setWhatsThis(tr("Contains a list of port forwarding rules."));
869
870 /* Set action's text: */
871 m_pActionAdd->setText(tr("Add New Rule"));
872 m_pActionCopy->setText(tr("Copy Selected Rule"));
873 m_pActionRemove->setText(tr("Remove Selected Rule"));
874
875 m_pActionAdd->setWhatsThis(tr("Adds new port forwarding rule."));
876 m_pActionCopy->setWhatsThis(tr("Copies selected port forwarding rule."));
877 m_pActionRemove->setWhatsThis(tr("Removes selected port forwarding rule."));
878
879 m_pActionAdd->setToolTip(m_pActionAdd->whatsThis());
880 m_pActionCopy->setToolTip(m_pActionCopy->whatsThis());
881 m_pActionRemove->setToolTip(m_pActionRemove->whatsThis());
882}
883
884void UIPortForwardingTable::sltAddRule()
885{
886 m_pTableModel->addRule(QModelIndex());
887 m_pTableView->setFocus();
888 m_pTableView->setCurrentIndex(m_pTableModel->index(m_pTableModel->rowCount() - 1, 0));
889 sltCurrentChanged();
890 sltAdjustTable();
891}
892
893void UIPortForwardingTable::sltCopyRule()
894{
895 m_pTableModel->addRule(m_pTableView->currentIndex());
896 m_pTableView->setFocus();
897 m_pTableView->setCurrentIndex(m_pTableModel->index(m_pTableModel->rowCount() - 1, 0));
898 sltCurrentChanged();
899 sltAdjustTable();
900}
901
902void UIPortForwardingTable::sltRemoveRule()
903{
904 m_pTableModel->removeRule(m_pTableView->currentIndex());
905 m_pTableView->setFocus();
906 sltCurrentChanged();
907 sltAdjustTable();
908}
909
910void UIPortForwardingTable::sltCurrentChanged()
911{
912 bool fTableFocused = m_pTableView->hasFocus();
913 bool fTableChildFocused = m_pTableView->findChildren<QWidget*>().contains(QApplication::focusWidget());
914 bool fTableOrChildFocused = fTableFocused || fTableChildFocused;
915 m_pActionCopy->setEnabled(m_pTableView->currentIndex().isValid() && fTableOrChildFocused);
916 m_pActionRemove->setEnabled(m_pTableView->currentIndex().isValid() && fTableOrChildFocused);
917}
918
919void UIPortForwardingTable::sltShowTableContexMenu(const QPoint &pos)
920{
921 /* Prepare context menu: */
922 QMenu menu(m_pTableView);
923 /* If some index is currently selected: */
924 if (m_pTableView->indexAt(pos).isValid())
925 {
926 menu.addAction(m_pActionCopy);
927 menu.addAction(m_pActionRemove);
928 }
929 /* If no valid index selected: */
930 else
931 {
932 menu.addAction(m_pActionAdd);
933 }
934 menu.exec(m_pTableView->viewport()->mapToGlobal(pos));
935}
936
937void UIPortForwardingTable::sltAdjustTable()
938{
939 m_pTableView->horizontalHeader()->setStretchLastSection(false);
940 /* If table is NOT empty: */
941 if (m_pTableModel->rowCount())
942 {
943 /* Resize table to contents size-hint and emit a spare place for first column: */
944 m_pTableView->resizeColumnsToContents();
945 uint uFullWidth = m_pTableView->viewport()->width();
946 for (uint u = 1; u < UIPortForwardingDataType_Max; ++u)
947 uFullWidth -= m_pTableView->horizontalHeader()->sectionSize(u);
948 m_pTableView->horizontalHeader()->resizeSection(UIPortForwardingDataType_Name, uFullWidth);
949 }
950 /* If table is empty: */
951 else
952 {
953 /* Resize table columns to be equal in size: */
954 uint uFullWidth = m_pTableView->viewport()->width();
955 for (uint u = 0; u < UIPortForwardingDataType_Max; ++u)
956 m_pTableView->horizontalHeader()->resizeSection(u, uFullWidth / UIPortForwardingDataType_Max);
957 }
958 m_pTableView->horizontalHeader()->setStretchLastSection(true);
959}
960
961void UIPortForwardingTable::prepare()
962{
963 /* Prepare layout: */
964 prepareLayout();
965
966 /* Apply language settings: */
967 retranslateUi();
968
969 /* Limit the minimum size to 33% of screen size: */
970 setMinimumSize(gpDesktop->screenGeometry(this).size() / 3);
971}
972
973void UIPortForwardingTable::prepareLayout()
974{
975 /* Create layout: */
976 m_pLayout = new QHBoxLayout(this);
977 if (m_pLayout)
978 {
979 /* Configure layout: */
980#ifdef VBOX_WS_MAC
981 /* On macOS we can do a bit of smoothness: */
982 m_pLayout->setContentsMargins(0, 0, 0, 0);
983 m_pLayout->setSpacing(3);
984#else
985 m_pLayout->setSpacing(qApp->style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing) / 3);
986#endif
987
988 /* Prepare table-view: */
989 prepareTableView();
990
991 /* Prepare toolbar: */
992 prepareToolbar();
993 }
994}
995
996void UIPortForwardingTable::prepareTableView()
997{
998 /* Create table-view: */
999 m_pTableView = new UIPortForwardingView;
1000 if (m_pTableView)
1001 {
1002 /* Configure table-view: */
1003 m_pTableView->setTabKeyNavigation(false);
1004 m_pTableView->verticalHeader()->hide();
1005 m_pTableView->verticalHeader()->setDefaultSectionSize((int)(m_pTableView->verticalHeader()->minimumSectionSize() * 1.33));
1006 m_pTableView->setSelectionMode(QAbstractItemView::SingleSelection);
1007 m_pTableView->setContextMenuPolicy(Qt::CustomContextMenu);
1008 m_pTableView->installEventFilter(this);
1009
1010 /* Prepare model: */
1011 prepareTableModel();
1012
1013 /* Finish configure table-view (after model is configured): */
1014 m_pTableView->setModel(m_pTableModel);
1015 connect(m_pTableView, &UIPortForwardingView::sigCurrentChanged, this, &UIPortForwardingTable::sltCurrentChanged);
1016 connect(m_pTableView, &UIPortForwardingView::customContextMenuRequested, this, &UIPortForwardingTable::sltShowTableContexMenu);
1017
1018 /* Prepare delegates: */
1019 prepareTableDelegates();
1020
1021 /* Add into layout: */
1022 m_pLayout->addWidget(m_pTableView);
1023 }
1024}
1025
1026void UIPortForwardingTable::prepareTableModel()
1027{
1028 /* Create table-model: */
1029 m_pTableModel = new UIPortForwardingModel(m_pTableView, m_rules);
1030 if (m_pTableModel)
1031 {
1032 /* Configure table-model: */
1033 connect(m_pTableModel, &UIPortForwardingModel::dataChanged,
1034 this, &UIPortForwardingTable::sltTableDataChanged);
1035 connect(m_pTableModel, &UIPortForwardingModel::rowsInserted,
1036 this, &UIPortForwardingTable::sltTableDataChanged);
1037 connect(m_pTableModel, &UIPortForwardingModel::rowsRemoved,
1038 this, &UIPortForwardingTable::sltTableDataChanged);
1039 }
1040}
1041
1042void UIPortForwardingTable::prepareTableDelegates()
1043{
1044 /* We certainly have abstract item delegate: */
1045 QAbstractItemDelegate *pAbstractItemDelegate = m_pTableView->itemDelegate();
1046 if (pAbstractItemDelegate)
1047 {
1048 /* But is this also styled item delegate? */
1049 QStyledItemDelegate *pStyledItemDelegate = qobject_cast<QStyledItemDelegate*>(pAbstractItemDelegate);
1050 if (pStyledItemDelegate)
1051 {
1052 /* Create new item editor factory: */
1053 QItemEditorFactory *pNewItemEditorFactory = new QItemEditorFactory;
1054 if (pNewItemEditorFactory)
1055 {
1056 /* Register NameEditor as the NameData editor: */
1057 int iNameId = qRegisterMetaType<NameData>();
1058 QStandardItemEditorCreator<NameEditor> *pNameEditorItemCreator = new QStandardItemEditorCreator<NameEditor>();
1059 pNewItemEditorFactory->registerEditor((QVariant::Type)iNameId, pNameEditorItemCreator);
1060
1061 /* Register ProtocolEditor as the KNATProtocol editor: */
1062 int iProtocolId = qRegisterMetaType<KNATProtocol>();
1063 QStandardItemEditorCreator<ProtocolEditor> *pProtocolEditorItemCreator = new QStandardItemEditorCreator<ProtocolEditor>();
1064 pNewItemEditorFactory->registerEditor((QVariant::Type)iProtocolId, pProtocolEditorItemCreator);
1065
1066 /* Register IPv4Editor/IPv6Editor as the IpData editor: */
1067 int iIpId = qRegisterMetaType<IpData>();
1068 if (!m_fIPv6)
1069 {
1070 QStandardItemEditorCreator<IPv4Editor> *pIPv4EditorItemCreator = new QStandardItemEditorCreator<IPv4Editor>();
1071 pNewItemEditorFactory->registerEditor((QVariant::Type)iIpId, pIPv4EditorItemCreator);
1072 }
1073 else
1074 {
1075 QStandardItemEditorCreator<IPv6Editor> *pIPv6EditorItemCreator = new QStandardItemEditorCreator<IPv6Editor>();
1076 pNewItemEditorFactory->registerEditor((QVariant::Type)iIpId, pIPv6EditorItemCreator);
1077 }
1078
1079 /* Register PortEditor as the PortData editor: */
1080 int iPortId = qRegisterMetaType<PortData>();
1081 QStandardItemEditorCreator<PortEditor> *pPortEditorItemCreator = new QStandardItemEditorCreator<PortEditor>();
1082 pNewItemEditorFactory->registerEditor((QVariant::Type)iPortId, pPortEditorItemCreator);
1083
1084 /* Set newly created item editor factory for table delegate: */
1085 pStyledItemDelegate->setItemEditorFactory(pNewItemEditorFactory);
1086 }
1087 }
1088 }
1089}
1090
1091void UIPortForwardingTable::prepareToolbar()
1092{
1093 /* Create toolbar: */
1094 m_pToolBar = new UIToolBar;
1095 if (m_pToolBar)
1096 {
1097 /* Determine icon metric: */
1098 const QStyle *pStyle = QApplication::style();
1099 const int iIconMetric = pStyle->pixelMetric(QStyle::PM_SmallIconSize);
1100
1101 /* Configure toolbar: */
1102 m_pToolBar->setIconSize(QSize(iIconMetric, iIconMetric));
1103 m_pToolBar->setOrientation(Qt::Vertical);
1104
1105 /* Create 'Add' action: */
1106 m_pActionAdd = new QAction(this);
1107 if (m_pActionAdd)
1108 {
1109 /* Configure action: */
1110 m_pActionAdd->setShortcut(QKeySequence("Ins"));
1111 m_pActionAdd->setIcon(UIIconPool::iconSet(":/controller_add_16px.png", ":/controller_add_disabled_16px.png"));
1112 connect(m_pActionAdd, &QAction::triggered, this, &UIPortForwardingTable::sltAddRule);
1113 m_pToolBar->addAction(m_pActionAdd);
1114 }
1115
1116 /* Create 'Copy' action: */
1117 m_pActionCopy = new QAction(this);
1118 if (m_pActionCopy)
1119 {
1120 /* Configure action: */
1121 m_pActionCopy->setIcon(UIIconPool::iconSet(":/controller_add_16px.png", ":/controller_add_disabled_16px.png"));
1122 connect(m_pActionCopy, &QAction::triggered, this, &UIPortForwardingTable::sltCopyRule);
1123 }
1124
1125 /* Create 'Remove' action: */
1126 m_pActionRemove = new QAction(this);
1127 if (m_pActionRemove)
1128 {
1129 /* Configure action: */
1130 m_pActionRemove->setShortcut(QKeySequence("Del"));
1131 m_pActionRemove->setIcon(UIIconPool::iconSet(":/controller_remove_16px.png", ":/controller_remove_disabled_16px.png"));
1132 connect(m_pActionRemove, &QAction::triggered, this, &UIPortForwardingTable::sltRemoveRule);
1133 m_pToolBar->addAction(m_pActionRemove);
1134 }
1135
1136 /* Add into layout: */
1137 m_pLayout->addWidget(m_pToolBar);
1138 }
1139}
1140
1141
1142#include "UIPortForwardingTable.moc"
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use