VirtualBox

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

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

scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use