mirror of
https://github.com/GNS3/gns3-gui.git
synced 2026-05-28 22:40:30 +03:00
Compare commits
156 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0321c11c34 | ||
|
|
522df41a57 | ||
|
|
afccdf5b9e | ||
|
|
b2cd24b511 | ||
|
|
6d131a05f1 | ||
|
|
35e6156c6c | ||
|
|
96d8de4da8 | ||
|
|
6b5a6f3dfe | ||
|
|
8f82eac321 | ||
|
|
e03ed64f59 | ||
|
|
3d702aabd0 | ||
|
|
f5e63c2321 | ||
|
|
1047eb916a | ||
|
|
5dc7d0fbda | ||
|
|
2609be98b6 | ||
|
|
6286e596c0 | ||
|
|
3c546086ed | ||
|
|
f4b2c1c5b9 | ||
|
|
e578ecdd8a | ||
|
|
da8adbaa18 | ||
|
|
6d1333f5fe | ||
|
|
92c858dd07 | ||
|
|
0c7a12f68c | ||
|
|
a4d08cce8c | ||
|
|
e0dd7a66e1 | ||
|
|
23be668c97 | ||
|
|
68d0278140 | ||
|
|
d8e4c1de4d | ||
|
|
a5aa9bfb7a | ||
|
|
3e0273848f | ||
|
|
ec374f173c | ||
|
|
b8abdc79dc | ||
|
|
43744eab7e | ||
|
|
e16f700e49 | ||
|
|
925d57b2f8 | ||
|
|
eceaea1317 | ||
|
|
4326785dfc | ||
|
|
3920c28bde | ||
|
|
b34f51e4b0 | ||
|
|
ef45b2e0f1 | ||
|
|
545a9f53a8 | ||
|
|
83d9367860 | ||
|
|
2131f07e5f | ||
|
|
cf3e716e63 | ||
|
|
c79f14bcab | ||
|
|
acd044a88a | ||
|
|
f26c638350 | ||
|
|
4ea24e622b | ||
|
|
ab854752d9 | ||
|
|
5cee045a65 | ||
|
|
37cd82fb44 | ||
|
|
334eb5175c | ||
|
|
25841ea7db | ||
|
|
3d3b4f92b2 | ||
|
|
82740da89d | ||
|
|
ad19b3dda0 | ||
|
|
bb8fd18f98 | ||
|
|
336eaf443a | ||
|
|
0b94be6805 | ||
|
|
671ced78ff | ||
|
|
c8766ce529 | ||
|
|
bec9512c78 | ||
|
|
b2ad5f4158 | ||
|
|
966873bc6c | ||
|
|
5b9111b55d | ||
|
|
56688f2236 | ||
|
|
2e656a9d53 | ||
|
|
2790f707c3 | ||
|
|
ee9002df61 | ||
|
|
52626e9fe9 | ||
|
|
6619c6af97 | ||
|
|
60e04c7248 | ||
|
|
724858f977 | ||
|
|
5a2e05a4fd | ||
|
|
010888e3ca | ||
|
|
3226921536 | ||
|
|
022e918301 | ||
|
|
846b19a9e7 | ||
|
|
45f5c6e010 | ||
|
|
963bbb7b89 | ||
|
|
016ad7a775 | ||
|
|
e8c82566c6 | ||
|
|
1ed6fceade | ||
|
|
d945fd8b7b | ||
|
|
fd6c7eccd0 | ||
|
|
7a1afe2aec | ||
|
|
6debe56d8e | ||
|
|
a4c7d41c26 | ||
|
|
ea9243dcd9 | ||
|
|
e9d8337bd6 | ||
|
|
3c92e463f8 | ||
|
|
3d07db5c5f | ||
|
|
20cc309ac8 | ||
|
|
262a2839c5 | ||
|
|
ece4d51213 | ||
|
|
0ef39ba129 | ||
|
|
f90267b4f0 | ||
|
|
8f16706a22 | ||
|
|
2d3ee3abf9 | ||
|
|
b8b209fa55 | ||
|
|
18129e3d29 | ||
|
|
7a2b9c024f | ||
|
|
4923a6dc17 | ||
|
|
73dfc047aa | ||
|
|
fe0a70c4be | ||
|
|
67014965be | ||
|
|
f14cb43404 | ||
|
|
f8517ee5ac | ||
|
|
7dc607b4c5 | ||
|
|
882fa76550 | ||
|
|
1490a1ad8f | ||
|
|
aab0c99cc6 | ||
|
|
a6a987d74c | ||
|
|
9c58b18c20 | ||
|
|
8bc499c68f | ||
|
|
bd5eb288b7 | ||
|
|
465a289568 | ||
|
|
d240ba3056 | ||
|
|
3cedfd3649 | ||
|
|
276d7abdd9 | ||
|
|
927e38bd6d | ||
|
|
376cc29995 | ||
|
|
1f8ebeb084 | ||
|
|
0212755c78 | ||
|
|
2f7d75eae9 | ||
|
|
fc1c060922 | ||
|
|
0ea72ce782 | ||
|
|
3de2d2eda2 | ||
|
|
c08262f8af | ||
|
|
9ae70bf2fe | ||
|
|
fa6d250602 | ||
|
|
0668840a2b | ||
|
|
8b25d1b06c | ||
|
|
58c3ba0755 | ||
|
|
5a91c9aaf8 | ||
|
|
0fc3f4ef16 | ||
|
|
f0e5cd2ba2 | ||
|
|
f59ef6378a | ||
|
|
61ef08d1b7 | ||
|
|
e812c000fd | ||
|
|
d3d9e1e8ae | ||
|
|
05f8df345a | ||
|
|
4b0cc11cab | ||
|
|
b5285cd142 | ||
|
|
69482343ba | ||
|
|
d4639c2e61 | ||
|
|
b85ade9dd7 | ||
|
|
e191cb8aa3 | ||
|
|
e6bc75ce26 | ||
|
|
bc1df346f2 | ||
|
|
3e212fc629 | ||
|
|
25e41dc0f1 | ||
|
|
c58c7774c4 | ||
|
|
bd2bc8265c | ||
|
|
f2209a2780 | ||
|
|
5dc2c77806 |
130
CHANGELOG
130
CHANGELOG
@@ -1,5 +1,135 @@
|
||||
# Change Log
|
||||
|
||||
## 2.2.32 27/04/2022
|
||||
|
||||
* Use public DSNs for Sentry
|
||||
* Fix exception when doubleclick on NAT node. Fixes #3312
|
||||
* Fix "Apply" button in the "Preferences" dialog stays gray when templates/nodes are opened by double-click. Fixes #3307
|
||||
* Add 'reset docks' in the view menu. Ref #3317
|
||||
|
||||
## 2.2.31 26/02/2022
|
||||
|
||||
* Install setuptools v59.6.0 when using Python 3.6
|
||||
|
||||
## 2.2.30 25/02/2022
|
||||
|
||||
* Set setuptools to v60.6.0
|
||||
* Upgrade to pywin32 v303. Ref #3290
|
||||
* Fix int() call. Ref #3283
|
||||
* Fix QPoint() as unexpected type 'float'. Fixes #3283
|
||||
* Fix painter.drawRect() has unexpected type 'float'. Fixes #3282
|
||||
* Fix SpinBox.setValue() requires integer. Fixes #3281
|
||||
|
||||
## 2.2.29 08/01/2022
|
||||
|
||||
* Clear cache when opening symbol selection dialog. Fixes #3256
|
||||
* Fix @ in username issue with HTTP authentication. Fixes #3275
|
||||
* Use '//' operator instead of int()
|
||||
* Fix create drawing item calls since mapToScene() returns a QPointF https://doc.qt.io/qt-5/qgraphicsview.html#mapToScene-4
|
||||
* Fixed QPoint called with floats
|
||||
|
||||
## 2.2.28 15/12/2021
|
||||
|
||||
* Fixed drawLine called with float arguments
|
||||
* Fixed dead VIX API link
|
||||
|
||||
## 2.2.27 12/11/2021
|
||||
|
||||
* Fix symbols in "Symbol selection" dialog are not placed in alphabetical order. Fixes #3245
|
||||
* Fix links duplicates in topology summary. Fixes #3251
|
||||
* chore : use --no-cache-dir flag to pip in dockerfiles to save space
|
||||
|
||||
## 2.2.26 08/10/2021
|
||||
|
||||
* Upgrade embedded Python to version 3.7 in Windows package
|
||||
* Upgrade Visual C++ Redistributable for Visual Studio 2019 in Windows package
|
||||
* Fix SSL support in Windows package
|
||||
* Open "template configuration" dialog with double click on template name in "Preferences". Fixes #3239
|
||||
* Only show "virtio" network adapter when legacy node is enabled. Fixes https://github.com/GNS3/gns3-gui/issues/1969
|
||||
* Double-click on a template opens "template configuration" dialog. Fixes #3236
|
||||
* Fix "Custom symbols" can't be unfolded after using "Filter" field. Fixes #3231
|
||||
|
||||
## 2.2.25 14/09/2021
|
||||
|
||||
* Fix menu disabled for modal dialogs on macOS. Fixes #3007
|
||||
* Change method to display the recent files menu. Fixes #3007
|
||||
* Fix bug when using empty port names for custom adapters. Fixes #3228
|
||||
* Upgrade Qt to version 5.15.4 on macOS
|
||||
* Fix mouse zoom-in/out step value is two times bigger than keyboard one. Fixes #3226
|
||||
* Upgrade to Qt 5.15.4 on Windows. Ref #3210
|
||||
* Fix issue with custom adapters at the node level. Fixes #3223
|
||||
* Explicitly require setuptools, utils/get_resource.py imports pkg_resources
|
||||
|
||||
## 2.2.24 25/08/2021
|
||||
|
||||
* Fix incorrect Qemu binary selected when importing template. Fixes https://github.com/GNS3/gns3-gui/issues/3216
|
||||
* Early support for Python3.10
|
||||
* Bump pywin32 from 300 to 301
|
||||
* Add PyQt5==5.12.3 for macOS build
|
||||
|
||||
## 2.2.23 05/08/2021
|
||||
|
||||
* Handle -no-kvm param deprecated in Qemu >= v5.2
|
||||
* Support for invisible links. Fixes #2461
|
||||
* Add kitty console application command line. Fixes #3203
|
||||
* Add Windows Terminal profile as an option for Console Applications. Fixes #3193
|
||||
|
||||
## 2.2.22 10/06/2021
|
||||
|
||||
* Fix exception shown when GNS3 is started with empty config. Fixes #3188
|
||||
* Add ZOC8 console terminal for macOS command line
|
||||
* Link style support. Fixes https://github.com/GNS3/gns3-gui/issues/2461
|
||||
* Fix charcoal theme. Ref #3137
|
||||
* Fix issue when showing menu to select port. Fixes #3169
|
||||
|
||||
## 2.2.21 10/05/2021
|
||||
|
||||
* Fix issue with empty project variable name. Fixes #3162
|
||||
* Downgrade to PyQt5 5.12.1. Fixes https://github.com/GNS3/gns3-gui/issues/3169
|
||||
|
||||
## 2.2.20 09/04/2021
|
||||
|
||||
* Fix project does not load anymore. Fixes #3140
|
||||
* Do not connect to server while waiting for user to accept/reject SSL certificate. Fixes #3144
|
||||
* Fix invalid server version check request. Fixes #3144
|
||||
* Upgrade dependencies
|
||||
* Add terminator as a predefined custom console option
|
||||
|
||||
## 2.2.19 05/03/2021
|
||||
|
||||
* No changes
|
||||
|
||||
## 2.2.18 16/02/2021
|
||||
|
||||
* SSL support.
|
||||
* Remove the useless file "zoom-in (copy).svg". Fixes #3114
|
||||
* Use HDD disk image as startup QEMU config disk
|
||||
* Edit only text mode config files
|
||||
* Hide config import/export when configFiles attribute is empty
|
||||
* Qemu disk interfaces must be set to "none" by default. Ref #3035
|
||||
* Do not allow image to be configured on Qemu VM secondary slave disk if create config disk option is enabled.
|
||||
* Add explicit option to automatically create or not the config disk. Off by default.
|
||||
* QEMU config disk support
|
||||
|
||||
## 2.2.17 04/12/2020
|
||||
|
||||
* Remove "-nographic" option by default for Qemu VM. Fixes #3094
|
||||
* Fix app cannot start on macOS Big Sur. Ref #3037
|
||||
* Require confirmation before stopping all devices.
|
||||
|
||||
## 2.2.16 05/11/2020
|
||||
|
||||
* Fix packets capture stops after some time. Fixes #3067
|
||||
* Option to allocate or not the vCPUs and RAM settings for the GNS3 VM. Fixes https://github.com/GNS3/gns3-gui/issues/3069
|
||||
|
||||
## 2.2.15 07/10/2020
|
||||
|
||||
* Fix custom symbol not sent to remote controller when installing appliance
|
||||
|
||||
## 2.2.14 14/09/2020
|
||||
|
||||
* Improvements to add a new version of an appliance from wizard. Fixes #3002.
|
||||
|
||||
## 2.2.13 04/09/2020
|
||||
|
||||
* No changes
|
||||
|
||||
@@ -8,7 +8,7 @@ RUN apt-get clean
|
||||
|
||||
ADD dev-requirements.txt /dev-requirements.txt
|
||||
ADD requirements.txt /requirements.txt
|
||||
RUN pip3 install -r /dev-requirements.txt
|
||||
RUN pip3 install --no-cache-dir -r /dev-requirements.txt
|
||||
|
||||
ADD . /src
|
||||
WORKDIR /src
|
||||
|
||||
@@ -54,6 +54,7 @@ https://github.com/Kozea/wdb
|
||||
|
||||
Security issues
|
||||
----------------
|
||||
Please contact us using contact informations available here:
|
||||
http://docs.gns3.com/1ON9JBXSeR7Nt2-Qum2o3ZX0GU86BZwlmNSUgvmqNWGY/index.html
|
||||
|
||||
Please contact us at security@gns3.net
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
-rrequirements.txt
|
||||
|
||||
pytest==5.4.3
|
||||
flake8==3.8.3
|
||||
pytest-timeout==1.4.1
|
||||
pytest==6.2.4
|
||||
flake8==3.9.2
|
||||
pytest-timeout==1.4.2
|
||||
|
||||
@@ -130,7 +130,8 @@ class Controller(QtCore.QObject):
|
||||
|
||||
self._connected = False
|
||||
self._connecting = True
|
||||
self.get('/version', self._versionGetSlot)
|
||||
status, json_data = self.httpClient().getSynchronous('GET', '/version', timeout=60)
|
||||
self._versionGetSlot(json_data, status is None or status >= 300)
|
||||
|
||||
def _httpClientDisconnectedSlot(self):
|
||||
if self._connected:
|
||||
@@ -148,11 +149,14 @@ class Controller(QtCore.QObject):
|
||||
if self._first_error:
|
||||
self._connecting = False
|
||||
self.connection_failed_signal.emit()
|
||||
if "message" in result and self._display_error:
|
||||
if self._display_error:
|
||||
self._error_dialog = QtWidgets.QMessageBox(self.parent())
|
||||
self._error_dialog.setWindowModality(QtCore.Qt.ApplicationModal)
|
||||
self._error_dialog.setWindowTitle("Connection to server")
|
||||
self._error_dialog.setText("Error when connecting to the GNS3 server:\n{}".format(result["message"]))
|
||||
if result and "message" in result:
|
||||
self._error_dialog.setText("Error when connecting to the GNS3 server:\n{}".format(result["message"]))
|
||||
else:
|
||||
self._error_dialog.setText("Cannot connect to the GNS3 server")
|
||||
self._error_dialog.setIcon(QtWidgets.QMessageBox.Critical)
|
||||
self._error_dialog.show()
|
||||
# Try to connect again in 5 seconds
|
||||
@@ -164,6 +168,7 @@ class Controller(QtCore.QObject):
|
||||
self._error_dialog.reject()
|
||||
self._error_dialog = None
|
||||
self._version = result.get("version")
|
||||
self._http_client.connection_connected_signal.emit()
|
||||
|
||||
def _httpClientConnectedSlot(self):
|
||||
|
||||
@@ -423,6 +428,7 @@ class Controller(QtCore.QObject):
|
||||
self._notification_stream = self._http_client.connectWebSocket(self._websocket, "/notifications/ws")
|
||||
self._notification_stream.textMessageReceived.connect(self._websocket_event_received)
|
||||
self._notification_stream.error.connect(self._websocket_error)
|
||||
self._notification_stream.sslErrors.connect(self._sslErrorsSlot)
|
||||
|
||||
def stopListenNotifications(self):
|
||||
if self._notification_stream:
|
||||
@@ -447,6 +453,11 @@ class Controller(QtCore.QObject):
|
||||
self._notification_stream = None
|
||||
self._startListenNotifications()
|
||||
|
||||
@qslot
|
||||
def _sslErrorsSlot(self, ssl_errors):
|
||||
|
||||
self._http_client.handleSslError(self._notification_stream, ssl_errors)
|
||||
|
||||
@qslot
|
||||
def _websocket_event_received(self, event):
|
||||
try:
|
||||
|
||||
@@ -51,7 +51,7 @@ class CrashReport:
|
||||
Report crash to a third party service
|
||||
"""
|
||||
|
||||
DSN = "https://ecfc8b6de2384166a78f60faa57a365b:854abb2a55b048588bf56011de63a11c@o19455.ingest.sentry.io/38506"
|
||||
DSN = "https://8aa9e09917494af7b7def60f0aed8512@o19455.ingest.sentry.io/38506"
|
||||
_instance = None
|
||||
|
||||
def __init__(self):
|
||||
|
||||
@@ -475,8 +475,24 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
Allow user to create a new version of an appliance
|
||||
"""
|
||||
|
||||
new_version, ok = QtWidgets.QInputDialog.getText(self, "Creating a new version", "Create a new version for this appliance.\nPlease share your experience on the GNS3 community if this version works.\n\nVersion name:", QtWidgets.QLineEdit.Normal)
|
||||
current = self.uiApplianceVersionTreeWidget.currentItem()
|
||||
if current is None:
|
||||
QtWidgets.QMessageBox.critical(self.parent(), "Base version", "Please select a base version")
|
||||
return
|
||||
base_version = current.data(0, QtCore.Qt.UserRole)
|
||||
|
||||
new_version_name, ok = QtWidgets.QInputDialog.getText(self, "Creating a new version", "Create a new version for this appliance.\nPlease share your experience on the GNS3 community if this version works.\n\nVersion name:", QtWidgets.QLineEdit.Normal, base_version.get("name"))
|
||||
if ok:
|
||||
new_version = {"name": new_version_name}
|
||||
new_version["images"] = {}
|
||||
|
||||
for disk_type in base_version["images"]:
|
||||
base_filename = base_version["images"][disk_type]["filename"]
|
||||
filename, ok = QtWidgets.QInputDialog.getText(self, "Image", "Disk image filename for {}".format(disk_type), QtWidgets.QLineEdit.Normal, base_filename)
|
||||
if not ok:
|
||||
filename = base_filename
|
||||
new_version["images"][disk_type] = {"filename": filename, "version": new_version_name}
|
||||
|
||||
try:
|
||||
self._appliance.create_new_version(new_version)
|
||||
except ApplianceError as e:
|
||||
@@ -538,7 +554,7 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
if self.uiQemuListComboBox.count() == 1:
|
||||
self.next()
|
||||
else:
|
||||
i = self.uiQemuListComboBox.findText(self._appliance["qemu"]["arch"], QtCore.Qt.MatchContains)
|
||||
i = self.uiQemuListComboBox.findData(self._appliance["qemu"]["arch"], flags=QtCore.Qt.MatchEndsWith)
|
||||
if i != -1:
|
||||
self.uiQemuListComboBox.setCurrentIndex(i)
|
||||
|
||||
|
||||
@@ -169,6 +169,9 @@ class CustomAdaptersConfigurationDialog(QtWidgets.QDialog, Ui_CustomAdaptersConf
|
||||
adapter_number = item.data(0, QtCore.Qt.UserRole)
|
||||
custom_adapter_settings["adapter_number"] = adapter_number
|
||||
original_port_name = item.data(1, QtCore.Qt.UserRole)
|
||||
if not port_name:
|
||||
QtWidgets.QMessageBox.critical(self, "Port name", "Port name cannot be empty for adapter {}".format(adapter_number))
|
||||
return False
|
||||
if original_port_name != port_name:
|
||||
custom_adapter_settings["port_name"] = port_name
|
||||
if self._default_adapter_type and self._adapter_types:
|
||||
@@ -180,13 +183,14 @@ class CustomAdaptersConfigurationDialog(QtWidgets.QDialog, Ui_CustomAdaptersConf
|
||||
if mac_address and mac_address != ":::::":
|
||||
if not re.search(r"""^([0-9a-fA-F]{2}[:]){5}[0-9a-fA-F]{2}$""", mac_address):
|
||||
QtWidgets.QMessageBox.critical(self, "MAC address", "Invalid MAC address (format required: hh:hh:hh:hh:hh:hh)")
|
||||
return
|
||||
return False
|
||||
default_mac_address = self._IntegerToMac(self._MacToInteger(self._base_mac_address) + adapter_number)
|
||||
if mac_address != default_mac_address:
|
||||
custom_adapter_settings["mac_address"] = mac_address
|
||||
if len(custom_adapter_settings) > 1:
|
||||
# only save if there is more than the adapter_number key
|
||||
self._custom_adapters.append(custom_adapter_settings.copy())
|
||||
return True
|
||||
|
||||
def done(self, result):
|
||||
"""
|
||||
@@ -196,5 +200,6 @@ class CustomAdaptersConfigurationDialog(QtWidgets.QDialog, Ui_CustomAdaptersConf
|
||||
"""
|
||||
|
||||
if result:
|
||||
self._updateCustomAdapters()
|
||||
if not self._updateCustomAdapters():
|
||||
return
|
||||
super().done(result)
|
||||
|
||||
@@ -41,6 +41,9 @@ class EditComputeDialog(QtWidgets.QDialog, Ui_EditComputeDialog):
|
||||
self.uiServerHostLineEdit.setText(self._compute.host())
|
||||
self.uiServerPortSpinBox.setValue(self._compute.port())
|
||||
|
||||
index = self.uiServerProtocolComboBox.findText(self._compute.protocol().upper())
|
||||
self.uiServerProtocolComboBox.setCurrentIndex(index)
|
||||
|
||||
if self._compute.user():
|
||||
self.uiEnableAuthenticationCheckBox.setChecked(True)
|
||||
self.uiServerUserLineEdit.setText(self._compute.user())
|
||||
@@ -78,7 +81,7 @@ class EditComputeDialog(QtWidgets.QDialog, Ui_EditComputeDialog):
|
||||
|
||||
host = self.uiServerHostLineEdit.text().strip()
|
||||
name = self.uiServerNameLineEdit.text().strip()
|
||||
protocol = "http"
|
||||
protocol = self.uiServerProtocolComboBox.currentText().lower()
|
||||
port = self.uiServerPortSpinBox.value()
|
||||
user = self.uiServerUserLineEdit.text().strip()
|
||||
password = self.uiServerPasswordLineEdit.text().strip()
|
||||
|
||||
@@ -98,7 +98,7 @@ class EditProjectDialog(QtWidgets.QDialog, Ui_EditProjectDialog):
|
||||
variable["value"] = text
|
||||
|
||||
def _cleanVariables(self):
|
||||
return [v for v in self._variables if v.get("name", "").strip() != ""]
|
||||
return [v for v in self._variables if v.get("name").strip() != ""]
|
||||
|
||||
def done(self, result):
|
||||
"""
|
||||
|
||||
@@ -131,6 +131,7 @@ class PreferencesDialog(QtWidgets.QDialog, Ui_PreferencesDialog):
|
||||
QtWidgets.QLineEdit: "textChanged",
|
||||
QtWidgets.QPlainTextEdit: "textChanged",
|
||||
# QtWidgets.QTreeWidget: "itemChanged",
|
||||
QtWidgets.QTreeWidget: "itemDoubleClicked",
|
||||
QtWidgets.QComboBox: "currentIndexChanged",
|
||||
QtWidgets.QSpinBox: "valueChanged",
|
||||
QtWidgets.QAbstractButton: "pressed"
|
||||
|
||||
@@ -53,7 +53,7 @@ class ProjectDialog(QtWidgets.QDialog, Ui_ProjectDialog):
|
||||
|
||||
if show_open_options:
|
||||
self.uiOpenProjectPushButton.clicked.connect(self._openProjectActionSlot)
|
||||
self.uiRecentProjectsPushButton.clicked.connect(self._showRecentProjectsSlot)
|
||||
self._addRecentFilesMenu()
|
||||
else:
|
||||
self.uiOpenProjectGroupBox.hide()
|
||||
self.uiProjectTabWidget.removeTab(1)
|
||||
@@ -231,12 +231,12 @@ class ProjectDialog(QtWidgets.QDialog, Ui_ProjectDialog):
|
||||
self._main_window.openProjectActionSlot()
|
||||
self.reject()
|
||||
|
||||
def _showRecentProjectsSlot(self):
|
||||
def _addRecentFilesMenu(self):
|
||||
"""
|
||||
lot to show all the recent projects in a menu.
|
||||
Add recent projects in a menu.
|
||||
"""
|
||||
|
||||
menu = QtWidgets.QMenu()
|
||||
menu = QtWidgets.QMenu(parent=self)
|
||||
if Controller.instance().isRemote():
|
||||
for action in self._main_window.recent_project_actions:
|
||||
menu.addAction(action)
|
||||
@@ -244,7 +244,7 @@ class ProjectDialog(QtWidgets.QDialog, Ui_ProjectDialog):
|
||||
for action in self._main_window.recent_file_actions:
|
||||
menu.addAction(action)
|
||||
menu.triggered.connect(self._menuTriggeredSlot)
|
||||
menu.exec_(QtGui.QCursor.pos())
|
||||
self.uiRecentProjectsPushButton.setMenu(menu)
|
||||
|
||||
def _overwriteProjectCallback(self, result, error=False, **kwargs):
|
||||
if error:
|
||||
|
||||
@@ -50,6 +50,7 @@ class SetupWizard(QtWidgets.QWizard, Ui_SetupWizard):
|
||||
"headless": False,
|
||||
"when_exit": "stop",
|
||||
"engine": "vmware",
|
||||
"allocate_vcpus_ram": True,
|
||||
"vcpus": 1,
|
||||
"ram": 2048,
|
||||
"vmname": "GNS3 VM",
|
||||
@@ -126,7 +127,7 @@ class SetupWizard(QtWidgets.QWizard, Ui_SetupWizard):
|
||||
from gns3.modules import VMware
|
||||
settings = VMware.instance().settings()
|
||||
if not os.path.exists(settings["vmrun_path"]):
|
||||
QtWidgets.QMessageBox.critical(self, "VMware", "VMware vmrun tool could not be found, VMware or the VIX API (required for VMware player) is probably not installed. You can download it from https://www.vmware.com/support/developer/vix-api/. After installation you need to restart GNS3.")
|
||||
QtWidgets.QMessageBox.critical(self, "VMware", "VMware vmrun tool could not be found, VMware or the VIX API (required for VMware player) is probably not installed. You can download it from https://customerconnect.vmware.com/downloads/details?downloadGroup=PLAYER-1400-VIX1170&productId=687. After installation you need to restart GNS3.")
|
||||
return
|
||||
self._refreshVMListSlot()
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ class StyleEditorDialog(QtWidgets.QDialog, Ui_StyleEditorDialog):
|
||||
self._border_color.green(),
|
||||
self._border_color.blue(),
|
||||
self._border_color.alpha()))
|
||||
self.uiRotationSpinBox.setValue(first_item.rotation())
|
||||
self.uiRotationSpinBox.setValue(int(first_item.rotation()))
|
||||
self.uiBorderWidthSpinBox.setValue(pen.width())
|
||||
index = self.uiBorderStyleComboBox.findData(pen.style())
|
||||
if index != -1:
|
||||
|
||||
115
gns3/dialogs/style_editor_dialog_link.py
Normal file
115
gns3/dialogs/style_editor_dialog_link.py
Normal file
@@ -0,0 +1,115 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2019 Pekka Helenius
|
||||
# Copyright (C) 2014 GNS3 Technologies Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
Style editor to edit Link items.
|
||||
"""
|
||||
|
||||
from ..qt import QtCore, QtWidgets, QtGui
|
||||
from ..ui.style_editor_dialog_ui import Ui_StyleEditorDialog
|
||||
|
||||
|
||||
class StyleEditorDialogLink(QtWidgets.QDialog, Ui_StyleEditorDialog):
|
||||
|
||||
"""
|
||||
Style editor dialog.
|
||||
|
||||
:param parent: parent widget
|
||||
:param link: selected link
|
||||
"""
|
||||
|
||||
def __init__(self, link, parent):
|
||||
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
|
||||
self._link = link
|
||||
self._link_style = {}
|
||||
|
||||
self.uiBorderColorPushButton.clicked.connect(self._setBorderColorSlot)
|
||||
self.uiButtonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(self._applyPreferencesSlot)
|
||||
|
||||
self.uiBorderStyleComboBox.addItem("Solid", QtCore.Qt.SolidLine)
|
||||
self.uiBorderStyleComboBox.addItem("Dash", QtCore.Qt.DashLine)
|
||||
self.uiBorderStyleComboBox.addItem("Dot", QtCore.Qt.DotLine)
|
||||
self.uiBorderStyleComboBox.addItem("Dash Dot", QtCore.Qt.DashDotLine)
|
||||
self.uiBorderStyleComboBox.addItem("Dash Dot Dot", QtCore.Qt.DashDotDotLine)
|
||||
self.uiBorderStyleComboBox.addItem("Invisible", QtCore.Qt.NoPen)
|
||||
|
||||
self.uiColorLabel.hide()
|
||||
self.uiColorPushButton.hide()
|
||||
self._color = None
|
||||
|
||||
self.uiRotationLabel.hide()
|
||||
self.uiRotationSpinBox.hide()
|
||||
|
||||
pen = link.pen()
|
||||
|
||||
self._border_color = pen.color()
|
||||
self.uiBorderColorPushButton.setStyleSheet("background-color: rgba({}, {}, {}, {});".format(self._border_color.red(),
|
||||
self._border_color.green(),
|
||||
self._border_color.blue(),
|
||||
self._border_color.alpha()))
|
||||
self.uiBorderWidthSpinBox.setValue(pen.width())
|
||||
index = self.uiBorderStyleComboBox.findData(pen.style())
|
||||
if index != -1:
|
||||
self.uiBorderStyleComboBox.setCurrentIndex(index)
|
||||
|
||||
self.adjustSize()
|
||||
|
||||
def _setBorderColorSlot(self):
|
||||
"""
|
||||
Slot to select the border color.
|
||||
"""
|
||||
|
||||
color = QtWidgets.QColorDialog.getColor(self._border_color, self, "Select Color", QtWidgets.QColorDialog.ShowAlphaChannel)
|
||||
if color.isValid():
|
||||
self._border_color = color
|
||||
self.uiBorderColorPushButton.setStyleSheet("background-color: rgba({}, {}, {}, {});".format(self._border_color.red(),
|
||||
self._border_color.green(),
|
||||
self._border_color.blue(),
|
||||
self._border_color.alpha()))
|
||||
|
||||
def _applyPreferencesSlot(self):
|
||||
"""
|
||||
Applies the new style settings.
|
||||
"""
|
||||
|
||||
border_style = QtCore.Qt.PenStyle(self.uiBorderStyleComboBox.itemData(self.uiBorderStyleComboBox.currentIndex()))
|
||||
pen = QtGui.QPen(self._border_color, self.uiBorderWidthSpinBox.value(), border_style, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
|
||||
|
||||
self._link.setPen(pen)
|
||||
|
||||
new_link_style = {}
|
||||
new_link_style["color"] = self._border_color.name()
|
||||
new_link_style["width"] = self.uiBorderWidthSpinBox.value()
|
||||
new_link_style["type"] = border_style
|
||||
|
||||
# Store values
|
||||
self._link.setLinkStyle(new_link_style)
|
||||
|
||||
def done(self, result):
|
||||
"""
|
||||
Called when the dialog is closed.
|
||||
|
||||
:param result: boolean (accepted or rejected)
|
||||
"""
|
||||
|
||||
if result:
|
||||
self._applyPreferencesSlot()
|
||||
super().done(result)
|
||||
@@ -67,6 +67,7 @@ class SymbolSelectionDialog(QtWidgets.QDialog, Ui_SymbolSelectionDialog):
|
||||
self._symbol_items = []
|
||||
self._parents = {}
|
||||
|
||||
Controller.instance().clearStaticCache() # TODO: use etag to know when to refresh the cache
|
||||
Controller.instance().get("/symbols", self._listSymbolsCallback)
|
||||
|
||||
def _listSymbolsCallback(self, result, error=False, **kwargs):
|
||||
@@ -108,6 +109,9 @@ class SymbolSelectionDialog(QtWidgets.QDialog, Ui_SymbolSelectionDialog):
|
||||
item.setIcon(0, icon)
|
||||
|
||||
Controller.instance().getStatic(symbol.url(), qpartial(render, item))
|
||||
|
||||
for parent in self._parents.values():
|
||||
parent.sortChildren(0, QtCore.Qt.AscendingOrder)
|
||||
self.adjustSize()
|
||||
|
||||
def _searchTextChangedSlot(self, text):
|
||||
@@ -119,13 +123,13 @@ class SymbolSelectionDialog(QtWidgets.QDialog, Ui_SymbolSelectionDialog):
|
||||
"""
|
||||
text = self.uiSearchLineEdit.text()
|
||||
for item in self._symbol_items:
|
||||
if not item.data(0, QtCore.Qt.UserRole).builtin():
|
||||
item.setHidden(True)
|
||||
# if not item.data(0, QtCore.Qt.UserRole).builtin():
|
||||
# item.setHidden(True)
|
||||
# else:
|
||||
if not text.strip() or text.strip().lower() in item.text(0).lower():
|
||||
item.setHidden(False)
|
||||
else:
|
||||
if len(text.strip()) == 0 or text.strip().lower() in item.text(0).lower():
|
||||
item.setHidden(False)
|
||||
else:
|
||||
item.setHidden(True)
|
||||
item.setHidden(True)
|
||||
|
||||
def _customSymbolToggledSlot(self, checked):
|
||||
"""
|
||||
|
||||
@@ -44,7 +44,7 @@ class TextEditorDialog(QtWidgets.QDialog, Ui_TextEditorDialog):
|
||||
# use the first item in the list as the model
|
||||
first_item = items[0]
|
||||
self._setColor(first_item.defaultTextColor())
|
||||
self.uiRotationSpinBox.setValue(first_item.rotation())
|
||||
self.uiRotationSpinBox.setValue(int(first_item.rotation()))
|
||||
self.uiPlainTextEdit.setPlainText(first_item.toPlainText())
|
||||
self.uiPlainTextEdit.setFont(first_item.font())
|
||||
|
||||
|
||||
@@ -326,6 +326,8 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
# connect the signals that let the graphics view knows about events such as
|
||||
# a new link creation or deletion.
|
||||
if self._topology.addLink(link):
|
||||
source_node.addLink(link)
|
||||
destination_node.addLink(link)
|
||||
link.add_link_signal.connect(self.addLinkSlot)
|
||||
link.delete_link_signal.connect(self.deleteLinkSlot)
|
||||
|
||||
@@ -392,7 +394,7 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
# link addition code
|
||||
if not self._newlink:
|
||||
source_item = item
|
||||
source_port = source_item.connectToPort()
|
||||
source_port = source_item.connectToPort(event.globalPos())
|
||||
if not source_port:
|
||||
return
|
||||
|
||||
@@ -409,7 +411,7 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
source_item = self._newlink.sourceItem()
|
||||
source_port = self._newlink.sourcePort()
|
||||
destination_item = item
|
||||
destination_port = destination_item.connectToPort()
|
||||
destination_port = destination_item.connectToPort(event.globalPos())
|
||||
if not destination_port:
|
||||
return
|
||||
|
||||
@@ -471,7 +473,7 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
#QtWidgets.QApplication.sendEvent(self, context_event)
|
||||
elif event.button() == QtCore.Qt.LeftButton and self._adding_note:
|
||||
pos = self.mapToScene(event.pos())
|
||||
note = self.createDrawingItem("text", pos.x(), pos.y(), 2)
|
||||
note = self.createDrawingItem("text", int(pos.x()), int(pos.y()), 2)
|
||||
pos_x = note.pos().x()
|
||||
pos_y = note.pos().y() - (note.boundingRect().height() / 2)
|
||||
note.setPos(pos_x, pos_y)
|
||||
@@ -481,19 +483,19 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
self._adding_note = False
|
||||
elif event.button() == QtCore.Qt.LeftButton and self._adding_rectangle:
|
||||
pos = self.mapToScene(event.pos())
|
||||
self.createDrawingItem("rect", pos.x(), pos.y(), 1)
|
||||
self.createDrawingItem("rect", int(pos.x()), int(pos.y()), 1)
|
||||
self._main_window.uiDrawRectangleAction.setChecked(False)
|
||||
self.setCursor(QtCore.Qt.ArrowCursor)
|
||||
self._adding_rectangle = False
|
||||
elif event.button() == QtCore.Qt.LeftButton and self._adding_ellipse:
|
||||
pos = self.mapToScene(event.pos())
|
||||
self.createDrawingItem("ellipse", pos.x(), pos.y(), 1)
|
||||
self.createDrawingItem("ellipse", int(pos.x()), int(pos.y()), 1)
|
||||
self._main_window.uiDrawEllipseAction.setChecked(False)
|
||||
self.setCursor(QtCore.Qt.ArrowCursor)
|
||||
self._adding_ellipse = False
|
||||
elif event.button() == QtCore.Qt.LeftButton and self._adding_line:
|
||||
pos = self.mapToScene(event.pos())
|
||||
self.createDrawingItem("line", pos.x(), pos.y(), 1)
|
||||
self.createDrawingItem("line", int(pos.x()), int(pos.y()), 1)
|
||||
self._main_window.uiDrawLineAction.setChecked(False)
|
||||
self.setCursor(QtCore.Qt.ArrowCursor)
|
||||
self._adding_line = False
|
||||
@@ -577,7 +579,7 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
delta = event.angleDelta()
|
||||
if delta is not None and delta.x() == 0:
|
||||
# CTRL is pressed then use the mouse wheel to zoom in or out.
|
||||
self.scaleView(pow(2.0, delta.y() / 240.0))
|
||||
self.scaleView(pow(2.0, (delta.y()/2) / 240.0))
|
||||
self._topology.project().setZoom(round(self.transform().m11() * 100))
|
||||
self._topology.project().update()
|
||||
else:
|
||||
@@ -657,7 +659,7 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
if not self._adding_link:
|
||||
if isinstance(item, NodeItem) and item.node().initialized():
|
||||
item.setSelected(True)
|
||||
if item.node().status() == Node.stopped or item.node().consoleType() == "none":
|
||||
if item.node().status() == Node.stopped or item.node().consoleType() == "none" or item.node().consoleType() is None:
|
||||
self.configureSlot()
|
||||
return
|
||||
else:
|
||||
@@ -721,8 +723,8 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
integer, ok = QtWidgets.QInputDialog.getInt(self, "Nodes", "Number of nodes:", 2, 1, 100, 1)
|
||||
if ok:
|
||||
for node_number in range(integer):
|
||||
x = event.pos().x() - (150 / 2) + (node_number % max_nodes_per_line) * offset
|
||||
y = event.pos().y() - (70 / 2) + (node_number // max_nodes_per_line) * offset
|
||||
x = event.pos().x() - (150 // 2) + (node_number % max_nodes_per_line) * offset
|
||||
y = event.pos().y() - (70 // 2) + (node_number // max_nodes_per_line) * offset
|
||||
if self.createNodeFromTemplateId(template_id, QtCore.QPoint(x, y)) is False:
|
||||
event.ignore()
|
||||
break
|
||||
@@ -861,19 +863,19 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
bring_to_front_action.triggered.connect(self.bringToFrontSlot)
|
||||
menu.addAction(bring_to_front_action)
|
||||
|
||||
if True in list(map(lambda item: isinstance(item, NodeItem) and hasattr(item.node(), "configFiles"), items)):
|
||||
if True in list(map(lambda item: isinstance(item, NodeItem) and bool(item.node().configFiles()), items)):
|
||||
import_config_action = QtWidgets.QAction("Import config", menu)
|
||||
import_config_action.setIcon(get_icon("import.svg"))
|
||||
import_config_action.triggered.connect(self.importConfigActionSlot)
|
||||
menu.addAction(import_config_action)
|
||||
|
||||
if True in list(map(lambda item: isinstance(item, NodeItem) and hasattr(item.node(), "configFiles"), items)):
|
||||
if True in list(map(lambda item: isinstance(item, NodeItem) and bool(item.node().configFiles()), items)):
|
||||
export_config_action = QtWidgets.QAction("Export config", menu)
|
||||
export_config_action.setIcon(get_icon("export.svg"))
|
||||
export_config_action.triggered.connect(self.exportConfigActionSlot)
|
||||
menu.addAction(export_config_action)
|
||||
|
||||
if True in list(map(lambda item: isinstance(item, NodeItem) and hasattr(item.node(), "configFiles"), items)):
|
||||
if True in list(map(lambda item: isinstance(item, NodeItem) and bool(item.node().configTextFiles()), items)):
|
||||
export_config_action = QtWidgets.QAction("Edit config", menu)
|
||||
export_config_action.setIcon(get_icon("edit.svg"))
|
||||
export_config_action.triggered.connect(self.editConfigActionSlot)
|
||||
@@ -1226,7 +1228,7 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
|
||||
items = []
|
||||
for item in self.scene().selectedItems():
|
||||
if isinstance(item, NodeItem) and hasattr(item.node(), "configFiles") and item.node().initialized():
|
||||
if isinstance(item, NodeItem) and item.node().configFiles() and item.node().initialized():
|
||||
items.append(item)
|
||||
|
||||
if not items:
|
||||
@@ -1257,17 +1259,17 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
|
||||
items = []
|
||||
for item in self.scene().selectedItems():
|
||||
if isinstance(item, NodeItem) and hasattr(item.node(), "configFiles") and item.node().initialized():
|
||||
if isinstance(item, NodeItem) and item.node().configTextFiles() and item.node().initialized():
|
||||
items.append(item)
|
||||
|
||||
if not items:
|
||||
return
|
||||
|
||||
for item in items:
|
||||
if len(item.node().configFiles()) == 1:
|
||||
config_file = item.node().configFiles()[0]
|
||||
if len(item.node().configTextFiles()) == 1:
|
||||
config_file = item.node().configTextFiles()[0]
|
||||
else:
|
||||
config_file, ok = QtWidgets.QInputDialog.getItem(self, "Edit file", "File to edit?", item.node().configFiles(), 0, False)
|
||||
config_file, ok = QtWidgets.QInputDialog.getItem(self, "Edit file", "File to edit?", item.node().configTextFiles(), 0, False)
|
||||
if not ok:
|
||||
continue
|
||||
dialog = FileEditorDialog(item.node(), config_file, parent=self)
|
||||
@@ -1282,7 +1284,7 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
|
||||
items = []
|
||||
for item in self.scene().selectedItems():
|
||||
if isinstance(item, NodeItem) and hasattr(item.node(), "configFiles") and item.node().initialized():
|
||||
if isinstance(item, NodeItem) and item.node().configFiles() and item.node().initialized():
|
||||
items.append(item)
|
||||
|
||||
if not items:
|
||||
@@ -1409,7 +1411,15 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
type = "rect"
|
||||
else:
|
||||
type = "image"
|
||||
self.createDrawingItem(type, item.pos().x() + 20, item.pos().y() + 20, item.zValue(), rotation=item.rotation(), svg=item.toSvg())
|
||||
|
||||
self.createDrawingItem(
|
||||
type,
|
||||
int(item.pos().x()) + 20,
|
||||
int(item.pos().y()) + 20,
|
||||
item.zValue(),
|
||||
rotation=item.rotation(),
|
||||
svg=item.toSvg()
|
||||
)
|
||||
elif isinstance(item, NodeItem):
|
||||
item.node().duplicate(item.pos().x() + 20, item.pos().y() + 20, item.zValue())
|
||||
|
||||
@@ -1661,11 +1671,11 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
|
||||
x = left
|
||||
while x < rect.right():
|
||||
painter.drawLine(x, rect.top(), x, rect.bottom())
|
||||
painter.drawLine(x, int(rect.top()), x, int(rect.bottom()))
|
||||
x += grid
|
||||
y = top
|
||||
while y < rect.bottom():
|
||||
painter.drawLine(rect.left(), y, rect.right(), y)
|
||||
painter.drawLine(int(rect.left()), y, int(rect.right()), y)
|
||||
y += grid
|
||||
painter.restore()
|
||||
|
||||
|
||||
@@ -18,18 +18,15 @@
|
||||
from .qt import sip
|
||||
import json
|
||||
import copy
|
||||
import http
|
||||
import uuid
|
||||
import pathlib
|
||||
import base64
|
||||
import datetime
|
||||
import ipaddress
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
|
||||
|
||||
from .version import __version__, __version_info__
|
||||
from .qt import QtCore, QtNetwork, qpartial, sip_is_deleted
|
||||
from .qt import QtCore, QtNetwork, QtWidgets, qpartial, sip_is_deleted
|
||||
from .utils import parse_version
|
||||
|
||||
import logging
|
||||
@@ -79,6 +76,18 @@ class HTTPClient(QtCore.QObject):
|
||||
self._shutdown = False # Shutdown in progress
|
||||
self._accept_insecure_certificate = settings.get("accept_insecure_certificate", None)
|
||||
|
||||
# Add custom CA
|
||||
# ssl_config = QtNetwork.QSslConfiguration.defaultConfiguration()
|
||||
# if ssl_config.addCaCertificates("/path/to/rootCA.crt"):
|
||||
# log.debug("CA certificate added")
|
||||
# QtNetwork.QSslConfiguration.setDefaultConfiguration(ssl_config)
|
||||
|
||||
if self._protocol == "https":
|
||||
if not QtNetwork.QSslSocket.supportsSsl():
|
||||
log.error("SSL is not supported")
|
||||
else:
|
||||
log.debug(f"SSL is supported, version: {QtNetwork.QSslSocket().sslLibraryBuildVersionString()}")
|
||||
|
||||
# In order to detect computer hibernation we detect the date of the last
|
||||
# query and disconnect if time is too long between two query
|
||||
self._last_query_timestamp = None
|
||||
@@ -93,6 +102,12 @@ class HTTPClient(QtCore.QObject):
|
||||
# List of query waiting for the connection
|
||||
self._query_waiting_connections = []
|
||||
|
||||
# To catch SSL errors
|
||||
self._network_manager.sslErrors.connect(self._sslErrorsSlot)
|
||||
|
||||
# Store SSL error exceptions
|
||||
self._ssl_exceptions = {}
|
||||
|
||||
def setMaxTimeDifferenceBetweenQueries(self, value):
|
||||
self._max_time_difference_between_queries = value
|
||||
|
||||
@@ -470,7 +485,14 @@ class HTTPClient(QtCore.QObject):
|
||||
"""
|
||||
host = self._getHostForQuery()
|
||||
request = websocket.request()
|
||||
ws_url = "ws://{host}:{port}{prefix}{path}".format(host=host, port=self._port, path=path, prefix=prefix)
|
||||
ws_protocol = "ws"
|
||||
if self._protocol == "https":
|
||||
ws_protocol = "wss"
|
||||
ws_url = "{protocol}://{host}:{port}{prefix}{path}".format(protocol=ws_protocol,
|
||||
host=host,
|
||||
port=self._port,
|
||||
path=path,
|
||||
prefix=prefix)
|
||||
log.debug("Connecting to WebSocket endpoint: {}".format(ws_url))
|
||||
request.setUrl(QtCore.QUrl(ws_url))
|
||||
self._addAuth(request)
|
||||
@@ -532,14 +554,13 @@ class HTTPClient(QtCore.QObject):
|
||||
query_string = self._paramsToQueryString(params)
|
||||
|
||||
log.debug("{method} {protocol}://{host}:{port}{prefix}{path} {body}{query_string}".format(method=method, protocol=self._protocol, host=host, port=self._port, path=path, body=body, prefix=prefix, query_string=query_string))
|
||||
url = QtCore.QUrl("{protocol}://{host}:{port}{prefix}{path}{query_string}".format(protocol=self._protocol, host=host, port=self._port, path=path, prefix=prefix, query_string=query_string))
|
||||
|
||||
if self._user:
|
||||
url = QtCore.QUrl("{protocol}://{user}@{host}:{port}{prefix}{path}{query_string}".format(protocol=self._protocol, user=self._user, host=host, port=self._port, path=path, prefix=prefix, query_string=query_string))
|
||||
else:
|
||||
url = QtCore.QUrl("{protocol}://{host}:{port}{prefix}{path}{query_string}".format(protocol=self._protocol, host=host, port=self._port, path=path, prefix=prefix, query_string=query_string))
|
||||
url.setUserName(self._user)
|
||||
|
||||
request = self._request(url)
|
||||
|
||||
request = self._addAuth(request)
|
||||
|
||||
request.setRawHeader(b"User-Agent", "GNS3 QT Client v{version}".format(version=__version__).encode())
|
||||
|
||||
# By default QT doesn't support GET with body even if it's in the RFC that's why we need to use sendCustomRequest
|
||||
@@ -737,10 +758,10 @@ class HTTPClient(QtCore.QObject):
|
||||
host = self._getHostForQuery()
|
||||
|
||||
log.debug("{method} {protocol}://{host}:{port}{prefix}{endpoint}".format(method=method, protocol=self._protocol, host=host, port=self._port, prefix=prefix, endpoint=endpoint))
|
||||
url = QtCore.QUrl("{protocol}://{host}:{port}{prefix}{endpoint}".format(protocol=self._protocol, host=host, port=self._port, prefix=prefix, endpoint=endpoint))
|
||||
|
||||
if self._user:
|
||||
url = QtCore.QUrl("{protocol}://{user}@{host}:{port}{prefix}{endpoint}".format(protocol=self._protocol, user=self._user, host=host, port=self._port, prefix=prefix, endpoint=endpoint))
|
||||
else:
|
||||
url = QtCore.QUrl("{protocol}://{host}:{port}{prefix}{endpoint}".format(protocol=self._protocol, host=host, port=self._port, prefix=prefix, endpoint=endpoint))
|
||||
url.setUserName(self._user)
|
||||
|
||||
request = self._request(url)
|
||||
request = self._addAuth(request)
|
||||
@@ -776,6 +797,55 @@ class HTTPClient(QtCore.QObject):
|
||||
return status, json_data
|
||||
return status, None
|
||||
|
||||
def _sslErrorsSlot(self, response, ssl_errors):
|
||||
|
||||
self.handleSslError(response, ssl_errors)
|
||||
|
||||
def handleSslError(self, response, ssl_errors):
|
||||
|
||||
if self._accept_insecure_certificate:
|
||||
response.ignoreSslErrors()
|
||||
return
|
||||
|
||||
url = response.request().url()
|
||||
host_port_key = f"{url.host()}:{url.port()}"
|
||||
|
||||
# get the certificate digest
|
||||
ssl_config = response.sslConfiguration()
|
||||
peer_cert = ssl_config.peerCertificate()
|
||||
digest = peer_cert.digest()
|
||||
|
||||
if host_port_key in self._ssl_exceptions:
|
||||
|
||||
if self._ssl_exceptions[host_port_key] == digest:
|
||||
response.ignoreSslErrors()
|
||||
return
|
||||
|
||||
from gns3.main_window import MainWindow
|
||||
main_window = MainWindow.instance()
|
||||
|
||||
msgbox = QtWidgets.QMessageBox(main_window)
|
||||
msgbox.setWindowTitle("SSL error detected")
|
||||
msgbox.setText(f"This server could not prove that it is {url.host()}:{url.port()}. Please carefully examine the certificate to make sure the server can be trusted.")
|
||||
msgbox.setInformativeText(f"{ssl_errors[0].errorString()}")
|
||||
msgbox.setDetailedText(peer_cert.toText())
|
||||
msgbox.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||
connect_button = QtWidgets.QPushButton(f"&Connect to {url.host()}:{url.port()}", msgbox)
|
||||
msgbox.addButton(connect_button, QtWidgets.QMessageBox.YesRole)
|
||||
abort_button = QtWidgets.QPushButton("&Abort", msgbox)
|
||||
msgbox.addButton(abort_button, QtWidgets.QMessageBox.RejectRole)
|
||||
msgbox.setDefaultButton(abort_button)
|
||||
msgbox.setIcon(QtWidgets.QMessageBox.Critical)
|
||||
msgbox.exec_()
|
||||
|
||||
if msgbox.clickedButton() == connect_button:
|
||||
self._ssl_exceptions[host_port_key] = digest
|
||||
response.ignoreSslErrors()
|
||||
else:
|
||||
for error in ssl_errors:
|
||||
log.error(f"SSL error detected: {error.errorString()}")
|
||||
main_window.close()
|
||||
|
||||
@classmethod
|
||||
def fromUrl(cls, url, network_manager=None, base_settings=None):
|
||||
"""
|
||||
|
||||
@@ -246,7 +246,7 @@ class DrawingItem:
|
||||
center = self.mapFromItem(self, brect.width() / 2.0, brect.height() / 2.0)
|
||||
painter.setBrush(QtCore.Qt.red)
|
||||
painter.setPen(QtCore.Qt.red)
|
||||
painter.drawRect((brect.width() / 2.0) - 10, (brect.height() / 2.0) - 10, 20, 20)
|
||||
painter.drawRect(QtCore.QRectF((brect.width() / 2.0) - 10, (brect.height() / 2.0) - 10, 20, 20))
|
||||
painter.setPen(QtCore.Qt.black)
|
||||
zval = str(int(self.zValue()))
|
||||
painter.drawText(QtCore.QPointF(center.x() - 4, center.y() + 4), zval)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2019 Pekka Helenius
|
||||
# Copyright (C) 2014 GNS3 Technologies Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -51,10 +52,16 @@ class EthernetLinkItem(LinkItem):
|
||||
|
||||
LinkItem.adjust(self)
|
||||
|
||||
if self._hovered:
|
||||
self.setPen(QtGui.QPen(QtCore.Qt.red, self._pen_width + 1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
|
||||
else:
|
||||
self.setPen(QtGui.QPen(QtCore.Qt.black, self._pen_width, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
|
||||
try:
|
||||
if self._hovered:
|
||||
self.setPen(QtGui.QPen(QtCore.Qt.red, self._link._link_style["width"] + 1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
|
||||
else:
|
||||
self.setPen(QtGui.QPen(QtGui.QColor(self._link._link_style["color"]), self._link._link_style["width"], self._link._link_style["type"], QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
|
||||
except:
|
||||
if self._hovered:
|
||||
self.setPen(QtGui.QPen(QtCore.Qt.red, self._pen_width + 1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
|
||||
else:
|
||||
self.setPen(QtGui.QPen(QtGui.QColor("#000000"), self._pen_width, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
|
||||
|
||||
# draw a line between nodes
|
||||
path = QtGui.QPainterPath(self.source)
|
||||
@@ -152,7 +159,7 @@ class EthernetLinkItem(LinkItem):
|
||||
else:
|
||||
source_port_label.hide()
|
||||
|
||||
if self._settings["draw_link_status_points"]:
|
||||
if self._settings["draw_link_status_points"] and self.pen().style() != QtCore.Qt.NoPen:
|
||||
painter.drawPoint(point1)
|
||||
|
||||
if self._link.suspended() or self._destination_port.status() == Port.suspended:
|
||||
@@ -195,7 +202,7 @@ class EthernetLinkItem(LinkItem):
|
||||
else:
|
||||
destination_port_label.hide()
|
||||
|
||||
if self._settings["draw_link_status_points"]:
|
||||
if self._settings["draw_link_status_points"] and self.pen().style() != QtCore.Qt.NoPen:
|
||||
painter.drawPoint(point2)
|
||||
|
||||
self._drawSymbol()
|
||||
|
||||
@@ -165,7 +165,7 @@ class LabelItem(QtWidgets.QGraphicsTextItem):
|
||||
center = self.mapFromItem(self, brect.width() / 2.0, brect.height() / 2.0)
|
||||
painter.setBrush(QtCore.Qt.red)
|
||||
painter.setPen(QtCore.Qt.red)
|
||||
painter.drawRect((brect.width() / 2.0) - 10, (brect.height() / 2.0) - 10, 20, 20)
|
||||
painter.drawRect(QtCore.QRectF((brect.width() / 2.0) - 10, (brect.height() / 2.0) - 10, 20, 20))
|
||||
painter.setPen(QtCore.Qt.black)
|
||||
zval = str(int(self.zValue()))
|
||||
painter.drawText(QtCore.QPointF(center.x(), center.y()), zval)
|
||||
|
||||
@@ -25,6 +25,7 @@ from ..qt import QtCore, QtGui, QtWidgets, QtSvg, qslot, sip_is_deleted
|
||||
|
||||
from ..packet_capture import PacketCapture
|
||||
from ..dialogs.filter_dialog import FilterDialog
|
||||
from ..dialogs.style_editor_dialog_link import StyleEditorDialogLink
|
||||
from ..utils.get_icon import get_icon
|
||||
|
||||
|
||||
@@ -137,6 +138,21 @@ class LinkItem(QtWidgets.QGraphicsPathItem):
|
||||
def _suspendActionSlot(self, *args):
|
||||
self._link.toggleSuspend()
|
||||
|
||||
@qslot
|
||||
def _styleActionSlot(self, *args):
|
||||
style_dialog = StyleEditorDialogLink(self, self._main_window)
|
||||
style_dialog.show()
|
||||
style_dialog.exec_()
|
||||
|
||||
def setLinkStyle(self, link_style):
|
||||
self._link._link_style["color"] = link_style["color"]
|
||||
self._link._link_style["width"] = link_style["width"]
|
||||
self._link._link_style["type"] = link_style["type"]
|
||||
|
||||
# This refers to functions in link.py!
|
||||
self._link.setLinkStyle(link_style)
|
||||
self._link.update()
|
||||
|
||||
def delete(self):
|
||||
"""
|
||||
Delete this link
|
||||
@@ -266,6 +282,12 @@ class LinkItem(QtWidgets.QGraphicsPathItem):
|
||||
resume_action.triggered.connect(self._suspendActionSlot)
|
||||
menu.addAction(resume_action)
|
||||
|
||||
# style
|
||||
style_action = QtWidgets.QAction("Style", menu)
|
||||
style_action.setIcon(get_icon("node_conception.svg"))
|
||||
style_action.triggered.connect(self._styleActionSlot)
|
||||
menu.addAction(style_action)
|
||||
|
||||
# delete
|
||||
delete_action = QtWidgets.QAction("Delete", menu)
|
||||
delete_action.setIcon(get_icon('delete.svg'))
|
||||
|
||||
@@ -388,7 +388,7 @@ class NodeItem(QtSvg.QGraphicsSvgItem):
|
||||
else:
|
||||
self._node_label.setPos(label_data["x"], label_data["y"])
|
||||
|
||||
def connectToPort(self, unavailable_ports=[]):
|
||||
def connectToPort(self, pos, unavailable_ports=[]):
|
||||
"""
|
||||
Shows a contextual menu for the user to choose port or auto-select one.
|
||||
|
||||
@@ -436,7 +436,10 @@ class NodeItem(QtSvg.QGraphicsSvgItem):
|
||||
menu.addAction(QtGui.QIcon(':/icons/led_green.svg'), port_object.name())
|
||||
|
||||
menu.triggered.connect(self.selectedPortSlot)
|
||||
menu.exec_(QtGui.QCursor.pos())
|
||||
# add some delay before showing the menu
|
||||
# https://github.com/GNS3/gns3-gui/issues/3169
|
||||
QtCore.QThread.msleep(100)
|
||||
menu.exec_(pos)
|
||||
return self._selected_port
|
||||
|
||||
def selectedPortSlot(self, action):
|
||||
@@ -504,7 +507,7 @@ class NodeItem(QtSvg.QGraphicsSvgItem):
|
||||
center = self.mapFromItem(self, brect.width() / 2.0, brect.height() / 2.0)
|
||||
painter.setBrush(QtCore.Qt.red)
|
||||
painter.setPen(QtCore.Qt.red)
|
||||
painter.drawRect((brect.width() / 2.0) - 10, (brect.height() / 2.0) - 10, 20, 20)
|
||||
painter.drawRect(QtCore.QRectF((brect.width() / 2.0) - 10, (brect.height() / 2.0) - 10, 20, 20))
|
||||
painter.setPen(QtCore.Qt.black)
|
||||
if self.show_layer:
|
||||
text = str(int(self.zValue())) # Z value
|
||||
|
||||
@@ -50,10 +50,16 @@ class SerialLinkItem(LinkItem):
|
||||
|
||||
LinkItem.adjust(self)
|
||||
|
||||
if self._hovered:
|
||||
self.setPen(QtGui.QPen(QtCore.Qt.red, self._pen_width + 1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
|
||||
else:
|
||||
self.setPen(QtGui.QPen(QtCore.Qt.darkRed, self._pen_width, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
|
||||
try:
|
||||
if self._hovered:
|
||||
self.setPen(QtGui.QPen(QtCore.Qt.red, self._link._link_style["width"] + 1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
|
||||
else:
|
||||
self.setPen(QtGui.QPen(QtGui.QColor(self._link._link_style["color"]), self._link._link_style["width"], self._link._link_style["type"], QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
|
||||
except:
|
||||
if self._hovered:
|
||||
self.setPen(QtGui.QPen(QtCore.Qt.red, self._pen_width + 1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
|
||||
else:
|
||||
self.setPen(QtGui.QPen(QtCore.Qt.darkRed, self._pen_width, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
|
||||
|
||||
# get source to destination angle
|
||||
vector_angle = math.atan2(self.dy, self.dx)
|
||||
@@ -141,7 +147,7 @@ class SerialLinkItem(LinkItem):
|
||||
else:
|
||||
source_port_label.hide()
|
||||
|
||||
if self._settings["draw_link_status_points"]:
|
||||
if self._settings["draw_link_status_points"] and self.pen().style() != QtCore.Qt.NoPen:
|
||||
painter.drawPoint(self.source_point)
|
||||
|
||||
# destination point color
|
||||
@@ -173,7 +179,7 @@ class SerialLinkItem(LinkItem):
|
||||
else:
|
||||
destination_port_label.hide()
|
||||
|
||||
if self._settings["draw_link_status_points"]:
|
||||
if self._settings["draw_link_status_points"] and self.pen().style() != QtCore.Qt.NoPen:
|
||||
painter.drawPoint(self.destination_point)
|
||||
|
||||
self._drawSymbol()
|
||||
|
||||
39
gns3/link.py
39
gns3/link.py
@@ -19,7 +19,6 @@
|
||||
Manages and stores everything needed for a connection between 2 devices.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
from .qt import sip
|
||||
import uuid
|
||||
@@ -79,6 +78,7 @@ class Link(QtCore.QObject):
|
||||
self._deleting = False
|
||||
self._capture_file_path = None
|
||||
self._capture_file = None
|
||||
self._response_stream = None
|
||||
self._capture_compute_id = None
|
||||
self._initialized = False
|
||||
self._filters = {}
|
||||
@@ -90,9 +90,7 @@ class Link(QtCore.QObject):
|
||||
self._creator = False
|
||||
|
||||
self._nodes = []
|
||||
|
||||
self._source_node.addLink(self)
|
||||
self._destination_node.addLink(self)
|
||||
self._link_style = {}
|
||||
|
||||
body = self._prepareParams()
|
||||
if self._link_id:
|
||||
@@ -119,19 +117,23 @@ class Link(QtCore.QObject):
|
||||
else:
|
||||
self._capture_file = QtCore.QFile(self._capture_file_path)
|
||||
self._capture_file.open(QtCore.QFile.WriteOnly)
|
||||
Controller.instance().get("/projects/{project_id}/links/{link_id}/pcap".format(project_id=self.project().id(), link_id=self._link_id),
|
||||
None,
|
||||
showProgress=False,
|
||||
downloadProgressCallback=self._downloadPcapProgress,
|
||||
ignoreErrors=True, # If something is wrong avoid disconnect us from server
|
||||
timeout=None)
|
||||
log.debug("Capturing packets to '{}'".format(self._capture_file_path))
|
||||
self._response_stream = Controller.instance().get("/projects/{project_id}/links/{link_id}/pcap".format(project_id=self.project().id(), link_id=self._link_id),
|
||||
None,
|
||||
showProgress=False,
|
||||
downloadProgressCallback=self._downloadPcapProgress,
|
||||
ignoreErrors=True, # If something is wrong avoid disconnect us from server
|
||||
timeout=None)
|
||||
log.debug("Has successfully started capturing packets on link {} to '{}'".format(self._link_id, self._capture_file_path))
|
||||
else:
|
||||
self._response_stream = None
|
||||
|
||||
if "nodes" in result:
|
||||
self._nodes = result["nodes"]
|
||||
self._updateLabels()
|
||||
if "filters" in result:
|
||||
self._filters = result["filters"]
|
||||
if "link_style" in result:
|
||||
self._link_style = result["link_style"]
|
||||
if "suspend" in result:
|
||||
self._suspend = result["suspend"]
|
||||
self.updated_link_signal.emit(self._id)
|
||||
@@ -214,6 +216,7 @@ class Link(QtCore.QObject):
|
||||
}
|
||||
],
|
||||
"filters": self._filters,
|
||||
"link_style": self._link_style,
|
||||
"suspend": self._suspend
|
||||
}
|
||||
if self._source_port.label():
|
||||
@@ -356,9 +359,8 @@ class Link(QtCore.QObject):
|
||||
|
||||
def _startCaptureCallback(self, result, error=False, **kwargs):
|
||||
if error:
|
||||
log.error("Error while starting capture on link: {}".format(result["message"]))
|
||||
log.error("Error while starting capture on link {}: {}".format(self._link_id, result["message"]))
|
||||
return
|
||||
#self._parseResponse(result)
|
||||
|
||||
def _downloadPcapProgress(self, content, server=None, context={}, **kwargs):
|
||||
"""
|
||||
@@ -386,11 +388,12 @@ class Link(QtCore.QObject):
|
||||
link_id=self._link_id),
|
||||
self._stopCaptureCallback)
|
||||
|
||||
|
||||
def _stopCaptureCallback(self, result, error=False, **kwargs):
|
||||
if error:
|
||||
log.error("Error while stopping capture on link: {}".format(result["message"]))
|
||||
log.error("Error while stopping capture on link {}: {}".format(self._link_id, result["message"]))
|
||||
return
|
||||
#self._parseResponse(result)
|
||||
log.debug("Has successfully stopped capturing packets on link {}".format(self._link_id))
|
||||
|
||||
def get(self, path, callback, **kwargs):
|
||||
"""
|
||||
@@ -468,3 +471,9 @@ class Link(QtCore.QObject):
|
||||
:params filters: List of filters
|
||||
"""
|
||||
self._filters = filters
|
||||
|
||||
def setLinkStyle(self, link_style):
|
||||
"""
|
||||
:params _link_style: Set link style attributes
|
||||
"""
|
||||
self._link_style = link_style
|
||||
|
||||
@@ -118,6 +118,9 @@ def main():
|
||||
# an extra argument starting with -psn_. We filter it
|
||||
if sys.platform.startswith("darwin"):
|
||||
sys.argv = [a for a in sys.argv if not a.startswith("-psn_")]
|
||||
if parse_version(QtCore.QT_VERSION_STR) < parse_version("5.15.2"):
|
||||
# Fixes issue on macOS Big Sur: https://github.com/GNS3/gns3-gui/issues/3037
|
||||
os.environ["QT_MAC_WANTS_LAYER"] = "1"
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("project", help="load a GNS3 project (.gns3)", metavar="path", nargs="?")
|
||||
|
||||
@@ -86,6 +86,23 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
self.setupUi(self)
|
||||
self.setUnifiedTitleAndToolBarOnMac(True)
|
||||
|
||||
# These widgets will be disabled when no project is loaded
|
||||
self.disableWhenNoProjectWidgets = [
|
||||
self.uiGraphicsView,
|
||||
self.uiAnnotateMenu,
|
||||
self.uiAnnotationToolBar,
|
||||
self.uiControlToolBar,
|
||||
self.uiControlMenu,
|
||||
self.uiSaveProjectAsAction,
|
||||
self.uiExportProjectAction,
|
||||
self.uiScreenshotAction,
|
||||
self.uiSnapshotAction,
|
||||
self.uiEditProjectAction,
|
||||
self.uiDeleteProjectAction,
|
||||
self.uiImportExportConfigsAction,
|
||||
self.uiLockAllAction
|
||||
]
|
||||
|
||||
self._notif_dialog = NotifDialog(self)
|
||||
# Setup logger
|
||||
logging.getLogger().addHandler(NotifDialogHandler(self._notif_dialog))
|
||||
@@ -178,28 +195,6 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
|
||||
self.setWindowTitle("[*] GNS3")
|
||||
|
||||
# This widgets will be disable when you have no project loaded
|
||||
self.disableWhenNoProjectWidgets = [
|
||||
self.uiGraphicsView,
|
||||
self.uiAnnotateMenu,
|
||||
self.uiAnnotationToolBar,
|
||||
self.uiControlToolBar,
|
||||
self.uiControlMenu,
|
||||
self.uiSaveProjectAsAction,
|
||||
self.uiExportProjectAction,
|
||||
self.uiScreenshotAction,
|
||||
self.uiSnapshotAction,
|
||||
self.uiEditProjectAction,
|
||||
self.uiDeleteProjectAction,
|
||||
self.uiImportExportConfigsAction,
|
||||
self.uiLockAllAction
|
||||
]
|
||||
|
||||
# This widgets are not enabled if it's a remote controller (no access to the local file system)
|
||||
self.disableWhenRemoteContollerWidgets = [
|
||||
# self.uiImportExportConfigsAction
|
||||
]
|
||||
|
||||
# load initial stuff once the event loop isn't busy
|
||||
self.run_later(0, self.startupLoading)
|
||||
|
||||
@@ -239,6 +234,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
self.uiShowGridAction.triggered.connect(self._showGridActionSlot)
|
||||
self.uiSnapToGridAction.triggered.connect(self._snapToGridActionSlot)
|
||||
self.uiLockAllAction.triggered.connect(self._lockActionSlot)
|
||||
self.uiResetDocksAction.triggered.connect(self._resetDocksSlot)
|
||||
|
||||
# tool menu connections
|
||||
self.uiWebUIAction.triggered.connect(self._openWebInterfaceActionSlot)
|
||||
@@ -371,6 +367,16 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
item.updateNode()
|
||||
item.update()
|
||||
|
||||
def _resetDocksSlot(self):
|
||||
"""
|
||||
Reset the dock widgets.
|
||||
"""
|
||||
|
||||
self.uiTopologySummaryDockWidget.setFloating(False)
|
||||
self.uiComputeSummaryDockWidget.setFloating(False)
|
||||
self.uiConsoleDockWidget.setFloating(False)
|
||||
self.uiNodesDockWidget.setFloating(False)
|
||||
|
||||
def analyticsClient(self):
|
||||
"""
|
||||
Return the analytics client
|
||||
@@ -540,8 +546,6 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
"""
|
||||
Refresh widgets that should be visible or not
|
||||
"""
|
||||
for widget in self.disableWhenRemoteContollerWidgets:
|
||||
widget.setVisible(not Controller.instance().isRemote())
|
||||
|
||||
# No projects
|
||||
if Topology.instance().project() is None:
|
||||
@@ -810,6 +814,13 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
"""
|
||||
Slot called when starting all the nodes.
|
||||
"""
|
||||
|
||||
reply = QtWidgets.QMessageBox.question(self, "Confirm Start All", "Are you sure you want to start all devices?",
|
||||
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
|
||||
|
||||
if reply == QtWidgets.QMessageBox.No:
|
||||
return
|
||||
|
||||
project = Topology.instance().project()
|
||||
if project is not None:
|
||||
project.start_all_nodes()
|
||||
@@ -819,6 +830,12 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
Slot called when suspending all the nodes.
|
||||
"""
|
||||
|
||||
reply = QtWidgets.QMessageBox.question(self, "Confirm Suspend All", "Are you sure you want to suspend all devices?",
|
||||
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
|
||||
|
||||
if reply == QtWidgets.QMessageBox.No:
|
||||
return
|
||||
|
||||
project = Topology.instance().project()
|
||||
if project is not None:
|
||||
project.suspend_all_nodes()
|
||||
@@ -828,6 +845,12 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
Slot called when stopping all the nodes.
|
||||
"""
|
||||
|
||||
reply = QtWidgets.QMessageBox.question(self, "Confirm Stop All", "Are you sure you want to stop all devices?",
|
||||
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
|
||||
|
||||
if reply == QtWidgets.QMessageBox.No:
|
||||
return
|
||||
|
||||
project = Topology.instance().project()
|
||||
if project is not None:
|
||||
project.stop_all_nodes()
|
||||
@@ -837,6 +860,12 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
Slot called when reloading all the nodes.
|
||||
"""
|
||||
|
||||
reply = QtWidgets.QMessageBox.question(self, "Confirm Reload All", "Are you sure you want to reload all devices?",
|
||||
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
|
||||
|
||||
if reply == QtWidgets.QMessageBox.No:
|
||||
return
|
||||
|
||||
project = Topology.instance().project()
|
||||
if project is not None:
|
||||
project.reload_all_nodes()
|
||||
|
||||
@@ -52,6 +52,7 @@ class CloudPreferencesPage(QtWidgets.QWidget, Ui_CloudPreferencesPageWidget):
|
||||
self.uiEditCloudNodePushButton.clicked.connect(self._editCloudNodeSlot)
|
||||
self.uiDeleteCloudNodePushButton.clicked.connect(self._deleteCloudNodeSlot)
|
||||
self.uiCloudNodesTreeWidget.itemSelectionChanged.connect(self._cloudNodeChangedSlot)
|
||||
self.uiCloudNodesTreeWidget.itemDoubleClicked.connect(self._editCloudNodeSlot)
|
||||
|
||||
def _createSectionItem(self, name):
|
||||
"""
|
||||
|
||||
@@ -53,6 +53,8 @@ class EthernetHubPreferencesPage(QtWidgets.QWidget, Ui_EthernetHubPreferencesPag
|
||||
self.uiEditEthernetHubPushButton.clicked.connect(self._editEthernetHubSlot)
|
||||
self.uiDeleteEthernetHubPushButton.clicked.connect(self._deleteEthernetHubSlot)
|
||||
self.uiEthernetHubsTreeWidget.itemSelectionChanged.connect(self._ethernetHubChangedSlot)
|
||||
self.uiEthernetHubsTreeWidget.itemDoubleClicked.connect(self._editEthernetHubSlot)
|
||||
|
||||
|
||||
def _createSectionItem(self, name):
|
||||
"""
|
||||
|
||||
@@ -53,6 +53,7 @@ class EthernetSwitchPreferencesPage(QtWidgets.QWidget, Ui_EthernetSwitchPreferen
|
||||
self.uiEditEthernetSwitchPushButton.clicked.connect(self._editEthernetSwitchSlot)
|
||||
self.uiDeleteEthernetSwitchPushButton.clicked.connect(self._deleteEthernetSwitchSlot)
|
||||
self.uiEthernetSwitchesTreeWidget.itemSelectionChanged.connect(self._ethernetSwitchChangedSlot)
|
||||
self.uiEthernetSwitchesTreeWidget.itemDoubleClicked.connect(self._editEthernetSwitchSlot)
|
||||
|
||||
def _createSectionItem(self, name):
|
||||
"""
|
||||
|
||||
@@ -52,6 +52,7 @@ class DockerVMPreferencesPage(QtWidgets.QWidget, Ui_DockerVMPreferencesPageWidge
|
||||
self.uiEditDockerVMPushButton.clicked.connect(self._dockerImageEditSlot)
|
||||
self.uiDeleteDockerVMPushButton.clicked.connect(self._dockerImageDeleteSlot)
|
||||
self.uiDockerVMsTreeWidget.itemSelectionChanged.connect(self._dockerImageChangedSlot)
|
||||
self.uiDockerVMsTreeWidget.itemDoubleClicked.connect(self._dockerImageEditSlot)
|
||||
|
||||
def _createSectionItem(self, name):
|
||||
"""
|
||||
|
||||
@@ -70,6 +70,7 @@ class IOSRouterPreferencesPage(QtWidgets.QWidget, Ui_IOSRouterPreferencesPageWid
|
||||
self.uiDeleteIOSRouterPushButton.clicked.connect(self._iosRouterDeleteSlot)
|
||||
self.uiIOSRoutersTreeWidget.itemSelectionChanged.connect(self._iosRouterChangedSlot)
|
||||
self.uiDecompressIOSPushButton.clicked.connect(self._decompressIOSSlot)
|
||||
self.uiIOSRoutersTreeWidget.itemDoubleClicked.connect(self._iosRouterEditSlot)
|
||||
|
||||
def _iosRouterChangedSlot(self):
|
||||
"""
|
||||
|
||||
@@ -59,6 +59,7 @@ class IOUDevicePreferencesPage(QtWidgets.QWidget, Ui_IOUDevicePreferencesPageWid
|
||||
self.uiEditIOUDevicePushButton.clicked.connect(self._iouDeviceEditSlot)
|
||||
self.uiDeleteIOUDevicePushButton.clicked.connect(self._iouDeviceDeleteSlot)
|
||||
self.uiIOUDevicesTreeWidget.itemSelectionChanged.connect(self._iouDeviceChangedSlot)
|
||||
self.uiIOUDevicesTreeWidget.itemDoubleClicked.connect(self._iouDeviceEditSlot)
|
||||
|
||||
def _createSectionItem(self, name):
|
||||
"""
|
||||
|
||||
@@ -164,7 +164,7 @@ class QemuVMWizard(VMWithImagesWizard, Ui_QemuVMWizard):
|
||||
settings["initrd"] = self.uiInitrdImageLineEdit.text()
|
||||
settings["kernel_image"] = self.uiKernelImageLineEdit.text()
|
||||
settings["kernel_command_line"] = "ide_generic.probe_mask=0x01 ide_core.chs=0.0:980,16,32 auto nousb console=ttyS0,9600 bigphysarea=65536 ide1=noprobe no-hlt -net nic"
|
||||
settings["options"] = "-no-kvm -icount auto"
|
||||
settings["options"] = "-machine accel=tcg -icount auto"
|
||||
if not sys.platform.startswith("darwin"):
|
||||
settings["cpu_throttling"] = 80 # limit to 80% CPU usage
|
||||
settings["process_priority"] = "low"
|
||||
@@ -177,8 +177,6 @@ class QemuVMWizard(VMWithImagesWizard, Ui_QemuVMWizard):
|
||||
(sys.platform.startswith("darwin") and "GNS3.app" in qemu_path):
|
||||
settings["options"] += " -vga none -vnc none"
|
||||
settings["legacy_networking"] = True
|
||||
else:
|
||||
settings["options"] += " -nographic"
|
||||
settings["options"] = settings["options"].strip()
|
||||
|
||||
return settings
|
||||
|
||||
@@ -90,6 +90,7 @@ class QemuVMConfigurationPage(QtWidgets.QWidget, Ui_QemuVMConfigPageWidget):
|
||||
self.uiActivateCPUThrottlingCheckBox.stateChanged.connect(self._cpuThrottlingChangedSlot)
|
||||
self.uiLegacyNetworkingCheckBox.stateChanged.connect(self._legacyNetworkingChangedSlot)
|
||||
self.uiCustomAdaptersConfigurationPushButton.clicked.connect(self._customAdaptersConfigurationSlot)
|
||||
self.uiCreateConfigDiskCheckBox.stateChanged.connect(self._createConfigDiskChangedSlot)
|
||||
|
||||
# add the categories
|
||||
for name, category in Node.defaultCategories().items():
|
||||
@@ -101,6 +102,7 @@ class QemuVMConfigurationPage(QtWidgets.QWidget, Ui_QemuVMConfigPageWidget):
|
||||
|
||||
# Supported NIC models: e1000, e1000-82544gc, e1000-82545em, e1000e, i82550, i82551, i82557a, i82557b, i82557c, i82558a
|
||||
# i82558b, i82559a, i82559b, i82559c, i82559er, i82562, i82801, ne2k_pci, pcnet, rocker, rtl8139, virtio-net-pci, vmxnet3
|
||||
# This list can be retrieved using "qemu-system-x86_64 -nic model=?" or "qemu-system-x86_64 -device help"
|
||||
self._legacy_devices = ("e1000", "i82551", "i82557b", "i82559er", "ne2k_pci", "pcnet", "rtl8139", "virtio")
|
||||
self._qemu_network_devices = OrderedDict([("e1000", "Intel Gigabit Ethernet"),
|
||||
("e1000-82544gc", "Intel 82544GC Gigabit Ethernet"),
|
||||
@@ -153,6 +155,9 @@ class QemuVMConfigurationPage(QtWidgets.QWidget, Ui_QemuVMConfigPageWidget):
|
||||
for device_name, device_description in self._qemu_network_devices.items():
|
||||
if legacy_networking and device_name not in self._legacy_devices:
|
||||
continue
|
||||
# special case for virtio legacy networking
|
||||
if not legacy_networking and device_name == "virtio":
|
||||
continue
|
||||
self.uiAdapterTypesComboBox.addItem("{} ({})".format(device_description, device_name), device_name)
|
||||
|
||||
@staticmethod
|
||||
@@ -366,6 +371,19 @@ class QemuVMConfigurationPage(QtWidgets.QWidget, Ui_QemuVMConfigPageWidget):
|
||||
else:
|
||||
self._refreshQemuNetworkDevices()
|
||||
|
||||
def _createConfigDiskChangedSlot(self, state):
|
||||
"""
|
||||
Slot to allow or not HDD disk to be configured based on the state of the config disk option.
|
||||
"""
|
||||
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
if state:
|
||||
self.uiHddDiskImageLabel.setText(_translate("QemuVMConfigPageWidget", "Startup-cfg:"))
|
||||
else:
|
||||
self.uiHddDiskImageLabel.setText(_translate("QemuVMConfigPageWidget", "Disk image:"))
|
||||
self.uiHddDiskImageCreateToolButton.setEnabled(not state)
|
||||
self.uiHddDiskImageResizeToolButton.setEnabled(not state)
|
||||
|
||||
def _customAdaptersConfigurationSlot(self):
|
||||
"""
|
||||
Slot to open the custom adapters configuration dialog
|
||||
@@ -407,7 +425,9 @@ class QemuVMConfigurationPage(QtWidgets.QWidget, Ui_QemuVMConfigPageWidget):
|
||||
if nic in self._legacy_devices:
|
||||
network_devices[nic] = desc
|
||||
else:
|
||||
network_devices = self._qemu_network_devices
|
||||
network_devices = self._qemu_network_devices.copy()
|
||||
# special case for virtio legacy networking
|
||||
network_devices.pop("virtio")
|
||||
|
||||
dialog = CustomAdaptersConfigurationDialog(ports, self._custom_adapters, default_adapter, network_devices, base_mac_address, parent=self)
|
||||
dialog.show()
|
||||
@@ -453,6 +473,7 @@ class QemuVMConfigurationPage(QtWidgets.QWidget, Ui_QemuVMConfigPageWidget):
|
||||
self.uiHdbDiskInterfaceComboBox.setCurrentIndex(self.uiHdbDiskInterfaceComboBox.findText(settings["hdb_disk_interface"]))
|
||||
self.uiHdcDiskInterfaceComboBox.setCurrentIndex(self.uiHdcDiskInterfaceComboBox.findText(settings["hdc_disk_interface"]))
|
||||
self.uiHddDiskInterfaceComboBox.setCurrentIndex(self.uiHddDiskInterfaceComboBox.findText(settings["hdd_disk_interface"]))
|
||||
self.uiCreateConfigDiskCheckBox.setChecked(settings["create_config_disk"])
|
||||
self.uiCdromImageLineEdit.setText(settings["cdrom_image"])
|
||||
self.uiBiosImageLineEdit.setText(settings["bios_image"])
|
||||
self.uiInitrdLineEdit.setText(settings["initrd"])
|
||||
@@ -588,6 +609,7 @@ class QemuVMConfigurationPage(QtWidgets.QWidget, Ui_QemuVMConfigPageWidget):
|
||||
settings["hdb_disk_interface"] = self.uiHdbDiskInterfaceComboBox.currentText()
|
||||
settings["hdc_disk_interface"] = self.uiHdcDiskInterfaceComboBox.currentText()
|
||||
settings["hdd_disk_interface"] = self.uiHddDiskInterfaceComboBox.currentText()
|
||||
settings["create_config_disk"] = self.uiCreateConfigDiskCheckBox.isChecked()
|
||||
settings["cdrom_image"] = self.uiCdromImageLineEdit.text().strip()
|
||||
settings["bios_image"] = self.uiBiosImageLineEdit.text().strip()
|
||||
settings["initrd"] = self.uiInitrdLineEdit.text().strip()
|
||||
|
||||
@@ -54,6 +54,7 @@ class QemuVMPreferencesPage(QtWidgets.QWidget, Ui_QemuVMPreferencesPageWidget):
|
||||
self.uiEditQemuVMPushButton.clicked.connect(self._qemuVMEditSlot)
|
||||
self.uiDeleteQemuVMPushButton.clicked.connect(self._qemuVMDeleteSlot)
|
||||
self.uiQemuVMsTreeWidget.itemSelectionChanged.connect(self._qemuVMChangedSlot)
|
||||
self.uiQemuVMsTreeWidget.itemDoubleClicked.connect(self._qemuVMEditSlot)
|
||||
|
||||
def _createSectionItem(self, name):
|
||||
"""
|
||||
|
||||
@@ -72,6 +72,7 @@ class QemuVM(Node):
|
||||
"mac_address": QEMU_VM_SETTINGS["mac_address"],
|
||||
"legacy_networking": QEMU_VM_SETTINGS["legacy_networking"],
|
||||
"replicate_network_connection_state": QEMU_VM_SETTINGS["replicate_network_connection_state"],
|
||||
"create_config_disk": QEMU_VM_SETTINGS["create_config_disk"],
|
||||
"platform": QEMU_VM_SETTINGS["platform"],
|
||||
"on_close": QEMU_VM_SETTINGS["on_close"],
|
||||
"cpu_throttling": QEMU_VM_SETTINGS["cpu_throttling"],
|
||||
@@ -134,6 +135,24 @@ class QemuVM(Node):
|
||||
usage = "\n" + self._settings.get("usage")
|
||||
return info + port_info + usage
|
||||
|
||||
def configFiles(self):
|
||||
"""
|
||||
Name of the configuration files
|
||||
"""
|
||||
|
||||
if self._settings.get("create_config_disk"):
|
||||
return ["config.zip"]
|
||||
return None
|
||||
|
||||
def configTextFiles(self):
|
||||
"""
|
||||
Name of the configuration files, which are plain text files
|
||||
|
||||
:returns: List of configuration files, False if no files
|
||||
"""
|
||||
|
||||
return None
|
||||
|
||||
def configPage(self):
|
||||
"""
|
||||
Returns the configuration page widget to be used by the node properties dialog.
|
||||
|
||||
@@ -41,10 +41,10 @@ QEMU_VM_SETTINGS = {
|
||||
"hdb_disk_image": "",
|
||||
"hdc_disk_image": "",
|
||||
"hdd_disk_image": "",
|
||||
"hda_disk_interface": "ide",
|
||||
"hdb_disk_interface": "ide",
|
||||
"hdc_disk_interface": "ide",
|
||||
"hdd_disk_interface": "ide",
|
||||
"hda_disk_interface": "none",
|
||||
"hdb_disk_interface": "none",
|
||||
"hdc_disk_interface": "none",
|
||||
"hdd_disk_interface": "none",
|
||||
"cdrom_image": "",
|
||||
"bios_image": "",
|
||||
"boot_priority": "c",
|
||||
@@ -57,6 +57,7 @@ QEMU_VM_SETTINGS = {
|
||||
"mac_address": "",
|
||||
"legacy_networking": False,
|
||||
"replicate_network_connection_state": True,
|
||||
"create_config_disk": False,
|
||||
"on_close": "power_off",
|
||||
"platform": "",
|
||||
"cpu_throttling": 0,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>941</width>
|
||||
<height>877</height>
|
||||
<height>939</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -399,14 +399,21 @@
|
||||
<string>HDD (Secondary Slave)</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_9">
|
||||
<item row="0" column="0">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="uiCreateConfigDiskCheckBox">
|
||||
<property name="text">
|
||||
<string>Automatically create a config disk on HDD</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="uiHddDiskImageLabel">
|
||||
<property name="text">
|
||||
<string>Disk image:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" rowspan="2">
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_10">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="uiHddDiskImageLineEdit"/>
|
||||
@@ -437,7 +444,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0" rowspan="2">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="uiHddDiskInterfaceLabel">
|
||||
<property name="text">
|
||||
<string>Disk interface:</string>
|
||||
@@ -470,7 +477,16 @@
|
||||
<string>CD/DVD</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="margin">
|
||||
<property name="leftMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
|
||||
@@ -13,7 +13,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
class Ui_QemuVMConfigPageWidget(object):
|
||||
def setupUi(self, QemuVMConfigPageWidget):
|
||||
QemuVMConfigPageWidget.setObjectName("QemuVMConfigPageWidget")
|
||||
QemuVMConfigPageWidget.resize(941, 877)
|
||||
QemuVMConfigPageWidget.resize(941, 939)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(QemuVMConfigPageWidget)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.uiQemutabWidget = QtWidgets.QTabWidget(QemuVMConfigPageWidget)
|
||||
@@ -211,9 +211,12 @@ class Ui_QemuVMConfigPageWidget(object):
|
||||
self.uiHddGroupBox.setObjectName("uiHddGroupBox")
|
||||
self.gridLayout_9 = QtWidgets.QGridLayout(self.uiHddGroupBox)
|
||||
self.gridLayout_9.setObjectName("gridLayout_9")
|
||||
self.uiCreateConfigDiskCheckBox = QtWidgets.QCheckBox(self.uiHddGroupBox)
|
||||
self.uiCreateConfigDiskCheckBox.setObjectName("uiCreateConfigDiskCheckBox")
|
||||
self.gridLayout_9.addWidget(self.uiCreateConfigDiskCheckBox, 0, 0, 1, 2)
|
||||
self.uiHddDiskImageLabel = QtWidgets.QLabel(self.uiHddGroupBox)
|
||||
self.uiHddDiskImageLabel.setObjectName("uiHddDiskImageLabel")
|
||||
self.gridLayout_9.addWidget(self.uiHddDiskImageLabel, 0, 0, 1, 1)
|
||||
self.gridLayout_9.addWidget(self.uiHddDiskImageLabel, 1, 0, 1, 1)
|
||||
self.horizontalLayout_10 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_10.setObjectName("horizontalLayout_10")
|
||||
self.uiHddDiskImageLineEdit = QtWidgets.QLineEdit(self.uiHddGroupBox)
|
||||
@@ -229,10 +232,10 @@ class Ui_QemuVMConfigPageWidget(object):
|
||||
self.uiHddDiskImageResizeToolButton = QtWidgets.QToolButton(self.uiHddGroupBox)
|
||||
self.uiHddDiskImageResizeToolButton.setObjectName("uiHddDiskImageResizeToolButton")
|
||||
self.horizontalLayout_10.addWidget(self.uiHddDiskImageResizeToolButton)
|
||||
self.gridLayout_9.addLayout(self.horizontalLayout_10, 0, 1, 2, 1)
|
||||
self.gridLayout_9.addLayout(self.horizontalLayout_10, 1, 1, 1, 1)
|
||||
self.uiHddDiskInterfaceLabel = QtWidgets.QLabel(self.uiHddGroupBox)
|
||||
self.uiHddDiskInterfaceLabel.setObjectName("uiHddDiskInterfaceLabel")
|
||||
self.gridLayout_9.addWidget(self.uiHddDiskInterfaceLabel, 1, 0, 2, 1)
|
||||
self.gridLayout_9.addWidget(self.uiHddDiskInterfaceLabel, 2, 0, 1, 1)
|
||||
self.uiHddDiskInterfaceComboBox = QtWidgets.QComboBox(self.uiHddGroupBox)
|
||||
self.uiHddDiskInterfaceComboBox.setObjectName("uiHddDiskInterfaceComboBox")
|
||||
self.gridLayout_9.addWidget(self.uiHddDiskInterfaceComboBox, 2, 1, 1, 1)
|
||||
@@ -497,6 +500,7 @@ class Ui_QemuVMConfigPageWidget(object):
|
||||
self.uiHdcDiskImageResizeToolButton.setText(_translate("QemuVMConfigPageWidget", "Resize..."))
|
||||
self.uiHdcDiskInterfaceLabel.setText(_translate("QemuVMConfigPageWidget", "Disk interface:"))
|
||||
self.uiHddGroupBox.setTitle(_translate("QemuVMConfigPageWidget", "HDD (Secondary Slave)"))
|
||||
self.uiCreateConfigDiskCheckBox.setText(_translate("QemuVMConfigPageWidget", "Automatically create a config disk on HDD"))
|
||||
self.uiHddDiskImageLabel.setText(_translate("QemuVMConfigPageWidget", "Disk image:"))
|
||||
self.uiHddDiskImageToolButton.setText(_translate("QemuVMConfigPageWidget", "&Browse..."))
|
||||
self.uiHddDiskImageCreateToolButton.setText(_translate("QemuVMConfigPageWidget", "Create..."))
|
||||
|
||||
@@ -54,6 +54,7 @@ class VirtualBoxVMPreferencesPage(QtWidgets.QWidget, Ui_VirtualBoxVMPreferencesP
|
||||
self.uiEditVirtualBoxVMPushButton.clicked.connect(self._vboxVMEditSlot)
|
||||
self.uiDeleteVirtualBoxVMPushButton.clicked.connect(self._vboxVMDeleteSlot)
|
||||
self.uiVirtualBoxVMsTreeWidget.itemSelectionChanged.connect(self._vboxVMChangedSlot)
|
||||
self.uiVirtualBoxVMsTreeWidget.itemDoubleClicked.connect(self._vboxVMEditSlot)
|
||||
|
||||
def _createSectionItem(self, name):
|
||||
"""
|
||||
|
||||
@@ -53,6 +53,7 @@ class VMwareVMPreferencesPage(QtWidgets.QWidget, Ui_VMwareVMPreferencesPageWidge
|
||||
self.uiEditVMwareVMPushButton.clicked.connect(self._vmwareVMEditSlot)
|
||||
self.uiDeleteVMwareVMPushButton.clicked.connect(self._vmwareVMDeleteSlot)
|
||||
self.uiVMwareVMsTreeWidget.itemSelectionChanged.connect(self._vmwareVMChangedSlot)
|
||||
self.uiVMwareVMsTreeWidget.itemDoubleClicked.connect(self._vmwareVMEditSlot)
|
||||
|
||||
def _createSectionItem(self, name):
|
||||
"""
|
||||
|
||||
@@ -53,6 +53,7 @@ class VPCSNodePreferencesPage(QtWidgets.QWidget, Ui_VPCSNodePageWidget):
|
||||
self.uiEditVPCSPushButton.clicked.connect(self._editVPCSSlot)
|
||||
self.uiDeleteVPCSPushButton.clicked.connect(self._deleteVPCSSlot)
|
||||
self.uiVPCSTreeWidget.itemSelectionChanged.connect(self._vpcsChangedSlot)
|
||||
self.uiVPCSTreeWidget.itemDoubleClicked.connect(self._editVPCSSlot)
|
||||
|
||||
def _createSectionItem(self, name):
|
||||
"""
|
||||
|
||||
35
gns3/node.py
35
gns3/node.py
@@ -199,6 +199,26 @@ class Node(BaseNode):
|
||||
|
||||
return self._always_on
|
||||
|
||||
def configFiles(self):
|
||||
"""
|
||||
Name of the configuration files
|
||||
|
||||
This method should be overridden in derived classes
|
||||
|
||||
:returns: List of configuration files, False if no files
|
||||
"""
|
||||
|
||||
return None
|
||||
|
||||
def configTextFiles(self):
|
||||
"""
|
||||
Name of the configuration files, which are plain text files
|
||||
|
||||
:returns: List of configuration files, False if no files
|
||||
"""
|
||||
|
||||
return self.configFiles()
|
||||
|
||||
def get(self, path, *args, **kwargs):
|
||||
"""
|
||||
GET on current server / project
|
||||
@@ -538,7 +558,7 @@ class Node(BaseNode):
|
||||
del result["properties"]
|
||||
|
||||
# Update common element of all nodes
|
||||
for key in ["x", "y", "z", "locked", "symbol", "label", "console_host", "console", "console_type", "console_auto_start", "custom_adapters"]:
|
||||
for key in ["x", "y", "z", "locked", "symbol", "label", "console_host", "console", "console_type", "console_auto_start", "custom_adapters", "first_port_name", "port_name_format", "port_segment_size"]:
|
||||
if key in result:
|
||||
self._settings[key] = result[key]
|
||||
|
||||
@@ -630,10 +650,11 @@ class Node(BaseNode):
|
||||
|
||||
if not console_type:
|
||||
console_type = self.consoleType()
|
||||
if console_type == "vnc":
|
||||
return general_settings["vnc_console_command"]
|
||||
elif console_type.startswith("spice"):
|
||||
return general_settings["spice_console_command"]
|
||||
if console_type:
|
||||
if console_type == "vnc":
|
||||
return general_settings["vnc_console_command"]
|
||||
elif console_type.startswith("spice"):
|
||||
return general_settings["spice_console_command"]
|
||||
return general_settings["telnet_console_command"]
|
||||
|
||||
def consoleType(self):
|
||||
@@ -774,7 +795,7 @@ class Node(BaseNode):
|
||||
:param directory: destination directory path
|
||||
"""
|
||||
|
||||
if not hasattr(self, "configFiles"):
|
||||
if not self.configFiles():
|
||||
return False
|
||||
for file in self.configFiles():
|
||||
self.get("/files/{file}".format(file=file),
|
||||
@@ -813,7 +834,7 @@ class Node(BaseNode):
|
||||
:param directory: source directory path
|
||||
"""
|
||||
|
||||
if not hasattr(self, "configFiles"):
|
||||
if not self.configFiles():
|
||||
return
|
||||
|
||||
try:
|
||||
|
||||
@@ -151,6 +151,22 @@ class NodesView(QtWidgets.QTreeWidget):
|
||||
|
||||
self._showContextualMenu(event.globalPos())
|
||||
|
||||
def mouseDoubleClickEvent(self, event):
|
||||
"""
|
||||
Handles all mouse double click events.
|
||||
|
||||
:param event: QMouseEvent instance
|
||||
"""
|
||||
|
||||
item = self.itemAt(event.pos())
|
||||
if item:
|
||||
template = TemplateManager.instance().getTemplate(item.data(0, QtCore.Qt.UserRole))
|
||||
if template:
|
||||
configuration_page = TEMPLATE_TYPE_TO_CONFIGURATION_PAGE.get(template.template_type())
|
||||
if not template.builtin() and configuration_page:
|
||||
self._configurationSlot(template, configuration_page)
|
||||
super().mouseDoubleClickEvent(event)
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
"""
|
||||
Handles all mouse move events.
|
||||
@@ -204,14 +220,14 @@ class NodesView(QtWidgets.QTreeWidget):
|
||||
|
||||
menu.exec_(pos)
|
||||
|
||||
def _configurationSlot(self, template, configuration_page, source):
|
||||
def _configurationSlot(self, template, configuration_page, source=None):
|
||||
|
||||
dialog = ConfigurationDialog(template.name(), template.settings(), configuration_page(), parent=self)
|
||||
dialog.show()
|
||||
if dialog.exec_():
|
||||
TemplateManager.instance().updateTemplate(template)
|
||||
|
||||
def _deleteSlot(self, template, source):
|
||||
def _deleteSlot(self, template, source=None):
|
||||
|
||||
reply = QtWidgets.QMessageBox.question(self, "Template", "Delete {} template?".format(template.name()),
|
||||
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
|
||||
|
||||
@@ -90,12 +90,11 @@ class PacketCapture:
|
||||
|
||||
def _updatedLinkSlot(self, link_id):
|
||||
link = self.topology().getLink(link_id)
|
||||
|
||||
if link:
|
||||
if link.capturing():
|
||||
if self._autostart.get(link) and link not in self._tail_process:
|
||||
log.debug("Starting packet capture reader for link {}".format(link.link_id()))
|
||||
self.startPacketCaptureReader(link)
|
||||
log.debug("Has successfully started capturing packets on {} to {}".format(link.id(), link.capture_file_path()))
|
||||
else:
|
||||
self.stopPacketCaptureReader(link)
|
||||
|
||||
@@ -108,7 +107,6 @@ class PacketCapture:
|
||||
"""
|
||||
|
||||
link.stopCapture()
|
||||
log.debug("Has successfully stopped capturing packets on {}".format(link.id()))
|
||||
|
||||
def startPacketCaptureReader(self, link):
|
||||
"""
|
||||
@@ -121,6 +119,7 @@ class PacketCapture:
|
||||
Stop the packet capture reader
|
||||
"""
|
||||
if link in self._tail_process and self._tail_process[link].poll() is None:
|
||||
log.debug("Stopping packet capture reader for link {}".format(link.link_id()))
|
||||
self._tail_process[link].kill()
|
||||
del self._tail_process[link]
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ class GNS3VMPreferencesPage(QtWidgets.QWidget, Ui_GNS3VMPreferencesPageWidget):
|
||||
self._initialized = False
|
||||
self.uiRefreshPushButton.clicked.connect(self._refreshVMSlot)
|
||||
self.uiGNS3VMEngineComboBox.currentIndexChanged.connect(self._engineChangedSlot)
|
||||
self.uiAllocatevCPUsRAMCheckBox.stateChanged.connect(self._allocatevCPUsRAMSlot)
|
||||
Controller.instance().connected_signal.connect(self.loadPreferences)
|
||||
|
||||
def pageInitialized(self):
|
||||
@@ -74,6 +75,18 @@ class GNS3VMPreferencesPage(QtWidgets.QWidget, Ui_GNS3VMPreferencesPageWidget):
|
||||
self.uiPortSpinBox.setVisible(True)
|
||||
self._refreshVMSlot(ignore_error=True)
|
||||
|
||||
def _allocatevCPUsRAMSlot(self, state):
|
||||
"""
|
||||
Slot to enable or not the vCPUS and RAM spin boxes.
|
||||
"""
|
||||
|
||||
if state:
|
||||
self.uiRamSpinBox.setEnabled(True)
|
||||
self.uiCpuSpinBox.setEnabled(True)
|
||||
else:
|
||||
self.uiRamSpinBox.setEnabled(False)
|
||||
self.uiCpuSpinBox.setEnabled(False)
|
||||
|
||||
def loadPreferences(self):
|
||||
"""
|
||||
Loads the preference from controller.
|
||||
@@ -95,6 +108,7 @@ class GNS3VMPreferencesPage(QtWidgets.QWidget, Ui_GNS3VMPreferencesPageWidget):
|
||||
return
|
||||
self._old_settings = copy.copy(result)
|
||||
self._settings = result
|
||||
self.uiAllocatevCPUsRAMCheckBox.setChecked(self._settings["allocate_vcpus_ram"])
|
||||
self.uiRamSpinBox.setValue(self._settings["ram"])
|
||||
self.uiCpuSpinBox.setValue(self._settings["vcpus"])
|
||||
self.uiPortSpinBox.setValue(self._settings.get("port", 3080))
|
||||
@@ -174,6 +188,7 @@ class GNS3VMPreferencesPage(QtWidgets.QWidget, Ui_GNS3VMPreferencesPageWidget):
|
||||
"headless": self.uiHeadlessCheckBox.isChecked(),
|
||||
"when_exit": when_exit,
|
||||
"engine": self.uiGNS3VMEngineComboBox.currentData(),
|
||||
"allocate_vcpus_ram": self.uiAllocatevCPUsRAMCheckBox.isChecked(),
|
||||
"ram": self.uiRamSpinBox.value(),
|
||||
"vcpus": self.uiCpuSpinBox.value(),
|
||||
"port": self.uiPortSpinBox.value()
|
||||
|
||||
@@ -191,6 +191,7 @@ class ServerPreferencesPage(QtWidgets.QWidget, Ui_ServerPreferencesPageWidget):
|
||||
|
||||
self.uiRemoteMainServerHostLineEdit.setText(servers_settings["host"])
|
||||
self.uiRemoteMainServerPortSpinBox.setValue(servers_settings["port"])
|
||||
self.uiRemoteMainServerProtocolComboBox.setCurrentText(servers_settings["protocol"].upper())
|
||||
self.uiRemoteMainServerUserLineEdit.setText(servers_settings["user"])
|
||||
self.uiRemoteMainServerPasswordLineEdit.setText(servers_settings["password"])
|
||||
self.uiRemoteMainServerAuthCheckBox.setChecked(servers_settings["auth"])
|
||||
@@ -285,7 +286,7 @@ class ServerPreferencesPage(QtWidgets.QWidget, Ui_ServerPreferencesPageWidget):
|
||||
else:
|
||||
new_local_server_settings["host"] = self.uiRemoteMainServerHostLineEdit.text()
|
||||
new_local_server_settings["port"] = self.uiRemoteMainServerPortSpinBox.value()
|
||||
new_local_server_settings["protocol"] = "http"
|
||||
new_local_server_settings["protocol"] = self.uiRemoteMainServerProtocolComboBox.currentText().lower()
|
||||
new_local_server_settings["user"] = self.uiRemoteMainServerUserLineEdit.text()
|
||||
new_local_server_settings["password"] = self.uiRemoteMainServerPasswordLineEdit.text()
|
||||
new_local_server_settings["auth"] = self.uiRemoteMainServerAuthCheckBox.isChecked()
|
||||
|
||||
@@ -632,6 +632,7 @@ class Project(QtCore.QObject):
|
||||
self._notification_stream = Controller.instance().httpClient().connectWebSocket(self._websocket, path)
|
||||
self._notification_stream.textMessageReceived.connect(self._websocket_event_received)
|
||||
self._notification_stream.error.connect(self._websocket_error)
|
||||
self._notification_stream.sslErrors.connect(self._sslErrorsSlot)
|
||||
|
||||
def _endListenNotificationCallback(self, result, error=False, **kwargs):
|
||||
"""
|
||||
@@ -648,6 +649,11 @@ class Project(QtCore.QObject):
|
||||
self._notification_stream = None
|
||||
self._startListenNotifications()
|
||||
|
||||
@qslot
|
||||
def _sslErrorsSlot(self, ssl_errors):
|
||||
|
||||
Controller.instance().httpClient().handleSslError(self._notification_stream, ssl_errors)
|
||||
|
||||
@qslot
|
||||
def _websocket_event_received(self, event):
|
||||
try:
|
||||
|
||||
@@ -115,22 +115,14 @@ class Appliance(collections.abc.Mapping):
|
||||
if not found:
|
||||
raise ApplianceError("Broken appliance missing file {} for version {}".format(filename, version["name"]))
|
||||
|
||||
def create_new_version(self, version_name):
|
||||
def create_new_version(self, new_version):
|
||||
"""
|
||||
Duplicate a version in order to create a new version
|
||||
"""
|
||||
if 'versions' not in self._appliance.keys() or not self._appliance["versions"]:
|
||||
|
||||
if "versions" not in self._appliance.keys() or not self._appliance["versions"]:
|
||||
raise ApplianceError("Your appliance file doesn't contain any versions")
|
||||
|
||||
ref = self._appliance["versions"][0]
|
||||
new_version = {'name': version_name}
|
||||
new_version['images'] = {}
|
||||
|
||||
for disk_type in ref['images']:
|
||||
filename = ref['images'][disk_type]['filename']
|
||||
filename = filename.replace(ref['images'][disk_type]['version'], version_name)
|
||||
new_version['images'][disk_type] = {'filename': filename, 'version': version_name}
|
||||
self._appliance['versions'].append(new_version)
|
||||
self._appliance["versions"].append(new_version)
|
||||
|
||||
def search_images_for_version(self, version_name):
|
||||
"""
|
||||
|
||||
@@ -100,8 +100,8 @@ class ApplianceToTemplate:
|
||||
new_config.pop("arch", None)
|
||||
|
||||
options = appliance_config["qemu"].get("options", "")
|
||||
if appliance_config["qemu"].get("kvm", "allow") == "disable" and "-no-kvm" not in options:
|
||||
options += " -no-kvm"
|
||||
if appliance_config["qemu"].get("kvm", "allow") == "disable" and "-machine accel=tcg" not in options:
|
||||
options += " -machine accel=tcg"
|
||||
new_config["options"] = options.strip()
|
||||
|
||||
for image in appliance_config["images"]:
|
||||
@@ -178,8 +178,9 @@ class ApplianceToTemplate:
|
||||
if symbol_id.startswith(":/symbols/"):
|
||||
return symbol_id
|
||||
|
||||
controller = Controller.instance()
|
||||
path = os.path.join(Config().symbols_dir, symbol_id)
|
||||
if os.path.exists(path):
|
||||
if not controller.isRemote() and os.path.exists(path):
|
||||
return os.path.basename(path)
|
||||
|
||||
if controller_symbols:
|
||||
@@ -197,7 +198,6 @@ class ApplianceToTemplate:
|
||||
url = "https://raw.githubusercontent.com/GNS3/gns3-registry/master/symbols/{}".format(symbol_id)
|
||||
try:
|
||||
self._downloadApplianceSymbol(url, path)
|
||||
controller = Controller.instance()
|
||||
controller.clearStaticCache()
|
||||
if controller.isRemote():
|
||||
controller.uploadSymbol(symbol_id, path)
|
||||
|
||||
@@ -141,8 +141,10 @@ elif sys.platform.startswith("darwin"):
|
||||
r""" -e 'end tell'""",
|
||||
'Royal TSX': "open 'rtsx://telnet%3A%2F%2F%h:%p'",
|
||||
'SecureCRT': '/Applications/SecureCRT.app/Contents/MacOS/SecureCRT /N "%d" /T /TELNET %h %p',
|
||||
'Windows Terminal': 'wt.exe -w 1 new-tab --title %d telnet %h %p',
|
||||
'ZOC 6': '/Applications/zoc6.app/Contents/MacOS/zoc6 "/TELNET:%h:%p" /TABBED "/TITLE:%d"',
|
||||
'ZOC 7': '/Applications/zoc7.app/Contents/MacOS/zoc7 "/TELNET:%h:%p" /TABBED "/TITLE:%d"'
|
||||
'ZOC 7': '/Applications/zoc7.app/Contents/MacOS/zoc7 "/TELNET:%h:%p" /TABBED "/TITLE:%d"',
|
||||
'ZOC 8': '/Applications/zoc8.app/Contents/MacOS/zoc8 "/TELNET:%h:%p" /TABBED "/TITLE:%d"'
|
||||
}
|
||||
|
||||
# default Mac OS X Telnet console command
|
||||
@@ -157,7 +159,9 @@ else:
|
||||
'KDE Konsole': 'konsole --new-tab -p tabtitle="%d" -e "telnet %h %p"',
|
||||
'SecureCRT': 'SecureCRT /T /N "%d" /TELNET %h %p',
|
||||
'Mate Terminal': 'mate-terminal --tab -e "telnet %h %p" -t "%d"',
|
||||
'urxvt': 'urxvt -title %d -e telnet %h %p'}
|
||||
'terminator': 'terminator -e "telnet %h %p" -T "%d"',
|
||||
'urxvt': 'urxvt -title %d -e telnet %h %p',
|
||||
'kitty': 'kitty -T %d telnet %h %p'}
|
||||
|
||||
# default Telnet console command on other systems
|
||||
DEFAULT_TELNET_CONSOLE_COMMAND = PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Xterm"]
|
||||
|
||||
@@ -62,7 +62,7 @@ class Topology(QtCore.QObject):
|
||||
self._main_window = None
|
||||
|
||||
# If set the project is loaded when we got connection to the controller
|
||||
# usefull when we open a project from cli or when server restart
|
||||
# useful when we open a project from cli or when server restart
|
||||
self._project_to_load_path = None
|
||||
self._project_id_to_load = None
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>579</width>
|
||||
<height>374</height>
|
||||
<width>585</width>
|
||||
<height>353</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -23,10 +23,31 @@
|
||||
<string>Server settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="uiServerPortLabel">
|
||||
<property name="text">
|
||||
<string>Port:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="uiServerNameLineEdit"/>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="uiServerHostLineEdit">
|
||||
<property name="text">
|
||||
<string>192.168.56.101</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="uiServerHostLabel">
|
||||
<property name="text">
|
||||
<string>Host:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" colspan="2">
|
||||
<widget class="QSpinBox" name="uiServerPortSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
@@ -52,25 +73,25 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="uiServerHostLineEdit">
|
||||
<property name="text">
|
||||
<string>192.168.56.101</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="uiServerHostLabel">
|
||||
<widget class="QLabel" name="uiServerProtocolLabel">
|
||||
<property name="text">
|
||||
<string>Host:</string>
|
||||
<string>Protocol:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="uiServerPortLabel">
|
||||
<property name="text">
|
||||
<string>Port:</string>
|
||||
</property>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="uiServerProtocolComboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>HTTP</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>HTTPS</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
@@ -1,29 +1,39 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file '/Users/noplay/code/gns3/gns3-gui/gns3/ui/edit_compute_dialog.ui'
|
||||
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/edit_compute_dialog.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.8
|
||||
# Created by: PyQt5 UI code generator 5.15.2
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_EditComputeDialog(object):
|
||||
|
||||
def setupUi(self, EditComputeDialog):
|
||||
EditComputeDialog.setObjectName("EditComputeDialog")
|
||||
EditComputeDialog.setWindowModality(QtCore.Qt.WindowModal)
|
||||
EditComputeDialog.resize(579, 374)
|
||||
EditComputeDialog.resize(585, 353)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(EditComputeDialog)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.groupBox = QtWidgets.QGroupBox(EditComputeDialog)
|
||||
self.groupBox.setObjectName("groupBox")
|
||||
self.gridLayout = QtWidgets.QGridLayout(self.groupBox)
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.uiServerPortLabel = QtWidgets.QLabel(self.groupBox)
|
||||
self.uiServerPortLabel.setObjectName("uiServerPortLabel")
|
||||
self.gridLayout.addWidget(self.uiServerPortLabel, 3, 0, 1, 1)
|
||||
self.uiServerNameLineEdit = QtWidgets.QLineEdit(self.groupBox)
|
||||
self.uiServerNameLineEdit.setObjectName("uiServerNameLineEdit")
|
||||
self.gridLayout.addWidget(self.uiServerNameLineEdit, 0, 1, 1, 1)
|
||||
self.uiServerHostLineEdit = QtWidgets.QLineEdit(self.groupBox)
|
||||
self.uiServerHostLineEdit.setObjectName("uiServerHostLineEdit")
|
||||
self.gridLayout.addWidget(self.uiServerHostLineEdit, 2, 1, 1, 2)
|
||||
self.uiServerHostLabel = QtWidgets.QLabel(self.groupBox)
|
||||
self.uiServerHostLabel.setObjectName("uiServerHostLabel")
|
||||
self.gridLayout.addWidget(self.uiServerHostLabel, 2, 0, 1, 1)
|
||||
self.uiServerPortSpinBox = QtWidgets.QSpinBox(self.groupBox)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
@@ -34,19 +44,18 @@ class Ui_EditComputeDialog(object):
|
||||
self.uiServerPortSpinBox.setMaximum(65535)
|
||||
self.uiServerPortSpinBox.setProperty("value", 3080)
|
||||
self.uiServerPortSpinBox.setObjectName("uiServerPortSpinBox")
|
||||
self.gridLayout.addWidget(self.uiServerPortSpinBox, 2, 1, 1, 2)
|
||||
self.gridLayout.addWidget(self.uiServerPortSpinBox, 3, 1, 1, 2)
|
||||
self.label = QtWidgets.QLabel(self.groupBox)
|
||||
self.label.setObjectName("label")
|
||||
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
|
||||
self.uiServerHostLineEdit = QtWidgets.QLineEdit(self.groupBox)
|
||||
self.uiServerHostLineEdit.setObjectName("uiServerHostLineEdit")
|
||||
self.gridLayout.addWidget(self.uiServerHostLineEdit, 1, 1, 1, 2)
|
||||
self.uiServerHostLabel = QtWidgets.QLabel(self.groupBox)
|
||||
self.uiServerHostLabel.setObjectName("uiServerHostLabel")
|
||||
self.gridLayout.addWidget(self.uiServerHostLabel, 1, 0, 1, 1)
|
||||
self.uiServerPortLabel = QtWidgets.QLabel(self.groupBox)
|
||||
self.uiServerPortLabel.setObjectName("uiServerPortLabel")
|
||||
self.gridLayout.addWidget(self.uiServerPortLabel, 2, 0, 1, 1)
|
||||
self.uiServerProtocolLabel = QtWidgets.QLabel(self.groupBox)
|
||||
self.uiServerProtocolLabel.setObjectName("uiServerProtocolLabel")
|
||||
self.gridLayout.addWidget(self.uiServerProtocolLabel, 1, 0, 1, 1)
|
||||
self.uiServerProtocolComboBox = QtWidgets.QComboBox(self.groupBox)
|
||||
self.uiServerProtocolComboBox.setObjectName("uiServerProtocolComboBox")
|
||||
self.uiServerProtocolComboBox.addItem("")
|
||||
self.uiServerProtocolComboBox.addItem("")
|
||||
self.gridLayout.addWidget(self.uiServerProtocolComboBox, 1, 1, 1, 1)
|
||||
self.verticalLayout.addWidget(self.groupBox)
|
||||
self.uiEnableAuthenticationCheckBox = QtWidgets.QGroupBox(EditComputeDialog)
|
||||
self.uiEnableAuthenticationCheckBox.setCheckable(True)
|
||||
@@ -67,7 +76,7 @@ class Ui_EditComputeDialog(object):
|
||||
self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.uiServerPasswordLabel)
|
||||
self.uiServerPasswordLineEdit = QtWidgets.QLineEdit(self.uiEnableAuthenticationCheckBox)
|
||||
self.uiServerPasswordLineEdit.setEnabled(True)
|
||||
self.uiServerPasswordLineEdit.setInputMethodHints(QtCore.Qt.ImhHiddenText | QtCore.Qt.ImhNoAutoUppercase | QtCore.Qt.ImhNoPredictiveText | QtCore.Qt.ImhSensitiveData)
|
||||
self.uiServerPasswordLineEdit.setInputMethodHints(QtCore.Qt.ImhHiddenText|QtCore.Qt.ImhNoAutoUppercase|QtCore.Qt.ImhNoPredictiveText|QtCore.Qt.ImhSensitiveData)
|
||||
self.uiServerPasswordLineEdit.setEchoMode(QtWidgets.QLineEdit.Password)
|
||||
self.uiServerPasswordLineEdit.setObjectName("uiServerPasswordLineEdit")
|
||||
self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.uiServerPasswordLineEdit)
|
||||
@@ -80,7 +89,7 @@ class Ui_EditComputeDialog(object):
|
||||
self.verticalLayout.addItem(spacerItem)
|
||||
self.buttonBox = QtWidgets.QDialogButtonBox(EditComputeDialog)
|
||||
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
|
||||
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok)
|
||||
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
|
||||
self.buttonBox.setObjectName("buttonBox")
|
||||
self.verticalLayout.addWidget(self.buttonBox)
|
||||
|
||||
@@ -98,10 +107,13 @@ class Ui_EditComputeDialog(object):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
EditComputeDialog.setWindowTitle(_translate("EditComputeDialog", "Edit server settings"))
|
||||
self.groupBox.setTitle(_translate("EditComputeDialog", "Server settings"))
|
||||
self.label.setText(_translate("EditComputeDialog", "Name:"))
|
||||
self.uiServerPortLabel.setText(_translate("EditComputeDialog", "Port:"))
|
||||
self.uiServerHostLineEdit.setText(_translate("EditComputeDialog", "192.168.56.101"))
|
||||
self.uiServerHostLabel.setText(_translate("EditComputeDialog", "Host:"))
|
||||
self.uiServerPortLabel.setText(_translate("EditComputeDialog", "Port:"))
|
||||
self.label.setText(_translate("EditComputeDialog", "Name:"))
|
||||
self.uiServerProtocolLabel.setText(_translate("EditComputeDialog", "Protocol:"))
|
||||
self.uiServerProtocolComboBox.setItemText(0, _translate("EditComputeDialog", "HTTP"))
|
||||
self.uiServerProtocolComboBox.setItemText(1, _translate("EditComputeDialog", "HTTPS"))
|
||||
self.uiEnableAuthenticationCheckBox.setTitle(_translate("EditComputeDialog", "Enable authentication"))
|
||||
self.uiServerUserLabel.setText(_translate("EditComputeDialog", "User:"))
|
||||
self.uiServerPasswordLabel.setText(_translate("EditComputeDialog", "Password:"))
|
||||
|
||||
@@ -85,28 +85,28 @@
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="8" column="0" colspan="2">
|
||||
<widget class="QLabel" name="uiActionCloseLabel">
|
||||
<property name="text">
|
||||
<string>Action when closing GNS3:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="uiHeadlessCheckBox">
|
||||
<property name="text">
|
||||
<string>Run the VM in headless mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0" colspan="2">
|
||||
<item row="11" column="0" colspan="2">
|
||||
<widget class="QLabel" name="uiActionCloseLabel">
|
||||
<property name="text">
|
||||
<string>Action when closing GNS3:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0" colspan="2">
|
||||
<widget class="QRadioButton" name="uiWhenExitKeepRadioButton">
|
||||
<property name="text">
|
||||
<string>keep the GNS3 VM running</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0" colspan="2">
|
||||
<item row="13" column="0" colspan="2">
|
||||
<widget class="QRadioButton" name="uiWhenExitSuspendRadioButton">
|
||||
<property name="text">
|
||||
<string>suspend the GNS3 VM</string>
|
||||
@@ -141,22 +141,25 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="11" column="0" colspan="2">
|
||||
<item row="14" column="0" colspan="2">
|
||||
<widget class="QRadioButton" name="uiWhenExitStopRadioButton">
|
||||
<property name="text">
|
||||
<string>stop the GNS3 VM</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="uiRamLabel">
|
||||
<property name="text">
|
||||
<string>RAM:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="6" column="1">
|
||||
<widget class="QSpinBox" name="uiRamSpinBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> MB</string>
|
||||
</property>
|
||||
@@ -174,23 +177,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QSpinBox" name="uiCpuSpinBox">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="uiCpuLabel">
|
||||
<property name="text">
|
||||
<string>vCPUs:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="uiPortLabel">
|
||||
<property name="text">
|
||||
@@ -211,6 +197,33 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="uiAllocatevCPUsRAMCheckBox">
|
||||
<property name="text">
|
||||
<string>Allocate vCPUs and RAM</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="uiCpuLabel">
|
||||
<property name="text">
|
||||
<string>vCPUs:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QSpinBox" name="uiCpuSpinBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -234,9 +247,7 @@
|
||||
<tabstop>uiGNS3VMEngineComboBox</tabstop>
|
||||
<tabstop>uiVMListComboBox</tabstop>
|
||||
<tabstop>uiRefreshPushButton</tabstop>
|
||||
<tabstop>uiHeadlessCheckBox</tabstop>
|
||||
<tabstop>uiRamSpinBox</tabstop>
|
||||
<tabstop>uiCpuSpinBox</tabstop>
|
||||
<tabstop>uiWhenExitKeepRadioButton</tabstop>
|
||||
<tabstop>uiWhenExitSuspendRadioButton</tabstop>
|
||||
<tabstop>uiWhenExitStopRadioButton</tabstop>
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
|
||||
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/gns3_vm_preferences_page.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.13.2
|
||||
# Created by: PyQt5 UI code generator 5.15.0
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
@@ -54,18 +55,18 @@ class Ui_GNS3VMPreferencesPageWidget(object):
|
||||
self.uiGNS3VMSettingsGroupBox.setObjectName("uiGNS3VMSettingsGroupBox")
|
||||
self.gridLayout = QtWidgets.QGridLayout(self.uiGNS3VMSettingsGroupBox)
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.uiActionCloseLabel = QtWidgets.QLabel(self.uiGNS3VMSettingsGroupBox)
|
||||
self.uiActionCloseLabel.setObjectName("uiActionCloseLabel")
|
||||
self.gridLayout.addWidget(self.uiActionCloseLabel, 8, 0, 1, 2)
|
||||
self.uiHeadlessCheckBox = QtWidgets.QCheckBox(self.uiGNS3VMSettingsGroupBox)
|
||||
self.uiHeadlessCheckBox.setObjectName("uiHeadlessCheckBox")
|
||||
self.gridLayout.addWidget(self.uiHeadlessCheckBox, 1, 0, 1, 2)
|
||||
self.gridLayout.addWidget(self.uiHeadlessCheckBox, 3, 0, 1, 2)
|
||||
self.uiActionCloseLabel = QtWidgets.QLabel(self.uiGNS3VMSettingsGroupBox)
|
||||
self.uiActionCloseLabel.setObjectName("uiActionCloseLabel")
|
||||
self.gridLayout.addWidget(self.uiActionCloseLabel, 11, 0, 1, 2)
|
||||
self.uiWhenExitKeepRadioButton = QtWidgets.QRadioButton(self.uiGNS3VMSettingsGroupBox)
|
||||
self.uiWhenExitKeepRadioButton.setObjectName("uiWhenExitKeepRadioButton")
|
||||
self.gridLayout.addWidget(self.uiWhenExitKeepRadioButton, 9, 0, 1, 2)
|
||||
self.gridLayout.addWidget(self.uiWhenExitKeepRadioButton, 12, 0, 1, 2)
|
||||
self.uiWhenExitSuspendRadioButton = QtWidgets.QRadioButton(self.uiGNS3VMSettingsGroupBox)
|
||||
self.uiWhenExitSuspendRadioButton.setObjectName("uiWhenExitSuspendRadioButton")
|
||||
self.gridLayout.addWidget(self.uiWhenExitSuspendRadioButton, 10, 0, 1, 2)
|
||||
self.gridLayout.addWidget(self.uiWhenExitSuspendRadioButton, 13, 0, 1, 2)
|
||||
self.uiVMNameLabel = QtWidgets.QLabel(self.uiGNS3VMSettingsGroupBox)
|
||||
self.uiVMNameLabel.setObjectName("uiVMNameLabel")
|
||||
self.gridLayout.addWidget(self.uiVMNameLabel, 0, 0, 1, 1)
|
||||
@@ -85,25 +86,18 @@ class Ui_GNS3VMPreferencesPageWidget(object):
|
||||
self.gridLayout.addLayout(self.horizontalLayout, 0, 1, 1, 1)
|
||||
self.uiWhenExitStopRadioButton = QtWidgets.QRadioButton(self.uiGNS3VMSettingsGroupBox)
|
||||
self.uiWhenExitStopRadioButton.setObjectName("uiWhenExitStopRadioButton")
|
||||
self.gridLayout.addWidget(self.uiWhenExitStopRadioButton, 11, 0, 1, 2)
|
||||
self.gridLayout.addWidget(self.uiWhenExitStopRadioButton, 14, 0, 1, 2)
|
||||
self.uiRamLabel = QtWidgets.QLabel(self.uiGNS3VMSettingsGroupBox)
|
||||
self.uiRamLabel.setObjectName("uiRamLabel")
|
||||
self.gridLayout.addWidget(self.uiRamLabel, 4, 0, 1, 1)
|
||||
self.gridLayout.addWidget(self.uiRamLabel, 6, 0, 1, 1)
|
||||
self.uiRamSpinBox = QtWidgets.QSpinBox(self.uiGNS3VMSettingsGroupBox)
|
||||
self.uiRamSpinBox.setEnabled(False)
|
||||
self.uiRamSpinBox.setMinimum(512)
|
||||
self.uiRamSpinBox.setMaximum(1000000)
|
||||
self.uiRamSpinBox.setSingleStep(512)
|
||||
self.uiRamSpinBox.setProperty("value", 2048)
|
||||
self.uiRamSpinBox.setObjectName("uiRamSpinBox")
|
||||
self.gridLayout.addWidget(self.uiRamSpinBox, 4, 1, 1, 1)
|
||||
self.uiCpuSpinBox = QtWidgets.QSpinBox(self.uiGNS3VMSettingsGroupBox)
|
||||
self.uiCpuSpinBox.setMinimum(1)
|
||||
self.uiCpuSpinBox.setProperty("value", 1)
|
||||
self.uiCpuSpinBox.setObjectName("uiCpuSpinBox")
|
||||
self.gridLayout.addWidget(self.uiCpuSpinBox, 5, 1, 1, 1)
|
||||
self.uiCpuLabel = QtWidgets.QLabel(self.uiGNS3VMSettingsGroupBox)
|
||||
self.uiCpuLabel.setObjectName("uiCpuLabel")
|
||||
self.gridLayout.addWidget(self.uiCpuLabel, 5, 0, 1, 1)
|
||||
self.gridLayout.addWidget(self.uiRamSpinBox, 6, 1, 1, 1)
|
||||
self.uiPortLabel = QtWidgets.QLabel(self.uiGNS3VMSettingsGroupBox)
|
||||
self.uiPortLabel.setObjectName("uiPortLabel")
|
||||
self.gridLayout.addWidget(self.uiPortLabel, 2, 0, 1, 1)
|
||||
@@ -113,6 +107,18 @@ class Ui_GNS3VMPreferencesPageWidget(object):
|
||||
self.uiPortSpinBox.setProperty("value", 80)
|
||||
self.uiPortSpinBox.setObjectName("uiPortSpinBox")
|
||||
self.gridLayout.addWidget(self.uiPortSpinBox, 2, 1, 1, 1)
|
||||
self.uiAllocatevCPUsRAMCheckBox = QtWidgets.QCheckBox(self.uiGNS3VMSettingsGroupBox)
|
||||
self.uiAllocatevCPUsRAMCheckBox.setObjectName("uiAllocatevCPUsRAMCheckBox")
|
||||
self.gridLayout.addWidget(self.uiAllocatevCPUsRAMCheckBox, 4, 0, 1, 2)
|
||||
self.uiCpuLabel = QtWidgets.QLabel(self.uiGNS3VMSettingsGroupBox)
|
||||
self.uiCpuLabel.setObjectName("uiCpuLabel")
|
||||
self.gridLayout.addWidget(self.uiCpuLabel, 5, 0, 1, 1)
|
||||
self.uiCpuSpinBox = QtWidgets.QSpinBox(self.uiGNS3VMSettingsGroupBox)
|
||||
self.uiCpuSpinBox.setEnabled(False)
|
||||
self.uiCpuSpinBox.setMinimum(1)
|
||||
self.uiCpuSpinBox.setProperty("value", 1)
|
||||
self.uiCpuSpinBox.setObjectName("uiCpuSpinBox")
|
||||
self.gridLayout.addWidget(self.uiCpuSpinBox, 5, 1, 1, 1)
|
||||
self.verticalLayout.addWidget(self.uiGNS3VMSettingsGroupBox)
|
||||
spacerItem = QtWidgets.QSpacerItem(10, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.verticalLayout.addItem(spacerItem)
|
||||
@@ -122,10 +128,8 @@ class Ui_GNS3VMPreferencesPageWidget(object):
|
||||
GNS3VMPreferencesPageWidget.setTabOrder(self.uiEnableVMCheckBox, self.uiGNS3VMEngineComboBox)
|
||||
GNS3VMPreferencesPageWidget.setTabOrder(self.uiGNS3VMEngineComboBox, self.uiVMListComboBox)
|
||||
GNS3VMPreferencesPageWidget.setTabOrder(self.uiVMListComboBox, self.uiRefreshPushButton)
|
||||
GNS3VMPreferencesPageWidget.setTabOrder(self.uiRefreshPushButton, self.uiHeadlessCheckBox)
|
||||
GNS3VMPreferencesPageWidget.setTabOrder(self.uiHeadlessCheckBox, self.uiRamSpinBox)
|
||||
GNS3VMPreferencesPageWidget.setTabOrder(self.uiRamSpinBox, self.uiCpuSpinBox)
|
||||
GNS3VMPreferencesPageWidget.setTabOrder(self.uiCpuSpinBox, self.uiWhenExitKeepRadioButton)
|
||||
GNS3VMPreferencesPageWidget.setTabOrder(self.uiRefreshPushButton, self.uiRamSpinBox)
|
||||
GNS3VMPreferencesPageWidget.setTabOrder(self.uiRamSpinBox, self.uiWhenExitKeepRadioButton)
|
||||
GNS3VMPreferencesPageWidget.setTabOrder(self.uiWhenExitKeepRadioButton, self.uiWhenExitSuspendRadioButton)
|
||||
GNS3VMPreferencesPageWidget.setTabOrder(self.uiWhenExitSuspendRadioButton, self.uiWhenExitStopRadioButton)
|
||||
|
||||
@@ -136,8 +140,8 @@ class Ui_GNS3VMPreferencesPageWidget(object):
|
||||
self.uiVirtualizationGroupBox.setTitle(_translate("GNS3VMPreferencesPageWidget", "Virtualization engine"))
|
||||
self.uiEngineDescriptionLabel.setText(_translate("GNS3VMPreferencesPageWidget", "Description"))
|
||||
self.uiGNS3VMSettingsGroupBox.setTitle(_translate("GNS3VMPreferencesPageWidget", "Settings"))
|
||||
self.uiActionCloseLabel.setText(_translate("GNS3VMPreferencesPageWidget", "Action when closing GNS3:"))
|
||||
self.uiHeadlessCheckBox.setText(_translate("GNS3VMPreferencesPageWidget", "Run the VM in headless mode"))
|
||||
self.uiActionCloseLabel.setText(_translate("GNS3VMPreferencesPageWidget", "Action when closing GNS3:"))
|
||||
self.uiWhenExitKeepRadioButton.setText(_translate("GNS3VMPreferencesPageWidget", "keep the GNS3 VM running"))
|
||||
self.uiWhenExitSuspendRadioButton.setText(_translate("GNS3VMPreferencesPageWidget", "suspend the GNS3 VM"))
|
||||
self.uiVMNameLabel.setText(_translate("GNS3VMPreferencesPageWidget", "VM name:"))
|
||||
@@ -145,5 +149,6 @@ class Ui_GNS3VMPreferencesPageWidget(object):
|
||||
self.uiWhenExitStopRadioButton.setText(_translate("GNS3VMPreferencesPageWidget", "stop the GNS3 VM"))
|
||||
self.uiRamLabel.setText(_translate("GNS3VMPreferencesPageWidget", "RAM:"))
|
||||
self.uiRamSpinBox.setSuffix(_translate("GNS3VMPreferencesPageWidget", " MB"))
|
||||
self.uiCpuLabel.setText(_translate("GNS3VMPreferencesPageWidget", "vCPUs:"))
|
||||
self.uiPortLabel.setText(_translate("GNS3VMPreferencesPageWidget", "Port:"))
|
||||
self.uiAllocatevCPUsRAMCheckBox.setText(_translate("GNS3VMPreferencesPageWidget", "Allocate vCPUs and RAM"))
|
||||
self.uiCpuLabel.setText(_translate("GNS3VMPreferencesPageWidget", "vCPUs:"))
|
||||
|
||||
@@ -38,7 +38,16 @@ background-none;
|
||||
</property>
|
||||
<widget class="QWidget" name="uiCentralWidget">
|
||||
<layout class="QGridLayout">
|
||||
<property name="margin">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
@@ -62,7 +71,7 @@ background-none;
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>986</width>
|
||||
<height>42</height>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="uiEditMenu">
|
||||
@@ -129,6 +138,7 @@ background-none;
|
||||
<addaction name="uiShowPortNamesAction"/>
|
||||
<addaction name="uiLockAllAction"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="uiResetDocksAction"/>
|
||||
<addaction name="uiDocksMenu"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="uiControlMenu">
|
||||
@@ -228,7 +238,16 @@ background-none;
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
@@ -372,7 +391,16 @@ background-none;
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
@@ -438,7 +466,16 @@ background-none;
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QGridLayout">
|
||||
<property name="margin">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
@@ -482,7 +519,16 @@ background-none;
|
||||
</attribute>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="margin">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
@@ -1243,6 +1289,11 @@ background-none;
|
||||
<string>New template</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="uiResetDocksAction">
|
||||
<property name="text">
|
||||
<string>Reset docks</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/main_window.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.13.2
|
||||
# Created by: PyQt5 UI code generator 5.14.1
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
@@ -48,7 +48,7 @@ class Ui_MainWindow(object):
|
||||
self.gridlayout.addWidget(self.uiGraphicsView, 0, 0, 1, 1)
|
||||
MainWindow.setCentralWidget(self.uiCentralWidget)
|
||||
self.uiMenuBar = QtWidgets.QMenuBar(MainWindow)
|
||||
self.uiMenuBar.setGeometry(QtCore.QRect(0, 0, 986, 42))
|
||||
self.uiMenuBar.setGeometry(QtCore.QRect(0, 0, 986, 22))
|
||||
self.uiMenuBar.setObjectName("uiMenuBar")
|
||||
self.uiEditMenu = QtWidgets.QMenu(self.uiMenuBar)
|
||||
self.uiEditMenu.setObjectName("uiEditMenu")
|
||||
@@ -448,6 +448,8 @@ class Ui_MainWindow(object):
|
||||
self.uiNewTemplateAction = QtWidgets.QAction(MainWindow)
|
||||
self.uiNewTemplateAction.setIcon(icon)
|
||||
self.uiNewTemplateAction.setObjectName("uiNewTemplateAction")
|
||||
self.uiResetDocksAction = QtWidgets.QAction(MainWindow)
|
||||
self.uiResetDocksAction.setObjectName("uiResetDocksAction")
|
||||
self.uiEditMenu.addAction(self.uiSelectAllAction)
|
||||
self.uiEditMenu.addAction(self.uiSelectNoneAction)
|
||||
self.uiEditMenu.addSeparator()
|
||||
@@ -488,6 +490,7 @@ class Ui_MainWindow(object):
|
||||
self.uiViewMenu.addAction(self.uiShowPortNamesAction)
|
||||
self.uiViewMenu.addAction(self.uiLockAllAction)
|
||||
self.uiViewMenu.addSeparator()
|
||||
self.uiViewMenu.addAction(self.uiResetDocksAction)
|
||||
self.uiViewMenu.addAction(self.uiDocksMenu.menuAction())
|
||||
self.uiControlMenu.addAction(self.uiStartAllAction)
|
||||
self.uiControlMenu.addAction(self.uiSuspendAllAction)
|
||||
@@ -711,6 +714,7 @@ class Ui_MainWindow(object):
|
||||
self.uiLockAllAction.setToolTip(_translate("MainWindow", "Lock or unlock all items"))
|
||||
self.uiWebUIAction.setText(_translate("MainWindow", "Web UI - beta"))
|
||||
self.uiNewTemplateAction.setText(_translate("MainWindow", "New template"))
|
||||
self.uiResetDocksAction.setText(_translate("MainWindow", "Reset docks"))
|
||||
from ..compute_summary_view import ComputeSummaryView
|
||||
from ..console_view import ConsoleView
|
||||
from ..graphics_view import GraphicsView
|
||||
|
||||
238202
gns3/ui/resources_rc.py
238202
gns3/ui/resources_rc.py
File diff suppressed because it is too large
Load Diff
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1273</width>
|
||||
<height>1097</height>
|
||||
<width>681</width>
|
||||
<height>843</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@@ -295,24 +295,14 @@
|
||||
<string>Remote main server</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="0" column="0">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Host:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="uiRemoteMainServerHostLineEdit"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Port:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QSpinBox" name="uiRemoteMainServerPortSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
@@ -331,44 +321,75 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Auth:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QCheckBox" name="uiRemoteMainServerAuthCheckBox">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<item row="4" column="2">
|
||||
<widget class="QLineEdit" name="uiRemoteMainServerUserLineEdit"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>User:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QLineEdit" name="uiRemoteMainServerUserLineEdit"/>
|
||||
<item row="5" column="2">
|
||||
<widget class="QLineEdit" name="uiRemoteMainServerPasswordLineEdit">
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Port:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="uiRemoteMainServerHostLineEdit"/>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Password:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QLineEdit" name="uiRemoteMainServerPasswordLineEdit">
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::Password</enum>
|
||||
<item row="3" column="2">
|
||||
<widget class="QCheckBox" name="uiRemoteMainServerAuthCheckBox">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="uiRemoteMainServerProtocolLabel">
|
||||
<property name="text">
|
||||
<string>Protocol:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QComboBox" name="uiRemoteMainServerProtocolComboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>HTTP</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>HTTPS</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -404,7 +425,16 @@
|
||||
<string>Remote servers</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<property name="margin">
|
||||
<property name="leftMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="2">
|
||||
|
||||
@@ -2,16 +2,19 @@
|
||||
|
||||
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/server_preferences_page.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.9
|
||||
# Created by: PyQt5 UI code generator 5.15.2
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_ServerPreferencesPageWidget(object):
|
||||
def setupUi(self, ServerPreferencesPageWidget):
|
||||
ServerPreferencesPageWidget.setObjectName("ServerPreferencesPageWidget")
|
||||
ServerPreferencesPageWidget.resize(1273, 1097)
|
||||
ServerPreferencesPageWidget.resize(681, 843)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
@@ -149,13 +152,7 @@ class Ui_ServerPreferencesPageWidget(object):
|
||||
self.gridLayout_4.setObjectName("gridLayout_4")
|
||||
self.label_2 = QtWidgets.QLabel(self.uiRemoteMainServerGroupBox)
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.gridLayout_4.addWidget(self.label_2, 0, 0, 1, 1)
|
||||
self.uiRemoteMainServerHostLineEdit = QtWidgets.QLineEdit(self.uiRemoteMainServerGroupBox)
|
||||
self.uiRemoteMainServerHostLineEdit.setObjectName("uiRemoteMainServerHostLineEdit")
|
||||
self.gridLayout_4.addWidget(self.uiRemoteMainServerHostLineEdit, 0, 1, 1, 2)
|
||||
self.label_3 = QtWidgets.QLabel(self.uiRemoteMainServerGroupBox)
|
||||
self.label_3.setObjectName("label_3")
|
||||
self.gridLayout_4.addWidget(self.label_3, 1, 0, 1, 1)
|
||||
self.gridLayout_4.addWidget(self.label_2, 1, 0, 1, 1)
|
||||
self.uiRemoteMainServerPortSpinBox = QtWidgets.QSpinBox(self.uiRemoteMainServerGroupBox)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
@@ -165,27 +162,41 @@ class Ui_ServerPreferencesPageWidget(object):
|
||||
self.uiRemoteMainServerPortSpinBox.setMaximum(65535)
|
||||
self.uiRemoteMainServerPortSpinBox.setProperty("value", 3080)
|
||||
self.uiRemoteMainServerPortSpinBox.setObjectName("uiRemoteMainServerPortSpinBox")
|
||||
self.gridLayout_4.addWidget(self.uiRemoteMainServerPortSpinBox, 1, 1, 1, 2)
|
||||
self.gridLayout_4.addWidget(self.uiRemoteMainServerPortSpinBox, 2, 1, 1, 2)
|
||||
self.label = QtWidgets.QLabel(self.uiRemoteMainServerGroupBox)
|
||||
self.label.setObjectName("label")
|
||||
self.gridLayout_4.addWidget(self.label, 2, 0, 1, 1)
|
||||
self.uiRemoteMainServerAuthCheckBox = QtWidgets.QCheckBox(self.uiRemoteMainServerGroupBox)
|
||||
self.uiRemoteMainServerAuthCheckBox.setText("")
|
||||
self.uiRemoteMainServerAuthCheckBox.setObjectName("uiRemoteMainServerAuthCheckBox")
|
||||
self.gridLayout_4.addWidget(self.uiRemoteMainServerAuthCheckBox, 2, 2, 1, 1)
|
||||
self.label_4 = QtWidgets.QLabel(self.uiRemoteMainServerGroupBox)
|
||||
self.label_4.setObjectName("label_4")
|
||||
self.gridLayout_4.addWidget(self.label_4, 3, 0, 1, 1)
|
||||
self.gridLayout_4.addWidget(self.label, 3, 0, 1, 1)
|
||||
self.uiRemoteMainServerUserLineEdit = QtWidgets.QLineEdit(self.uiRemoteMainServerGroupBox)
|
||||
self.uiRemoteMainServerUserLineEdit.setObjectName("uiRemoteMainServerUserLineEdit")
|
||||
self.gridLayout_4.addWidget(self.uiRemoteMainServerUserLineEdit, 3, 2, 1, 1)
|
||||
self.label_5 = QtWidgets.QLabel(self.uiRemoteMainServerGroupBox)
|
||||
self.label_5.setObjectName("label_5")
|
||||
self.gridLayout_4.addWidget(self.label_5, 4, 0, 1, 2)
|
||||
self.gridLayout_4.addWidget(self.uiRemoteMainServerUserLineEdit, 4, 2, 1, 1)
|
||||
self.label_4 = QtWidgets.QLabel(self.uiRemoteMainServerGroupBox)
|
||||
self.label_4.setObjectName("label_4")
|
||||
self.gridLayout_4.addWidget(self.label_4, 4, 0, 1, 1)
|
||||
self.uiRemoteMainServerPasswordLineEdit = QtWidgets.QLineEdit(self.uiRemoteMainServerGroupBox)
|
||||
self.uiRemoteMainServerPasswordLineEdit.setEchoMode(QtWidgets.QLineEdit.Password)
|
||||
self.uiRemoteMainServerPasswordLineEdit.setObjectName("uiRemoteMainServerPasswordLineEdit")
|
||||
self.gridLayout_4.addWidget(self.uiRemoteMainServerPasswordLineEdit, 4, 2, 1, 1)
|
||||
self.gridLayout_4.addWidget(self.uiRemoteMainServerPasswordLineEdit, 5, 2, 1, 1)
|
||||
self.label_3 = QtWidgets.QLabel(self.uiRemoteMainServerGroupBox)
|
||||
self.label_3.setObjectName("label_3")
|
||||
self.gridLayout_4.addWidget(self.label_3, 2, 0, 1, 1)
|
||||
self.uiRemoteMainServerHostLineEdit = QtWidgets.QLineEdit(self.uiRemoteMainServerGroupBox)
|
||||
self.uiRemoteMainServerHostLineEdit.setObjectName("uiRemoteMainServerHostLineEdit")
|
||||
self.gridLayout_4.addWidget(self.uiRemoteMainServerHostLineEdit, 1, 1, 1, 2)
|
||||
self.label_5 = QtWidgets.QLabel(self.uiRemoteMainServerGroupBox)
|
||||
self.label_5.setObjectName("label_5")
|
||||
self.gridLayout_4.addWidget(self.label_5, 5, 0, 1, 2)
|
||||
self.uiRemoteMainServerAuthCheckBox = QtWidgets.QCheckBox(self.uiRemoteMainServerGroupBox)
|
||||
self.uiRemoteMainServerAuthCheckBox.setText("")
|
||||
self.uiRemoteMainServerAuthCheckBox.setObjectName("uiRemoteMainServerAuthCheckBox")
|
||||
self.gridLayout_4.addWidget(self.uiRemoteMainServerAuthCheckBox, 3, 2, 1, 1)
|
||||
self.uiRemoteMainServerProtocolLabel = QtWidgets.QLabel(self.uiRemoteMainServerGroupBox)
|
||||
self.uiRemoteMainServerProtocolLabel.setObjectName("uiRemoteMainServerProtocolLabel")
|
||||
self.gridLayout_4.addWidget(self.uiRemoteMainServerProtocolLabel, 0, 0, 1, 1)
|
||||
self.uiRemoteMainServerProtocolComboBox = QtWidgets.QComboBox(self.uiRemoteMainServerGroupBox)
|
||||
self.uiRemoteMainServerProtocolComboBox.setObjectName("uiRemoteMainServerProtocolComboBox")
|
||||
self.uiRemoteMainServerProtocolComboBox.addItem("")
|
||||
self.uiRemoteMainServerProtocolComboBox.addItem("")
|
||||
self.gridLayout_4.addWidget(self.uiRemoteMainServerProtocolComboBox, 0, 1, 1, 2)
|
||||
self.verticalLayout.addWidget(self.uiRemoteMainServerGroupBox)
|
||||
spacerItem2 = QtWidgets.QSpacerItem(10, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.verticalLayout.addItem(spacerItem2)
|
||||
@@ -290,11 +301,14 @@ class Ui_ServerPreferencesPageWidget(object):
|
||||
self.uiUDPPortRangeLabel.setText(_translate("ServerPreferencesPageWidget", "to"))
|
||||
self.uiRemoteMainServerGroupBox.setTitle(_translate("ServerPreferencesPageWidget", "Remote main server"))
|
||||
self.label_2.setText(_translate("ServerPreferencesPageWidget", "Host:"))
|
||||
self.label_3.setText(_translate("ServerPreferencesPageWidget", "Port:"))
|
||||
self.uiRemoteMainServerPortSpinBox.setSuffix(_translate("ServerPreferencesPageWidget", " TCP"))
|
||||
self.label.setText(_translate("ServerPreferencesPageWidget", "Auth:"))
|
||||
self.label_4.setText(_translate("ServerPreferencesPageWidget", "User:"))
|
||||
self.label_3.setText(_translate("ServerPreferencesPageWidget", "Port:"))
|
||||
self.label_5.setText(_translate("ServerPreferencesPageWidget", "Password:"))
|
||||
self.uiRemoteMainServerProtocolLabel.setText(_translate("ServerPreferencesPageWidget", "Protocol:"))
|
||||
self.uiRemoteMainServerProtocolComboBox.setItemText(0, _translate("ServerPreferencesPageWidget", "HTTP"))
|
||||
self.uiRemoteMainServerProtocolComboBox.setItemText(1, _translate("ServerPreferencesPageWidget", "HTTPS"))
|
||||
self.uiServerPreferenceTabWidget.setTabText(self.uiServerPreferenceTabWidget.indexOf(self.uiLocalTabWidget), _translate("ServerPreferencesPageWidget", "Main server"))
|
||||
self.uiRemoteServersTreeWidget.headerItem().setText(0, _translate("ServerPreferencesPageWidget", "Name"))
|
||||
self.uiRemoteServersTreeWidget.headerItem().setText(4, _translate("ServerPreferencesPageWidget", "User"))
|
||||
@@ -304,4 +318,3 @@ class Ui_ServerPreferencesPageWidget(object):
|
||||
self.label_7.setText(_translate("ServerPreferencesPageWidget", "Note: Changes are not visible in other part of the settings or application until you apply them."))
|
||||
self.uiServerPreferenceTabWidget.setTabText(self.uiServerPreferenceTabWidget.indexOf(self.uiRemoteTabWidget), _translate("ServerPreferencesPageWidget", "Remote servers"))
|
||||
self.uiRestoreDefaultsPushButton.setText(_translate("ServerPreferencesPageWidget", "Restore defaults"))
|
||||
|
||||
|
||||
@@ -2,14 +2,6 @@
|
||||
<ui version="4.0">
|
||||
<class>StyleEditorDialog</class>
|
||||
<widget class="QDialog" name="StyleEditorDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>328</width>
|
||||
<height>252</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Style editor</string>
|
||||
</property>
|
||||
@@ -22,7 +14,7 @@
|
||||
<property name="title">
|
||||
<string>Style settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="uiColorLabel">
|
||||
<property name="text">
|
||||
|
||||
@@ -1,58 +1,58 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file '/Users/noplay/code/gns3/gns3-gui/gns3/ui/style_editor_dialog.ui'
|
||||
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/style_editor_dialog.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.4.2
|
||||
# Created by: PyQt5 UI code generator 5.15.2
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_StyleEditorDialog(object):
|
||||
|
||||
def setupUi(self, StyleEditorDialog):
|
||||
StyleEditorDialog.setObjectName("StyleEditorDialog")
|
||||
StyleEditorDialog.resize(328, 252)
|
||||
StyleEditorDialog.setModal(True)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(StyleEditorDialog)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.uiStyleSettingsGroupBox = QtWidgets.QGroupBox(StyleEditorDialog)
|
||||
self.uiStyleSettingsGroupBox.setObjectName("uiStyleSettingsGroupBox")
|
||||
self.gridLayout = QtWidgets.QGridLayout(self.uiStyleSettingsGroupBox)
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.formLayout = QtWidgets.QFormLayout(self.uiStyleSettingsGroupBox)
|
||||
self.formLayout.setObjectName("formLayout")
|
||||
self.uiColorLabel = QtWidgets.QLabel(self.uiStyleSettingsGroupBox)
|
||||
self.uiColorLabel.setObjectName("uiColorLabel")
|
||||
self.gridLayout.addWidget(self.uiColorLabel, 0, 0, 1, 1)
|
||||
self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.uiColorLabel)
|
||||
self.uiColorPushButton = QtWidgets.QPushButton(self.uiStyleSettingsGroupBox)
|
||||
self.uiColorPushButton.setText("")
|
||||
self.uiColorPushButton.setObjectName("uiColorPushButton")
|
||||
self.gridLayout.addWidget(self.uiColorPushButton, 0, 1, 1, 1)
|
||||
self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.uiColorPushButton)
|
||||
self.uiBorderColorLabel = QtWidgets.QLabel(self.uiStyleSettingsGroupBox)
|
||||
self.uiBorderColorLabel.setObjectName("uiBorderColorLabel")
|
||||
self.gridLayout.addWidget(self.uiBorderColorLabel, 1, 0, 1, 1)
|
||||
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.uiBorderColorLabel)
|
||||
self.uiBorderColorPushButton = QtWidgets.QPushButton(self.uiStyleSettingsGroupBox)
|
||||
self.uiBorderColorPushButton.setText("")
|
||||
self.uiBorderColorPushButton.setObjectName("uiBorderColorPushButton")
|
||||
self.gridLayout.addWidget(self.uiBorderColorPushButton, 1, 1, 1, 1)
|
||||
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.uiBorderColorPushButton)
|
||||
self.uiBorderWidthLabel = QtWidgets.QLabel(self.uiStyleSettingsGroupBox)
|
||||
self.uiBorderWidthLabel.setObjectName("uiBorderWidthLabel")
|
||||
self.gridLayout.addWidget(self.uiBorderWidthLabel, 2, 0, 1, 1)
|
||||
self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.uiBorderWidthLabel)
|
||||
self.uiBorderWidthSpinBox = QtWidgets.QSpinBox(self.uiStyleSettingsGroupBox)
|
||||
self.uiBorderWidthSpinBox.setMinimum(1)
|
||||
self.uiBorderWidthSpinBox.setMaximum(100)
|
||||
self.uiBorderWidthSpinBox.setProperty("value", 2)
|
||||
self.uiBorderWidthSpinBox.setObjectName("uiBorderWidthSpinBox")
|
||||
self.gridLayout.addWidget(self.uiBorderWidthSpinBox, 2, 1, 1, 1)
|
||||
self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.uiBorderWidthSpinBox)
|
||||
self.uiBorderStyleLabel = QtWidgets.QLabel(self.uiStyleSettingsGroupBox)
|
||||
self.uiBorderStyleLabel.setObjectName("uiBorderStyleLabel")
|
||||
self.gridLayout.addWidget(self.uiBorderStyleLabel, 3, 0, 1, 1)
|
||||
self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.uiBorderStyleLabel)
|
||||
self.uiBorderStyleComboBox = QtWidgets.QComboBox(self.uiStyleSettingsGroupBox)
|
||||
self.uiBorderStyleComboBox.setObjectName("uiBorderStyleComboBox")
|
||||
self.gridLayout.addWidget(self.uiBorderStyleComboBox, 3, 1, 1, 1)
|
||||
self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.uiBorderStyleComboBox)
|
||||
self.uiRotationLabel = QtWidgets.QLabel(self.uiStyleSettingsGroupBox)
|
||||
self.uiRotationLabel.setObjectName("uiRotationLabel")
|
||||
self.gridLayout.addWidget(self.uiRotationLabel, 4, 0, 1, 1)
|
||||
self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.uiRotationLabel)
|
||||
self.uiRotationSpinBox = QtWidgets.QSpinBox(self.uiStyleSettingsGroupBox)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
@@ -62,11 +62,11 @@ class Ui_StyleEditorDialog(object):
|
||||
self.uiRotationSpinBox.setMinimum(-360)
|
||||
self.uiRotationSpinBox.setMaximum(360)
|
||||
self.uiRotationSpinBox.setObjectName("uiRotationSpinBox")
|
||||
self.gridLayout.addWidget(self.uiRotationSpinBox, 4, 1, 1, 1)
|
||||
self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.uiRotationSpinBox)
|
||||
self.verticalLayout.addWidget(self.uiStyleSettingsGroupBox)
|
||||
self.uiButtonBox = QtWidgets.QDialogButtonBox(StyleEditorDialog)
|
||||
self.uiButtonBox.setOrientation(QtCore.Qt.Horizontal)
|
||||
self.uiButtonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Apply | QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok)
|
||||
self.uiButtonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Apply|QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
|
||||
self.uiButtonBox.setObjectName("uiButtonBox")
|
||||
self.verticalLayout.addWidget(self.uiButtonBox)
|
||||
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
@@ -88,7 +88,6 @@ class Ui_StyleEditorDialog(object):
|
||||
self.uiBorderStyleLabel.setText(_translate("StyleEditorDialog", "Border style:"))
|
||||
self.uiRotationLabel.setText(_translate("StyleEditorDialog", "Rotation:"))
|
||||
self.uiRotationSpinBox.setToolTip(_translate("StyleEditorDialog", "Rotation can be ajusted on the scene for a selected item while\n"
|
||||
"editing (notes only) with ALT and \'+\' (or P) / ALT and \'-\' (or M)"))
|
||||
"editing (notes only) with ALT and \'+\' (or P) / ALT and \'-\' (or M)"))
|
||||
self.uiRotationSpinBox.setSuffix(_translate("StyleEditorDialog", "°"))
|
||||
|
||||
from . import resources_rc
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
# or negative for a release candidate or beta (after the base version
|
||||
# number has been incremented)
|
||||
|
||||
__version__ = "2.2.13"
|
||||
__version_info__ = (2, 2, 13, 0) # If it's a git checkout try to add the commit
|
||||
__version__ = "2.2.32"
|
||||
__version_info__ = (2, 2, 32, 0)
|
||||
|
||||
if "dev" in __version__:
|
||||
try:
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
-rrequirements.txt
|
||||
|
||||
PyQt5==5.15.6
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
jsonschema==3.2.0
|
||||
sentry-sdk>=0.14.4
|
||||
psutil==5.6.7
|
||||
distro>=1.3.0
|
||||
sentry-sdk==1.5.10
|
||||
psutil==5.9.0
|
||||
distro==1.6.0
|
||||
setuptools==60.6.0; python_version >= '3.7' # don't upgrade because of https://github.com/pypa/setuptools/issues/3084
|
||||
setuptools==59.6.0; python_version < '3.7' # v59.7.0 dropped support for Python 3.6
|
||||
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1"
|
||||
id="svg7631" xmlns:cc="http://creativecommons.org/ns#" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" sodipodi:docname="camera-photo.svg" sodipodi:version="0.32" inkscape:version="0.48.3.1 r9886" inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 48 48"
|
||||
enable-background="new 0 0 48 48" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#231F20" d="M42.8,38.4l-7.4-9c1.6-2.6,2.5-5.6,2.5-8.8c0-9.3-7.5-16.8-16.8-16.8S4.3,11.3,4.3,20.6
|
||||
c0,9.3,7.5,16.8,16.8,16.8c3.7,0,7.1-1.2,9.9-3.2l6.8,8.3c0.6,0.7,1.5,0.8,2.2,0.2l2.5-2.1C43.2,40.1,43.3,39.1,42.8,38.4z
|
||||
M9,20.6c0-6.7,5.4-12.1,12.1-12.1s12.1,5.4,12.1,12.1c0,6.7-5.4,12.1-12.1,12.1S9,27.3,9,20.6z"/>
|
||||
<polygon fill="#231F20" points="27.6,19 23.2,19 23.2,14.4 19,14.4 19,19 14.5,19 14.5,23.2 19,23.2 19,27.8 23.2,27.8 23.2,23.2
|
||||
27.6,23.2 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#CDCDCD" d="M42.6,40l-7.4-9c1.6-2.6,2.5-5.6,2.5-8.8C37.7,13,30.2,5.4,21,5.4S4.2,13,4.2,22.2C4.2,31.5,11.7,39,21,39
|
||||
c3.7,0,7.1-1.2,9.9-3.2l6.8,8.3c0.6,0.7,1.5,0.8,2.2,0.2l2.5-2.1C43.1,41.7,43.2,40.7,42.6,40z M8.9,22.2
|
||||
c0-6.7,5.4-12.1,12.1-12.1S33,15.6,33,22.2c0,6.7-5.4,12.1-12.1,12.1S8.9,28.9,8.9,22.2z"/>
|
||||
<polygon fill="#CDCDCD" points="27.8,20.6 23.2,20.6 23.2,16 18.9,16 18.9,20.6 14.4,20.6 14.4,24.9 18.9,24.9 18.9,29.4
|
||||
23.2,29.4 23.2,24.9 27.8,24.9 "/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.9 KiB |
@@ -1,4 +1,5 @@
|
||||
QWidget {
|
||||
color: black;
|
||||
background-color: #535353;
|
||||
}
|
||||
|
||||
@@ -7,10 +8,12 @@ QToolBar {
|
||||
}
|
||||
|
||||
QGraphicsView, QTextEdit, QPlainTextEdit, QTreeWidget, QListWidget, QLineEdit, QSpinBox, QComboBox {
|
||||
background-color: #dedede
|
||||
color: black;
|
||||
background-color: #dedede;
|
||||
}
|
||||
|
||||
QLabel, QMenu, QStatusBar {
|
||||
color: black;
|
||||
color: #dedede;
|
||||
}
|
||||
|
||||
@@ -48,6 +51,7 @@ QComboBox {
|
||||
}
|
||||
|
||||
QComboBox QAbstractItemView {
|
||||
color: black;
|
||||
background-color: #dedede;
|
||||
}
|
||||
|
||||
|
||||
2
setup.py
2
setup.py
@@ -96,6 +96,8 @@ setup(
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: Implementation :: CPython",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -171,8 +171,8 @@ def test_create_new_version():
|
||||
os.path.dirname(__file__), "appliances", "microcore-linux.gns3a")
|
||||
|
||||
a = Appliance(registry, appliance_path)
|
||||
|
||||
a.create_new_version("42.0")
|
||||
new_version = {'images': {'hda_disk_image': {'filename': 'linux-microcore-42.0.img', 'version': '42.0'}}, 'name': '42.0'}
|
||||
a.create_new_version(new_version)
|
||||
v = a['versions'][-1:][0]
|
||||
assert v == {
|
||||
'images':
|
||||
|
||||
@@ -65,6 +65,7 @@ def link(devices, controller, project):
|
||||
{"node_id": devices[0].node_id(), "adapter_number": 0, "port_number": 0},
|
||||
{"node_id": devices[1].node_id(), "adapter_number": 0, "port_number": 0}
|
||||
],
|
||||
"link_style": {},
|
||||
"filters": {},
|
||||
}
|
||||
|
||||
@@ -89,6 +90,7 @@ def test_create_link(devices, project, controller):
|
||||
{"node_id": devices[0].node_id(), "adapter_number": 0, "port_number": 0},
|
||||
{"node_id": devices[1].node_id(), "adapter_number": 0, "port_number": 0},
|
||||
],
|
||||
"link_style": {},
|
||||
"filters": {},
|
||||
}
|
||||
|
||||
@@ -102,9 +104,6 @@ def test_create_link(devices, project, controller):
|
||||
assert link._link_id is not None
|
||||
assert not devices[0].ports()[0].isFree()
|
||||
|
||||
assert link in devices[0].links()
|
||||
assert link in devices[1].links()
|
||||
|
||||
assert link.getNodePort(devices[0]) == devices[0].ports()[0]
|
||||
assert link.getNodePort(devices[1]) == devices[1].ports()[0]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
-rrequirements.txt
|
||||
|
||||
PyQt5==5.12.3 # pyup: ignore
|
||||
pywin32>=223 # pyup: ignore
|
||||
PyQt5==5.15.6 # pyup: ignore
|
||||
pywin32==303 # pyup: ignore
|
||||
|
||||
Reference in New Issue
Block a user