VirtualBox

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

Last change on this file was 105060, checked in by vboxsync, 3 months ago

FE/Qt: bugref:10681: A bit of cleanup for QITableView model stuff; Mostly reordering and adding RT_FINAL.

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

© 2024 Oracle
ContactPrivacy/Do Not Sell My InfoTerms of Use