Compare commits

...

237 Commits

Author SHA1 Message Date
grossmj
cf3e716e63 Release v2.2.26 2021-10-08 21:02:04 +10:30
grossmj
c79f14bcab Open "template configuration" dialog with double click on template name in "Preferences". Fixes #3239 2021-10-08 16:35:25 +10:30
grossmj
acd044a88a Only show "virtio" network adapter when legacy node is enabled. Fixes https://github.com/GNS3/gns3-gui/issues/1969 2021-10-08 15:46:56 +10:30
grossmj
ab854752d9 Double-click on a template opens "template configuration" dialog. Fixes #3236 2021-09-20 20:28:56 +09:30
grossmj
5cee045a65 Fix "Custom symbols" can't be unfolded after using "Filter" field. Fixes #3231 2021-09-20 18:39:32 +09:30
grossmj
37cd82fb44 Development on v2.2.26dev1 2021-09-14 21:13:04 +09:30
grossmj
334eb5175c Release v2.2.25 2021-09-14 19:20:11 +09:30
grossmj
25841ea7db Fix menu disabled for modal dialogs on macOS. Fixes #3007 2021-09-09 21:21:22 +09:30
grossmj
3d3b4f92b2 Change method to display the recent files menu. Fixes #3007 2021-09-09 09:23:45 +09:30
grossmj
82740da89d Fix bug when using empty port names for custom adapters. Fixes #3228 2021-09-08 16:16:27 +09:30
grossmj
ad19b3dda0 Upgrade PyQt5 to version 5.15.4 for macOS 2021-09-08 15:36:04 +09:30
grossmj
bb8fd18f98 Fix mouse zoom-in/out step value is two times bigger than keyboard one. Fixes #3226 2021-09-08 15:26:56 +09:30
grossmj
336eaf443a Upgrade to Qt 5.15.4 on Windows. Ref #3210 2021-09-08 14:25:25 +09:30
grossmj
0b94be6805 Fix issue with custom adapters at the node level. Fixes #3223 2021-09-05 21:15:30 +09:30
grossmj
671ced78ff Merge branch 'master' into 2.2 2021-09-02 14:45:00 +09:30
Jeremy Grossmann
c8766ce529 Merge pull request #3157 from hrnciar/setuptools
Explicitly require setuptools, utils/get_resource.py imports pkg_resources
2021-08-29 22:06:22 -07:00
Jeremy Grossmann
bec9512c78 Merge branch 'master' into setuptools 2021-08-29 22:02:55 -07:00
grossmj
b2ad5f4158 Development on 2.2.25dev1 2021-08-25 21:23:19 +09:30
grossmj
966873bc6c Release v2.2.24 2021-08-25 20:31:26 +09:30
grossmj
5b9111b55d Merge branch 'master' into 2.2 2021-08-25 20:08:45 +09:30
grossmj
56688f2236 Update dependencies 2021-08-24 21:12:27 +09:30
grossmj
2e656a9d53 Fix incorrect Qemu binary selected when importing template. Fixes https://github.com/GNS3/gns3-gui/issues/3216 2021-08-24 17:26:07 +09:30
grossmj
2790f707c3 Early support for Python3.10 2021-08-15 15:10:02 +09:30
Jeremy Grossmann
ee9002df61 Merge pull request #3217 from GNS3/dependabot/pip/pywin32-301
Bump pywin32 from 300 to 301
2021-08-09 17:59:04 -07:00
dependabot[bot]
52626e9fe9 Bump pywin32 from 300 to 301
Bumps [pywin32](https://github.com/mhammond/pywin32) from 300 to 301.
- [Release notes](https://github.com/mhammond/pywin32/releases)
- [Changelog](https://github.com/mhammond/pywin32/blob/master/CHANGES.txt)
- [Commits](https://github.com/mhammond/pywin32/commits)

---
updated-dependencies:
- dependency-name: pywin32
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-09 20:48:41 +00:00
grossmj
6619c6af97 Add PyQt5==5.12.3 for macOS build 2021-08-07 20:09:41 +09:30
grossmj
60e04c7248 Development on 2.2.24dev1 2021-08-05 21:16:10 +09:30
grossmj
724858f977 Release v2.2.23 2021-08-05 15:58:54 +09:30
Jeremy Grossmann
5a2e05a4fd Merge pull request #3212 from GNS3/handle_no-kvm_deprecated
Handle -no-kvm param deprecated in Qemu >= v5.2
2021-07-27 17:37:45 +09:30
grossmj
010888e3ca Handle -no-kvm param deprecated in Qemu >= v5.2 2021-07-27 16:34:51 +09:30
grossmj
3226921536 Support for invisible links. Fixes #2461 2021-07-27 15:30:58 +09:30
grossmj
022e918301 Add kitty console application command line. Fixes #3203 2021-07-25 16:12:35 +09:30
grossmj
846b19a9e7 Add Windows Terminal profile as an option for Console Applications. Fixes #3193 2021-06-14 13:10:01 +09:30
grossmj
45f5c6e010 Development on 2.2.23dev1 2021-06-10 16:20:10 +09:30
grossmj
963bbb7b89 Release v2.2.22 2021-06-10 15:41:58 +09:30
grossmj
016ad7a775 Fix exception shown when GNS3 is started with empty config. Fixes #3188 2021-06-10 12:28:25 +09:30
grossmj
e8c82566c6 Add ZOC8 console terminal for macOS command line 2021-06-07 19:41:09 +09:30
grossmj
1ed6fceade Fix tests. Ref https://github.com/GNS3/gns3-gui/issues/2461 2021-06-07 14:26:20 +09:30
grossmj
d945fd8b7b Minor changes to style editor dialog. 2021-06-07 14:10:32 +09:30
grossmj
fd6c7eccd0 Link style support. Fixes https://github.com/GNS3/gns3-gui/issues/2461 2021-06-07 14:09:58 +09:30
grossmj
7a1afe2aec Upgrade dependencies 2021-06-07 13:46:06 +09:30
grossmj
6debe56d8e Fix charcoal theme. Ref #3137 2021-06-06 21:45:16 +09:30
grossmj
a4c7d41c26 Fix issue when showing menu to select port. Fixes #3169 2021-05-20 22:15:21 -07:00
grossmj
ea9243dcd9 Merge remote-tracking branch 'origin/2.2' into 2.2 2021-05-20 15:00:49 +09:30
grossmj
e9d8337bd6 Revert "Downgrade to PyQt5 5.12.1. Fixes https://github.com/GNS3/gns3-gui/issues/3169"
This reverts commit ece4d51213.
2021-05-20 14:59:44 +09:30
Jeremy Grossmann
3c92e463f8 Update setup.py
Fixes https://github.com/GNS3/gns3-server/issues/1897
2021-05-16 17:45:11 +09:30
grossmj
3d07db5c5f Development on 2.2.22dev1 2021-05-10 23:44:40 +09:30
grossmj
20cc309ac8 Release v2.2.21 2021-05-10 22:42:47 +09:30
grossmj
262a2839c5 Fix issue with empty project variable name. Fixes #3162 2021-05-10 17:55:06 +09:30
grossmj
ece4d51213 Downgrade to PyQt5 5.12.1. Fixes https://github.com/GNS3/gns3-gui/issues/3169 2021-05-10 17:03:22 +09:30
grossmj
0ef39ba129 Development on 2.2.21dev1 2021-04-09 13:50:21 +09:30
grossmj
f90267b4f0 Release v2.2.20 2021-04-09 12:14:38 +09:30
grossmj
8f16706a22 Merge branch 'master' into 2.2 2021-04-09 12:05:15 +09:30
grossmj
2d3ee3abf9 Fix project does not load anymore. Fixes #3140 2021-04-07 16:47:09 +09:30
grossmj
b8b209fa55 Fix errors while connecting to server 2021-04-07 15:51:52 +09:30
grossmj
18129e3d29 Do not connect to server while waiting for user to accept/reject SSL certificate. Fixes #3144 2021-04-07 12:09:38 +09:30
grossmj
7a2b9c024f Fix invalid server version check request. Fixes #3144 2021-04-07 12:03:37 +09:30
grossmj
4923a6dc17 Revert to PyQt5 v5.12.3 because of SSL not working
Probably the SSL DLLs weren't properly found and included by cx_Freeze
2021-04-06 23:01:07 +09:30
grossmj
73dfc047aa Set PyQt5 version to 5.15.2 on Windows 2021-04-06 22:12:34 +09:30
grossmj
fe0a70c4be Upgrade dependencies 2021-04-06 13:57:00 +09:30
Tomas Hrnciar
67014965be Explicitly require setuptools, utils/get_resource.py imports pkg_resources 2021-03-31 11:53:28 +02:00
Jeremy Grossmann
f14cb43404 Merge pull request #3153 from VidVidex/master
Add terminator as a predefined custom console option
2021-03-26 14:53:00 +10:30
Vid
f8517ee5ac Add terminator as a predefined custom console option 2021-03-24 20:28:19 +01:00
grossmj
7dc607b4c5 Development on 2.2.20dev1 2021-03-05 16:48:09 +10:30
grossmj
882fa76550 Release v2.2.19 2021-03-05 14:51:03 +10:30
grossmj
1490a1ad8f Development on 2.2.19dev1 2021-02-16 20:44:58 +10:30
grossmj
aab0c99cc6 Release v2.2.18 2021-02-16 19:09:46 +10:30
grossmj
a6a987d74c Fix bug with SSL connection on projet websocket stream. 2021-02-16 17:42:18 +10:30
grossmj
9c58b18c20 Merge remote-tracking branch 'origin/2.2' into 2.2 2021-02-16 16:42:45 +10:30
grossmj
8bc499c68f Bump version to 2.2.18dev2 2021-02-16 16:35:26 +10:30
Jeremy Grossmann
bd5eb288b7 Merge pull request #3130 from GNS3/ssl-support
SSL support.
2021-02-16 16:16:32 +10:30
grossmj
465a289568 SSL support. 2021-02-16 16:08:27 +10:30
grossmj
d240ba3056 Merge remote-tracking branch 'origin/2.2' into 2.2 2021-01-26 23:11:11 +10:30
grossmj
3cedfd3649 Remove the useless file "zoom-in (copy).svg". Fixes #3114 2021-01-26 23:10:34 +10:30
Jeremy Grossmann
276d7abdd9 Merge pull request #3104 from b-ehlers/QemuConfig
Add Qemu config disk
2020-12-14 14:23:09 +10:30
grossmj
927e38bd6d Development on 2.2.18dev1 2020-12-04 18:10:11 +10:30
grossmj
376cc29995 Release v2.2.17 2020-12-04 16:26:56 +10:30
grossmj
1f8ebeb084 Merge branch 'master' into 2.2 2020-12-04 16:21:42 +10:30
grossmj
0212755c78 Remove "-nographic" option by default for Qemu VM. Fixes #3094 2020-12-02 18:44:18 +10:30
Jeremy Grossmann
2f7d75eae9 Fix app cannot start on macOS Big Sur. Ref #3037 2020-11-30 20:02:52 +10:30
Jeremy Grossmann
fc1c060922 Merge pull request #3097 from SpikefishSolutions/master
Add yes/no prompts to gui for global project level buttons start/stop/reload/suspend to prevent bad day.
2020-11-21 18:32:45 +10:30
John
0ea72ce782 one more spacing update 2020-11-20 21:33:44 -05:00
John
3de2d2eda2 spacing updates 2020-11-20 21:32:26 -05:00
John
c08262f8af Correct stop/start/reload/suspend button names 2020-11-20 21:26:08 -05:00
John
9ae70bf2fe Add yes/no prompts to all major buttons 2020-11-20 21:11:15 -05:00
John
fa6d250602 oops.. need to build after commit. 2020-11-20 20:27:43 -05:00
John
0668840a2b i don't get it. 2020-11-20 20:26:19 -05:00
John
8b25d1b06c can't fix indent? 2020-11-20 20:25:06 -05:00
John
58c3ba0755 update indent 2020-11-20 20:23:46 -05:00
John
5a91c9aaf8 Create a message box for stopping all devives instead of blindly making someone's day terrible. 2020-11-20 18:28:30 -05:00
grossmj
0fc3f4ef16 Development on 2.2.17dev1 2020-11-05 16:59:58 +10:30
grossmj
f0e5cd2ba2 Release v2.2.16 2020-11-05 15:38:19 +10:30
grossmj
f59ef6378a Fix broken security link (replaced by email). Fixes #3085 2020-11-05 15:00:04 +10:30
grossmj
61ef08d1b7 Fix packets capture stops after some time. Fixes #3067 2020-11-05 14:21:22 +10:30
grossmj
e812c000fd Option to allocate or not the vCPUs and RAM settings for the GNS3 VM. Fixes https://github.com/GNS3/gns3-gui/issues/3069 2020-11-05 11:13:57 +10:30
Bernhard Ehlers
d3d9e1e8ae Use HDD disk image as startup QEMU config disk 2020-10-19 03:45:27 +02:00
Bernhard Ehlers
05f8df345a Fix HDD configuration layout
(cherry picked from commit 4f631669e5)
2020-10-16 10:22:32 +02:00
grossmj
4b0cc11cab Development on 2.2.16dev1 2020-10-07 16:30:03 +10:30
grossmj
b5285cd142 Release v2.2.15 2020-10-07 15:29:52 +10:30
grossmj
69482343ba Fix custom symbol not sent to remote controller when installing appliance 2020-10-07 15:09:08 +10:30
grossmj
d4639c2e61 Development on 2.2.15dev1 2020-09-15 06:49:11 +09:30
grossmj
b85ade9dd7 Release v2.2.14 2020-09-15 05:52:48 +09:30
grossmj
e191cb8aa3 Fix tests. Ref #3002 2020-09-14 00:10:11 +09:30
grossmj
e6bc75ce26 Improvements to add a new version of an appliance from wizard. Fixes #3002. 2020-09-14 00:04:58 +09:30
grossmj
bc1df346f2 Development on 2.2.14dev1 2020-09-05 04:26:16 +09:30
grossmj
27c35321f0 Release v2.2.13 2020-09-04 23:13:28 +09:30
Bernhard Ehlers
3e212fc629 Edit only text mode config files
(cherry picked from commit 880ac5e8c3)
2020-08-18 02:27:31 +02:00
Bernhard Ehlers
25e41dc0f1 Hide config import/export when configFiles attribute is empty
(cherry picked from commit fd7b915e96)
2020-08-17 13:09:59 +02:00
grossmj
c58c7774c4 Qemu disk interfaces must be set to "none" by default. Ref #3035
(cherry picked from commit 5fbb6cbf61)
2020-08-17 12:49:21 +09:30
grossmj
bd2bc8265c Do not allow image to be configured on Qemu VM secondary slave disk if create config disk option is enabled.
(cherry picked from commit 04f9a1cf8c)
2020-08-15 16:05:43 +09:30
grossmj
f2209a2780 Add explicit option to automatically create or not the config disk. Off by default.
(cherry picked from commit af79471afd)
2020-08-14 17:57:24 +09:30
grossmj
7b99ba325b Development on 2.2.13dev1 2020-08-07 21:12:46 +09:30
grossmj
74763287fb Release v2.2.12 2020-08-07 19:27:32 +09:30
grossmj
737ff42d64 Merge branch 'master' into 2.2 2020-08-07 19:04:08 +09:30
Jeremy Grossmann
5656bd2d48 Downgrade psutil to version 5.6.7 2020-07-29 17:36:14 +09:30
Jeremy Grossmann
058c069394 Fix log shows the GUI command line without spaces between its arguments. Fixes #3026 2020-07-27 18:27:23 +09:30
grossmj
926ec48d00 Upgrade to psutil version 5.7.2 2020-07-21 15:49:58 +09:30
grossmj
410e5353b2 Use server host is console host is equal to "0:0:0:0:0:0:0:0" 2020-07-17 21:13:27 +09:30
grossmj
bfb90406ed Remove VMware promotion. 2020-07-17 21:12:59 +09:30
grossmj
439cdce287 Development on 2.2.12dev1 2020-07-09 21:37:03 +09:30
grossmj
4e50c2a4b1 Release v2.2.11 2020-07-09 20:37:10 +09:30
grossmj
94c636ae61 Merge branch 'master' into 2.2 2020-07-09 20:23:31 +09:30
grossmj
f53b9a266e Try to fix "Recent project" selection not working. Ref #3007 2020-07-09 15:37:47 +09:30
grossmj
2476448032 Fix debug entries shown twice in console window and double error messages with remote GNS3VM. Fixes #3010 #3011
Note that the debug level is broken (has been for a long time apparently).
2020-07-07 21:06:56 +09:30
grossmj
a34cd742e3 Merge branch '2.2' 2020-07-06 22:20:05 +09:30
grossmj
39698196ac Fix deprecation warning. Ref #3009 2020-07-06 22:08:10 +09:30
grossmj
61432ced4f Fix tests on macOS. Ref #3009 2020-07-06 22:03:29 +09:30
grossmj
2ddd13c445 Add Snyk badges. 2020-06-27 18:27:04 +09:30
grossmj
af6c4c5b3e Merge branch 'master' into 2.2 2020-06-26 21:30:37 +09:30
grossmj
d4012294bf Run tests inside container 2020-06-26 20:50:48 +09:30
grossmj
4b04b0e855 Use xvfb to run tests 2020-06-26 20:41:08 +09:30
grossmj
1bec5019bf Install PyQt5 using pip 2020-06-26 19:42:42 +09:30
grossmj
ec6b876baa Explicitly install sip 2020-06-26 19:38:10 +09:30
grossmj
7cee0d01ab Install PyQt5 for tests and add GitHub Actions badge 2020-06-26 19:34:02 +09:30
Jeremy Grossmann
dd3314d06b Set up GitHub Actions for running tests 2020-06-26 19:27:22 +09:30
grossmj
9c58b26265 Remove tox, Travis CI and pep8.sh script
Update dependencies
2020-06-26 19:21:51 +09:30
Jeremy Grossmann
83c26f47da Merge pull request #3005 from GNS3/whitesource/configure
Configure WhiteSource for GitHub.com
2020-06-26 09:04:39 +08:00
whitesource-for-github-com[bot]
8ed2f55600 Add .whitesource configuration file 2020-06-26 01:01:54 +00:00
Jeremy Grossmann
b435317904 Merge pull request #3003 from GNS3/snyk-fix-8bf3e4840df4587cc42afb85b857d470
[Snyk] Security upgrade psutil from 5.6.6 to 5.6.7
2020-06-25 11:41:01 +08:00
snyk-bot
acb8aa8ca2 fix: requirements.txt to reduce vulnerabilities
The following vulnerabilities are fixed by pinning transitive dependencies:
- https://snyk.io/vuln/SNYK-PYTHON-PSUTIL-483082
2020-06-24 13:10:33 +00:00
grossmj
c55d6b8a6f Fix sentry SDK is configured twice. 2020-06-24 12:40:06 +09:30
grossmj
a4039a254e Development on 2.2.11dev1 2020-06-18 19:06:00 +09:30
grossmj
85ed4b3026 Release v2.2.10 2020-06-18 12:29:33 +09:30
grossmj
5207a99692 New fix for multi-device selection/deselection not working as expected with right click. Fixes #2986 2020-06-09 13:50:31 +09:30
grossmj
d69527995d Revert "Fix Multi-device selection/deselection not working as expected with right click. Fixes #2986"
This reverts commit ddeb95cb0a.
2020-06-09 13:19:20 +09:30
grossmj
4b000ba2f7 Optimize snap-to-grid code for drawing items. Fixes #2997 2020-06-09 11:47:05 +09:30
grossmj
1b302b77a0 Move jsonschema 2.6.0 requirement in build repository.
https://github.com/GNS3/gns3-server/issues/1751
https://github.com/GNS3/gns3-gui/issues/2849

This is to avoid the following error:

```
ERROR: Double requirement given: jsonschema==2.6.0 (from -r gns3-gui\win-requirements.txt (line 4)) (already in jsonschema==3.2.0 (from -r gns3-gui\requirements.txt (line 1)), name='jsonschema')
```
2020-06-07 13:07:16 +09:30
grossmj
a5b5c404ec Only use jsonschema 2.6.0 on Windows and macOS.
https://github.com/GNS3/gns3-server/issues/1751
https://github.com/GNS3/gns3-gui/issues/2849
2020-06-07 12:55:22 +09:30
grossmj
6b97b0c6cd Disable default integrations for sentry sdk. 2020-06-06 15:37:17 +09:30
grossmj
115dd43eee Development on 2.2.10dev1 2020-06-04 21:06:30 +09:30
grossmj
2530bf97a8 Release v2.2.9 2020-06-04 18:39:27 +09:30
grossmj
9892fd0654 Fix issue editing README.txt on Windows. 2020-06-04 18:12:50 +09:30
grossmj
c71ee73da8 Merge branch 'master' into 2.2 2020-06-04 12:22:11 +09:30
Jeremy Grossmann
0643fd516d Merge pull request #2993 from GNS3/replicate-network-connection-state
Support to activate/deactive network connection state replication in Qemu
2020-06-04 10:49:41 +08:00
grossmj
a25680f2ce Fix GUI doesn't detect another GUI on macOS. Fixes #2994 2020-06-03 20:38:55 +09:30
grossmj
58bd5be920 Support to activate/deactive network connection state replication in Qemu. 2020-06-02 18:45:22 +09:30
Jeremy Grossmann
d95633ba2c Merge pull request #2989 from GNS3/reset-mac-addresses
Option to reset all MAC addresses when exporting or duplicating a project.
2020-05-27 10:53:22 +08:00
grossmj
dfea6d1723 Option to reset or not all MAC addresses when exporting or duplicating a project. 2020-05-27 12:14:47 +09:30
grossmj
ddeb95cb0a Fix Multi-device selection/deselection not working as expected with right click. Fixes #2986 2020-05-26 16:11:53 +09:30
grossmj
5f7ff0d70d Generate MainWindow Ui file. 2020-05-26 13:01:04 +09:30
Jeremy Grossmann
a00e039cec Merge pull request #2875 from fatoms/master
Proposed fix for "Edit readme" is missing in GNS3 GUI. #2854
2020-05-26 11:30:19 +08:00
Dominic
a24e9adef1 Merge branch 'Edit_Readme' 2020-05-21 20:03:03 +02:00
Dominic Harford
ee5f8e8edd Resolve conflict with GNS3 repo 2020-05-21 19:08:29 +02:00
grossmj
f5470130f5 Fix issues with crash reporting & bump version to 2.2.9dev2. Ref https://github.com/GNS3/gns3-server/issues/1758 2020-05-21 18:19:19 +09:30
grossmj
1ff405885e Merge branch 'master' into 2.2 2020-05-20 17:25:37 +09:30
Dominic
9fb42ead9f Revert "Updated GUI pyqt files from Tab Order 'fixes' in "Tab Order in Preferences and Project Dialog #2872""
This reverts commit 0d2f91709c.
2020-05-19 18:31:02 +02:00
grossmj
2ea1946c0f Replace Raven by Sentry SDK. Fixes https://github.com/GNS3/gns3-server/issues/1758 2020-05-19 15:48:53 +09:30
grossmj
963e054918 Fix online help menu URL. Fixes #2984 2020-05-08 12:42:06 +09:30
grossmj
0f5f6ab645 Require setuptools>=17.1 in setup.py. Ref https://github.com/GNS3/gns3-server/issues/1751
This is to support environmental markers.
https://github.com/pypa/setuptools/blob/master/CHANGES.rst#171
2020-05-08 12:34:58 +09:30
grossmj
8a905b5c39 Development on 2.2.9dev1 2020-05-07 23:10:20 +09:30
grossmj
e917193f06 Merge branch '2.2' 2020-05-07 23:09:04 +09:30
grossmj
16846ce49c Release v2.2.8 2020-05-07 18:10:57 +09:30
grossmj
624a670ae7 Make sure "port" is defined. 2020-05-07 17:51:32 +09:30
grossmj
406326ccd8 Merge remote-tracking branch 'origin/master' 2020-05-06 11:57:25 +09:30
grossmj
24bc15fb73 Default port set to 80 for server running in the GNS3 VM. Fixes #1737 2020-05-05 12:40:50 +09:30
grossmj
348d8b9438 Make the Web UI the default page. Ref https://github.com/GNS3/gns3-server/issues/1737 2020-04-30 17:27:06 +09:30
grossmj
6787982408 Fix "export portable project forgets contents of README". Fixes #1724 2020-04-30 16:43:00 +09:30
Jeremy Grossmann
c2384917fa Update README. Ref https://github.com/GNS3/gns3-server/issues/1719 2020-04-29 15:01:45 +09:30
grossmj
b80178d0cf Activate unified title and toolbar on MacOS. Fixes #2968 2020-04-29 13:08:51 +09:30
grossmj
e6084ed834 Confirmation dialog for "console connect to all nodes". Fixes #2971 2020-04-28 15:04:39 +09:30
grossmj
ba924cd0d9 Add "Resume all suspended links". Fixes #2858 2020-04-28 14:00:26 +09:30
grossmj
0c3d43346f Revert "Change default path for SecureCRT. Fixes #2896"
This reverts commit 0c4367d77e.
2020-04-28 13:19:38 +09:30
grossmj
fcf6ef3027 Remove @property from ConfigurationDialog(). Fixes #2819 #2965 2020-04-28 11:57:54 +09:30
grossmj
e0f87e573d Use Environmental Markers to force jsonschema version. Fixes https://github.com/GNS3/gns3-gui/issues/2849
Version 3.2.0 with Python >= 3.8
Version 2.6.0 with Python < 3.8
2020-04-27 12:54:17 +09:30
grossmj
3ec068f0cb Use Environmental Markers to force jsonschema version 2.6.0 on Windows/macOS. Ref https://github.com/GNS3/gns3-gui/issues/2849 2020-04-27 12:43:07 +09:30
grossmj
37f1fcf6f7 Remove preferences dialog geometry restoration. Fixes #2807 2020-04-27 11:55:01 +09:30
grossmj
c51dd1605d Merge branch '2.3'
# Conflicts:
#	gns3/version.py
2020-04-13 11:57:04 +09:30
grossmj
4ebf3b4e1c Development on 2.2.8dev1 2020-04-08 01:26:42 +09:30
grossmj
b1ec9d535c Release v2.2.7 2020-04-08 00:03:13 +09:30
grossmj
7fc9087cf0 Fix unable to configure custom adapters for Qemu VMs. Fixes #2961 2020-04-07 15:47:53 +09:30
Bernhard Ehlers
5dc2c77806 QEMU config disk - enable QEMU config import/export
(cherry picked from commit d01f15c4df)
2020-04-06 13:42:00 +02:00
grossmj
4972d460d2 Fix tests. 2020-04-06 21:09:47 +09:30
grossmj
c388836be7 Fix VNC console template doesn't extract %i (Project UUID). Fixes #2960 2020-04-06 18:34:37 +09:30
grossmj
18ae4a6ce9 Fix contextual menu issues. Ref #2955 2020-03-30 21:37:52 -07:00
grossmj
3020e1fc9f Downgrade to PyQt 5.12.3 Ref #2955 #2952 2020-03-29 18:18:53 +10:30
grossmj
fe2f8424db Downgrade to PyQt 5.13.2 Ref #2955 #2952 2020-03-29 14:46:34 +10:30
grossmj
a744f65199 Merge branch 'master' into 2.3
# Conflicts:
#	gns3/version.py
2020-03-28 13:44:08 +10:30
grossmj
d27578f0fc Release v2.2.6 2020-03-26 12:37:59 +10:30
grossmj
b01c11f19b Prevent locked drawings to be deleted. Fixes https://github.com/GNS3/gns3-gui/issues/2948 2020-03-16 16:30:09 +10:30
grossmj
fb269da4d3 Fix issues with empty project variables. Fixes https://github.com/GNS3/gns3-gui/issues/2941 2020-03-14 17:22:44 +10:30
grossmj
ab15f96bb5 Upgrade psutil to version 5.6.6 due to CVE-2019-18874
https://github.com/advisories/GHSA-qfc5-mcwq-26q8
2020-03-14 15:47:12 +10:30
grossmj
5bb8b8e8bd Use existing README.txt if existing when exporting portable project. Fixes https://github.com/GNS3/gns3-server/issues/1724 2020-03-10 17:32:13 +10:30
grossmj
3f9632fae0 Allow creation of a diskless Qemu VMs. Fixes #2939 2020-03-10 17:04:07 +10:30
grossmj
b5f8195abb Re-enable "create new version" in appliance wizard. Fixes #2837 2020-03-03 13:11:01 +08:00
grossmj
73a293bd17 Fix unable to load project from project library. Fixes #2932 2020-03-03 09:34:45 +08:00
grossmj
0a1dfb99e9 Merge remote-tracking branch 'origin/2.2' into 2.2 2020-02-19 14:13:16 +08:00
grossmj
d352919264 Fix some permission denied errors when loading remote project. Ref #2871 Fixes #2901 2020-02-19 14:13:03 +08:00
Jeremy Grossmann
65f2a1e461 Merge pull request #2931 from inthought/2.2
Add 'Royal TS V5' to predefined console list
2020-02-18 13:29:46 +10:30
Travis Abram
71f289721b Add 'Royal TS V5' to predefined console list 2020-02-16 20:46:40 -08:00
grossmj
c28089d400 Disallow invalid grid sized. Fixes #2908 2020-02-10 16:59:17 +08:00
grossmj
64f009bf71 Check if hostname is blank. Fixes #2924 2020-01-25 18:21:02 +08:00
Jeremy Grossmann
edb2fd7fd9 Merge pull request #2925 from GNS3/qemu-changes
GUI changes to support recent versions of Qemu
2020-01-25 16:04:54 +07:00
grossmj
62e7ad8c8a Add nvme disk interface and fix scsi disk interface for Qemu VMs. 2020-01-25 16:22:34 +08:00
grossmj
caeb5d71c3 Add latest Qemu nic models. 2020-01-24 19:05:46 +08:00
grossmj
cfe96b2311 Upgrade Qt version to 5.14.1. Ref #2778 #2903 2020-01-24 17:47:01 +08:00
grossmj
8955b9ee29 Upgrade to PyQt 5.14.1. Ref #2778 2020-01-22 17:53:04 +08:00
grossmj
e727abf27a Change version to 2.3.0dev1 on 2.3 branch 2020-01-16 18:06:51 +08:00
grossmj
f209bf7644 Development on 2.2.6dev1 2020-01-10 00:32:10 +08:00
grossmj
5860dedc32 Release v2.2.5 2020-01-09 23:52:40 +08:00
grossmj
9e2df17a4e Add gns3-gui.xml and update Linux icons paths & permissions. Ref #2919 2020-01-09 23:49:44 +08:00
grossmj
a95761437a Development on 2.2.5dev1 2020-01-09 05:17:01 +08:00
grossmj
626510865f Update paths to icons for Linux 2020-01-09 04:19:21 +08:00
grossmj
2e248aa340 Release v2.2.4 2020-01-09 00:45:09 +08:00
grossmj
e306f73f01 Fix "Console to all nodes" doesn't open cloud objects with console configured. Fixes #2902 2020-01-08 00:35:57 +08:00
grossmj
0c4367d77e Change default path for SecureCRT. Fixes #2896 2019-12-26 06:13:23 +08:00
grossmj
6dda0ff787 Add icons in setup.py Ref #2898 2019-12-26 06:04:40 +08:00
grossmj
d7d4b84309 Add remote viewer as a VNC console for Linux. Fixes #2913 2019-12-26 04:13:02 +08:00
grossmj
7b57983699 Development on 2.2.4dev1 2019-11-12 16:43:21 +08:00
grossmj
bb89fe2275 Release v2.2.3 2019-11-12 15:29:54 +08:00
grossmj
7eb2a923b2 Fix issue when binding on 0.0.0.0. Fixes #2892 2019-11-11 17:49:09 +08:00
grossmj
58052e3cce Allow double click on cloud with configured console to open session. Fixes #2894 2019-11-11 14:31:35 +08:00
grossmj
e431104f6b Officially support Python 3.8. Ref https://github.com/GNS3/gns3-gui/issues/2895 2019-11-11 12:56:11 +08:00
grossmj
a4e9d6b8ce Set psutil to version 5.6.3 in requirements.txt 2019-11-08 10:44:17 +08:00
grossmj
f58f5c7b95 Developement version on 2.2.3dev1 2019-11-04 19:45:18 +08:00
Dominic
c8a8663ff0 Restore editReadme attribute which was removed in Change 'New export project wizard' ( ID c2472bcb22 ) 2019-10-18 17:11:28 +02:00
Dominic
d27e5c1795 Revert "Remove unused edit readme action. Fixes #2816"
This reverts commit 7cd0187f33.
2019-10-18 16:46:48 +02:00
Dominic
0d2f91709c Updated GUI pyqt files from Tab Order 'fixes' in "Tab Order in Preferences and Project Dialog #2872" 2019-10-18 16:45:39 +02:00
119 changed files with 118744 additions and 122809 deletions

19
.github/workflows/testing.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: testing
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build and run Docker image
run: |
docker build -t gns3-gui-test .
docker run gns3-gui-test

View File

@@ -1,2 +0,0 @@
branch:
2.2

View File

@@ -1,21 +0,0 @@
sudo: required
services:
- docker
notifications:
email: false
script:
- docker build -t gns3-gui-test .
- docker run gns3-gui-test
before_deploy:
- sudo pip install twine
- sudo pip install urllib3[secure]
deploy:
provider: pypi
edge:
branch: v1.8.45
user: noplay
password:
secure: FofcqlJjgqf2jaDaXpLHeigVoexbrOz3WwnDuiJpwJxeFUlPY8s2cQs/Bm+dzxzZaOaGiVE0A83v/Xa10yD5tflThHt4sqYJK3iQCinA7wgeAlDimB4xrWUNplfNJZ/Eod5Ssa++E02W+3i29PxpXY//mjCY7qDxaoxul1gnFJY=
on:
tags: true
repo: GNS3/gns3-gui

13
.whitesource Normal file
View File

@@ -0,0 +1,13 @@
{
"scanSettings": {
"configMode": "AUTO",
"configExternalURL": "",
"projectToken" : ""
},
"checkRunSettings": {
"vulnerableCheckRunConclusionLevel": "failure"
},
"issueSettings": {
"minSeverityLevel": "LOW"
}
}

186
CHANGELOG
View File

@@ -1,5 +1,191 @@
# Change Log
## 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
## 2.2.12 07/08/2020
* Downgrade psutil to version 5.6.7
* Fix log shows the GUI command line without spaces between its arguments. Fixes #3026
* Use server host is console host is equal to "0:0:0:0:0:0:0:0"
* Remove VMware promotion.
## 2.2.11 09/07/2020
* Try to fix "Recent project" selection not working. Ref #3007
* Fix debug entries shown twice in console window and double error messages with remote GNS3VM. Fixes #3010
* Fix deprecation warning. Ref #3009
* Fix tests on macOS. Ref #3009
* Fix sentry SDK is configured twice.
## 2.2.10 18/06/2020
* New fix for multi-device selection/deselection not working as expected with right click. Fixes #2986
* Optimize snap-to-grid code for drawing items. Fixes #2997
* Move jsonschema 2.6.0 requirement in build repository.
* Only use jsonschema 2.6.0 on Windows and macOS.
* Disable default integrations for sentry sdk.
## 2.2.9 04/06/2020
* Fix GUI doesn't detect another GUI on macOS. Fixes #2994
* Support to activate/deactive network connection state replication in Qemu.
* Option to reset or not all MAC addresses when exporting or duplicating a project.
* Fix Multi-device selection/deselection not working as expected with right click. Fixes #2986
* Replace Raven by Sentry SDK. Fixes https://github.com/GNS3/gns3-server/issues/1758
* Fix online help menu URL. Fixes #2984
* Require setuptools>=17.1 in setup.py. Ref https://github.com/GNS3/gns3-server/issues/1751 This is to support environmental markers. https://github.com/pypa/setuptools/blob/master/CHANGES.rst#171
* Update README. Ref https://github.com/GNS3/gns3-server/issues/1719
* Restore editReadme attribute which was removed in Change 'New export project wizard'
* Updated GUI pyqt files from Tab Order 'fixes' in "Tab Order in Preferences and Project Dialog #2872"
## 2.2.8 07/05/2020
* Default port set to 80 for server running in the GNS3 VM. Fixes #1737
* Make the Web UI the default page. Ref https://github.com/GNS3/gns3-server/issues/1737
* Fix "export portable project forgets contents of README". Fixes #1724
* Activate unified title and toolbar on MacOS. Fixes #2968
* Confirmation dialog for "console connect to all nodes". Fixes #2971
* Add "Resume all suspended links". Fixes #2858
* Revert "Change default path for SecureCRT. Fixes #2896"
* Remove @property from ConfigurationDialog(). Fixes #2819 #2965
* Use Environmental Markers to force jsonschema version. Fixes https://github.com/GNS3/gns3-gui/issues/2849 Version 3.2.0 with Python >= 3.8 Version 2.6.0 with Python < 3.8
* Use Environmental Markers to force jsonschema version 2.6.0 on Windows/macOS. Ref https://github.com/GNS3/gns3-gui/issues/2849
* Remove preferences dialog geometry restoration. Fixes #2807
* Fix unable to configure custom adapters for Qemu VMs. Fixes #2961
## 2.2.7 07/04/2020
* Fix VNC console template doesn't extract %i (Project UUID). Fixes #2960
* Fix contextual menu issues. Ref #2955
## 2.2.6 26/03/2020
* Prevent locked drawings to be deleted. Fixes https://github.com/GNS3/gns3-gui/issues/2948
* Fix issues with empty project variables. Fixes https://github.com/GNS3/gns3-gui/issues/2941
* Upgrade psutil to version 5.6.6 due to CVE-2019-18874 https://github.com/advisories/GHSA-qfc5-mcwq-26q8
* Use existing README.txt if existing when exporting portable project. Fixes https://github.com/GNS3/gns3-server/issues/1724
* Allow creation of a diskless Qemu VMs. Fixes #2939
* Re-enable "create new version" in appliance wizard. Fixes #2837
* Fix unable to load project from project library. Fixes #2932
* Fix some permission denied errors when loading remote project. Ref #2871 Fixes #2901
* Add 'Royal TS V5' to predefined console list
* Disallow invalid grid sized. Fixes #2908
* Check if hostname is blank. Fixes #2924
* Add nvme disk interface and fix scsi disk interface for Qemu VMs.
* Add latest Qemu nic models.
* Upgrade Qt version to 5.14.1. Ref #2778 #2903
## 2.2.5 09/01/2020
* Add gns3-gui.xml and update Linux icons paths & permissions. Ref #2919
## 2.2.4 08/01/2020
* Fix "Console to all nodes" doesn't open cloud objects with console configured. Fixes #2902
* Change default path for SecureCRT. Fixes #2896
* Add icons in setup.py Ref #2898
* Add remote viewer as a VNC console for Linux. Fixes #2913
## 2.2.3 12/11/2019
* Fix issue when binding on 0.0.0.0. Fixes #2892
* Allow double click on cloud with configured console to open session. Fixes #2894
* Officially support Python 3.8. Ref https://github.com/GNS3/gns3-gui/issues/2895
* Set psutil to version 5.6.3 in requirements.txt
## 2.2.2 04/11/2019
* Fix KeyError: 'spice+agent'. Fixes #2890

View File

@@ -1,22 +1,16 @@
# Run tests inside a container
FROM ubuntu:18.04
MAINTAINER GNS3 Team
#ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update
RUN apt-get install -y --force-yes python3.6 python3-pyqt5 python3-pip python3-pyqt5.qtsvg python3-pyqt5.qtwebsockets python3.6-dev xvfb
RUN apt-get clean
ADD dev-requirements.txt /dev-requirements.txt
ADD requirements.txt /requirements.txt
RUN pip3 install -r /dev-requirements.txt
ADD . /src
WORKDIR /src
CMD xvfb-run python3.6 -m pytest -vv

View File

@@ -3,7 +3,6 @@ include AUTHORS
include LICENSE
include MANIFEST.in
include requirements.txt
include tox.ini
recursive-include tests *
recursive-include gns3 *
recursive-include resources *

View File

@@ -1,12 +1,15 @@
GNS3-gui
========
.. image:: https://travis-ci.org/GNS3/gns3-gui.svg?branch=master
:target: https://travis-ci.org/GNS3/gns3-gui
.. image:: https://github.com/GNS3/gns3-gui/workflows/testing/badge.svg
:target: https://github.com/GNS3/gns3-gui/actions?query=workflow%3Atesting
.. image:: https://img.shields.io/pypi/v/gns3-gui.svg
:target: https://pypi.python.org/pypi/gns3-gui
.. image:: https://snyk.io/test/github/GNS3/gns3-gui/badge.svg
:target: https://snyk.io/test/github/GNS3/gns3-gui
GNS3 GUI repository.
@@ -15,6 +18,15 @@ Installation
Please see https://docs.gns3.com/
Software dependencies
---------------------
PyQt5 which is either part of the Linux distribution or installable from PyPi. The other Python dependencies are automatically installed during the GNS3 GUI installation and are listed `here <https://github.com/GNS3/gns3-gui/blob/master/requirements.txt>`_
For connecting to nodes using Telnet, a Telnet client is required. On Linux that's a terminal emulator like xterm, gnome-terminal, konsole plus the telnet program. For connecting to nodes with a GUI, a VNC client is required, optionally a SPICE client can be used for Qemu nodes.
For using packet captures within GNS3, Wireshark should be installed. It's recommended, but if you don't need that functionality you can go without it.
Development
-------------
@@ -42,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

View File

@@ -1,6 +1,5 @@
-rrequirements.txt
pep8==1.7.0
pytest==4.4.1
pytest-pythonpath==0.7.3 # useful for running tests outside tox
pytest-timeout==1.3.3
pytest==6.2.4
flake8==3.9.2
pytest-timeout==1.4.2

View File

@@ -223,17 +223,10 @@ class ConsoleCmd(cmd.Cmd):
level = int(args[0])
if level == 0:
print("Deactivating debugging")
for handler in root.handlers:
if isinstance(handler, logging.StreamHandler):
root.removeHandler(handler)
root.setLevel(logging.INFO)
else:
root.addHandler(logging.StreamHandler(sys.stdout))
if level == 1:
print("Activating debugging")
else:
print("Activating full debugging")
root.setLevel(logging.DEBUG)
print("Activating debugging")
root.setLevel(logging.DEBUG)
from .main_window import MainWindow
MainWindow.instance().setSettings({"debug_level": level})
else:

View File

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

View File

@@ -16,19 +16,18 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import psutil
import os
import platform
import struct
import distro
try:
import raven
from raven.transport.http import HTTPTransport
RAVEN_AVAILABLE = True
import sentry_sdk
from sentry_sdk.integrations.logging import LoggingIntegration
SENTRY_SDK_AVAILABLE = True
except ImportError:
# raven is not installed with deb package in order to simplify packaging
RAVEN_AVAILABLE = False
# Sentry SDK is not installed with deb package in order to simplify packaging
SENTRY_SDK_AVAILABLE = False
from .utils.get_resource import get_resource
from .version import __version__, __version_info__
@@ -52,66 +51,67 @@ class CrashReport:
Report crash to a third party service
"""
DSN = "https://dbedb95015d948b3b38917d7ac01e15b:1fcb50016b474c12b14c53d2b83eeabc@sentry.io/38506"
if hasattr(sys, "frozen"):
cacert = get_resource("cacert.pem")
if cacert is not None and os.path.isfile(cacert):
DSN += "?ca_certs={}".format(cacert)
else:
log.warning("The SSL certificate bundle file '{}' could not be found".format(cacert))
DSN = "https://803fefdf04db46ee9f4f245a53e58e70:91e2e200ee32481a976937182357ecc8@o19455.ingest.sentry.io/38506"
_instance = None
def __init__(self):
# We don't want sentry making noise if an error is catched when you don't have internet
# We don't want sentry making noise if an error is caught when we don't have internet
sentry_errors = logging.getLogger('sentry.errors')
sentry_errors.disabled = True
sentry_uncaught = logging.getLogger('sentry.errors.uncaught')
sentry_uncaught.disabled = True
self._sentry_initialized = False
def captureException(self, exception, value, tb):
from .local_server import LocalServer
from .local_config import LocalConfig
from .controller import Controller
from .compute_manager import ComputeManager
if SENTRY_SDK_AVAILABLE:
cacert = None
if hasattr(sys, "frozen"):
cacert_resource = get_resource("cacert.pem")
if cacert_resource is not None and os.path.isfile(cacert_resource):
cacert = cacert_resource
else:
log.error("The SSL certificate bundle file '{}' could not be found".format(cacert_resource))
local_server = LocalServer.instance().localServerSettings()
if local_server["report_errors"]:
if not RAVEN_AVAILABLE:
return
# Don't send log records as events.
sentry_logging = LoggingIntegration(level=logging.INFO, event_level=None)
if os.path.exists(LocalConfig.instance().runAsRootPath()):
log.warning("User has run application as root. Crash reports are disabled.")
sys.exit(1)
return
sentry_sdk.init(dsn=CrashReport.DSN,
release=__version__,
ca_certs=cacert,
default_integrations=False,
integrations=[sentry_logging])
if os.path.exists(".git"):
log.warning("A .git directory exist crash report is turn off for developers. Instant exit")
sys.exit(1)
return
if hasattr(exception, "fingerprint"):
client = raven.Client(CrashReport.DSN, release=__version__, fingerprint=['{{ default }}', exception.fingerprint], transport=HTTPTransport)
else:
client = raven.Client(CrashReport.DSN, release=__version__, transport=HTTPTransport)
context = {
tags = {
"os:name": platform.system(),
"os:release": platform.release(),
"os:win_32": " ".join(platform.win32_ver()),
"os:mac": "{} {}".format(platform.mac_ver()[0], platform.mac_ver()[2]),
"os:linux": " ".join(distro.linux_distribution()),
}
self._add_qt_information(tags)
with sentry_sdk.configure_scope() as scope:
for key, value in tags.items():
scope.set_tag(key, value)
extra_context = {
"python:version": "{}.{}.{}".format(sys.version_info[0],
sys.version_info[1],
sys.version_info[2]),
"python:bit": struct.calcsize("P") * 8,
"python:encoding": sys.getdefaultencoding(),
"python:frozen": "{}".format(hasattr(sys, "frozen")),
"python:frozen": "{}".format(hasattr(sys, "frozen"))
}
# extra controller and compute information
extra_context = {"controller:version": Controller.instance().version(),
"controller:host": Controller.instance().host(),
"controller:connected": Controller.instance().connected()}
from .controller import Controller
from .compute_manager import ComputeManager
extra_context["controller:version"] = Controller.instance().version()
extra_context["controller:host"] = Controller.instance().host()
extra_context["controller:connected"] = Controller.instance().connected()
for index, compute in enumerate(ComputeManager.instance().computes()):
extra_context["compute{}:id".format(index)] = compute.id()
extra_context["compute{}:name".format(index)] = compute.name(),
@@ -120,27 +120,48 @@ class CrashReport:
extra_context["compute{}:platform".format(index)] = compute.capabilities().get("platform")
extra_context["compute{}:version".format(index)] = compute.capabilities().get("version")
context = self._add_qt_information(context)
client.tags_context(context)
client.extra_context(extra_context)
try:
report = client.captureException((exception, value, tb))
except Exception as e:
log.error("Can't send crash report to Sentry: {}".format(e))
return
log.debug("Crash report sent with event ID: {}".format(client.get_ident(report)))
with sentry_sdk.configure_scope() as scope:
for key, value in extra_context.items():
scope.set_extra(key, value)
def captureException(self, exception, value, tb):
from .local_server import LocalServer
from .local_config import LocalConfig
local_server = LocalServer.instance().localServerSettings()
if local_server["report_errors"]:
if not SENTRY_SDK_AVAILABLE:
log.warning("Cannot capture exception: Sentry SDK is not available")
return
if os.path.exists(LocalConfig.instance().runAsRootPath()):
log.warning("User is running application as root. Crash reports disabled.")
return
if not hasattr(sys, "frozen") and os.path.exists(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", ".git")):
log.warning(".git directory detected, crash reporting is turned off for developers.")
return
try:
error = (exception, value, tb)
sentry_sdk.capture_exception(error=error)
log.info("Crash report sent with event ID: {}".format(sentry_sdk.last_event_id()))
except Exception as e:
log.warning("Can't send crash report to Sentry: {}".format(e))
def _add_qt_information(self, tags):
def _add_qt_information(self, context):
try:
from .qt import QtCore
from .qt import sip
except ImportError:
return context
context["psutil:version"] = psutil.__version__
context["pyqt:version"] = QtCore.PYQT_VERSION_STR
context["qt:version"] = QtCore.QT_VERSION_STR
context["sip:version"] = sip.SIP_VERSION_STR
return context
return tags
tags["pyqt:version"] = QtCore.PYQT_VERSION_STR
tags["qt:version"] = QtCore.QT_VERSION_STR
tags["sip:version"] = sip.SIP_VERSION_STR
return tags
@classmethod
def instance(cls):

View File

@@ -72,9 +72,6 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
self.uiCreateVersionPushButton.clicked.connect(self._createVersionPushButtonClickedSlot)
self.allowCustomFiles.clicked.connect(self._allowCustomFilesChangedSlot)
#FIXME: deactivate the create version feature (confusing and maybe not necessary, TBD)
self.uiCreateVersionPushButton.hide()
# directories where to search for images
images_directories = list()
@@ -478,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", "Creating a new version allows to import unknown files to use with 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:
@@ -541,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)

View File

@@ -49,7 +49,6 @@ class ConfigurationDialog(QtWidgets.QDialog, Ui_configurationDialog):
self._settings = settings
self._configuration_page = configuration_page
@property
def settings(self):
return self._settings

View File

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

View File

@@ -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()

View File

@@ -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):
"""
@@ -108,14 +108,19 @@ class EditProjectDialog(QtWidgets.QDialog, Ui_EditProjectDialog):
"""
if result:
self._project.setName(self.uiProjectNameLineEdit.text())
self._project.setAutoOpen(self.uiProjectAutoOpenCheckBox.isChecked())
self._project.setAutoClose(not self.uiProjectAutoCloseCheckBox.isChecked())
self._project.setAutoStart(self.uiProjectAutoStartCheckBox.isChecked())
self._project.setSceneHeight(self.uiSceneHeightSpinBox.value())
self._project.setSceneWidth(self.uiSceneWidthSpinBox.value())
self._project.setNodeGridSize(self.uiNodeGridSizeSpinBox.value())
self._project.setDrawingGridSize(self.uiDrawingGridSizeSpinBox.value())
self._project.setVariables(self._cleanVariables())
self._project.update()
node_grid_size = self.uiNodeGridSizeSpinBox.value()
drawing_grid_size = self.uiDrawingGridSizeSpinBox.value()
if node_grid_size % drawing_grid_size != 0:
QtWidgets.QMessageBox.critical(self, "Grid sizes", "Invalid grid sizes which will create overlapping lines")
else:
self._project.setNodeGridSize(node_grid_size)
self._project.setDrawingGridSize(drawing_grid_size)
self._project.setName(self.uiProjectNameLineEdit.text())
self._project.setAutoOpen(self.uiProjectAutoOpenCheckBox.isChecked())
self._project.setAutoClose(not self.uiProjectAutoCloseCheckBox.isChecked())
self._project.setAutoStart(self.uiProjectAutoStartCheckBox.isChecked())
self._project.setSceneHeight(self.uiSceneHeightSpinBox.value())
self._project.setSceneWidth(self.uiSceneWidthSpinBox.value())
self._project.setVariables(self._cleanVariables())
self._project.update()
super().done(result)

View File

@@ -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)
@@ -135,17 +135,20 @@ class ProjectDialog(QtWidgets.QDialog, Ui_ProjectDialog):
new_project_name)
name = name.strip()
if reply and len(name) > 0:
reset_mac_addresses = self.uiResetMacAddressesCheckBox.isChecked()
if Controller.instance().isRemote():
Controller.instance().post("/projects/{project_id}/duplicate".format(project_id=project_id),
self._duplicateCallback,
body={"name": name},
body={"name": name, "reset_mac_addresses": reset_mac_addresses},
progressText="Duplicating project '{}'...".format(name),
timeout=None)
else:
project_location = os.path.join(Topology.instance().projectsDirPath(), name)
Controller.instance().post("/projects/{project_id}/duplicate".format(project_id=project_id),
self._duplicateCallback,
body={"name": name, "path": project_location},
body={"name": name, "path": project_location, "reset_mac_addresses": reset_mac_addresses},
progressText="Duplicating project '{}'...".format(name),
timeout=None)
@@ -228,20 +231,20 @@ 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.triggered.connect(self._menuTriggeredSlot)
menu = QtWidgets.QMenu(parent=self)
if Controller.instance().isRemote():
for action in self._main_window.recent_project_actions:
menu.addAction(action)
else:
for action in self._main_window.recent_file_actions:
menu.addAction(action)
menu.exec_(QtGui.QCursor.pos())
menu.triggered.connect(self._menuTriggeredSlot)
self.uiRecentProjectsPushButton.setMenu(menu)
def _overwriteProjectCallback(self, result, error=False, **kwargs):
if error:

View File

@@ -16,6 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import os
import datetime
from gns3.qt import QtCore, QtWidgets
@@ -54,9 +55,19 @@ class ExportProjectWizard(QtWidgets.QWizard, Ui_ExportProjectWizard):
self.uiCompressionComboBox.setCurrentIndex(1)
self.helpRequested.connect(self._showHelpSlot)
self.uiPathBrowserToolButton.clicked.connect(self._pathBrowserSlot)
self._loadReadme()
readme_text = "Project: '{}' created on {}\nAuthor: John Doe <john.doe@example.com>\n\nNo project description was given".format(self._project.name(), datetime.date.today())
self.uiReadmeTextEdit.setPlainText(readme_text)
def _loadReadme(self):
self._project.get("/files/README.txt", self._loadedReadme)
def _loadedReadme(self, result, error=False, raw_body=None, context={}, **kwargs):
if not error:
self.uiReadmeTextEdit.setPlainText(raw_body.decode("utf-8", errors="replace"))
else:
readme_text = "Project: '{}' created on {}\nAuthor: John Doe <john.doe@example.com>\n\nNo project description was given".format(self._project.name(), datetime.date.today())
self.uiReadmeTextEdit.setPlainText(readme_text)
def _pathBrowserSlot(self):
@@ -123,8 +134,12 @@ class ExportProjectWizard(QtWidgets.QWizard, Ui_ExportProjectWizard):
include_snapshots = "yes"
else:
include_snapshots = "no"
if self.uiResetMacAddressesCheckBox.isChecked():
reset_mac_addresses = "yes"
else:
reset_mac_addresses = "no"
compression = self.uiCompressionComboBox.currentData()
export_worker = ExportProjectWorker(self._project, self._path, include_images, include_snapshots, compression)
export_worker = ExportProjectWorker(self._project, self._path, include_images, include_snapshots, reset_mac_addresses, compression)
progress_dialog = ProgressDialog(export_worker, "Exporting project", "Exporting portable project files...", "Cancel", parent=self, create_thread=False)
progress_dialog.show()
progress_dialog.exec_()

View File

@@ -37,9 +37,7 @@ class ProjectWelcomeDialog(QtWidgets.QDialog, Ui_ProjectWelcomeDialog):
self.uiOkButton.clicked.connect(self._okButtonClickedSlot)
self.gridLayout.setAlignment(QtCore.Qt.AlignTop)
self.label.setOpenExternalLinks(True)
self._variables = self._getVariables(project)
self._loadReadme()
self._addMisingVariablesEdits()
@@ -50,10 +48,11 @@ class ProjectWelcomeDialog(QtWidgets.QDialog, Ui_ProjectWelcomeDialog):
return variables
def _addMisingVariablesEdits(self):
missing = [v for v in self._variables if v.get("value", "").strip() == ""]
#TODO: refactor this to use a QListWidget
missing = [v for v in self._variables if v.get("name") and v.get("value", "").strip() == ""]
for i, variable in enumerate(missing, start=0):
nameLabel = QtWidgets.QLabel()
nameLabel.setText(variable.get("name", ""))
nameLabel.setText(variable.get("name") + ":")
self.gridLayout.addWidget(nameLabel, i, 0)
valueEdit = QtWidgets.QLineEdit()
@@ -72,13 +71,13 @@ class ProjectWelcomeDialog(QtWidgets.QDialog, Ui_ProjectWelcomeDialog):
variable["value"] = text
def _okButtonClickedSlot(self):
missing = [v for v in self._variables if v.get("value", "").strip() == ""]
missing = [v for v in self._variables if v.get("name") and v.get("value", "").strip() == ""]
if len(missing) > 0:
reply = QtWidgets.QMessageBox.warning(
self, 'Missing values',
'Are you sure you want to continue without providing missing values?',
QtWidgets.QMessageBox.Yes,
QtWidgets.QMessageBox.No)
reply = QtWidgets.QMessageBox.warning(self,
"Missing values",
"Are you sure you want to continue without providing missing values?",
QtWidgets.QMessageBox.Yes,
QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.No:
return

View File

@@ -50,9 +50,11 @@ class SetupWizard(QtWidgets.QWizard, Ui_SetupWizard):
"headless": False,
"when_exit": "stop",
"engine": "vmware",
"allocate_vcpus_ram": True,
"vcpus": 1,
"ram": 2048,
"vmname": "GNS3 VM"
"vmname": "GNS3 VM",
"port": 80
}
self.setWizardStyle(QtWidgets.QWizard.ModernStyle)
@@ -66,7 +68,6 @@ class SetupWizard(QtWidgets.QWizard, Ui_SetupWizard):
self.uiRefreshPushButton.clicked.connect(self._refreshVMListSlot)
self.uiVmwareRadioButton.clicked.connect(self._listVMwareVMsSlot)
self.uiVirtualBoxRadioButton.clicked.connect(self._listVirtualBoxVMsSlot)
self.uiVMwareBannerButton.clicked.connect(self._VMwareBannerButtonClickedSlot)
settings = parent.settings()
self.uiShowCheckBox.setChecked(settings["hide_setup_wizard"])
@@ -89,10 +90,9 @@ class SetupWizard(QtWidgets.QWizard, Ui_SetupWizard):
continue
self.uiLocalServerHostComboBox.addItem(address_string, address_string)
if sys.platform.startswith("darwin"):
self.uiVMwareBannerButton.setIcon(QtGui.QIcon(":/images/vmware_fusion_banner.png"))
else:
self.uiVMwareBannerButton.setIcon(QtGui.QIcon(":/images/vmware_workstation_banner.png"))
self.uiLocalServerHostComboBox.addItem("localhost", "localhost") # local host
self.uiLocalServerHostComboBox.addItem("::", "::") # all IPv6 addresses
self.uiLocalServerHostComboBox.addItem("0.0.0.0", "0.0.0.0") # all IPv4 addresses
if sys.platform.startswith("linux"):
self.uiLocalRadioButton.setChecked(True)
@@ -116,13 +116,6 @@ class SetupWizard(QtWidgets.QWizard, Ui_SetupWizard):
self.uiLocalServerPathLineEdit.setText(path)
def _VMwareBannerButtonClickedSlot(self):
if sys.platform.startswith("darwin"):
url = "http://send.onenetworkdirect.net/z/621395/CD225091/"
else:
url = "http://send.onenetworkdirect.net/z/616207/CD225091/"
QtGui.QDesktopServices.openUrl(QtCore.QUrl(url))
def _listVMwareVMsSlot(self):
"""
Slot to refresh the VMware VMs list.
@@ -415,9 +408,7 @@ class SetupWizard(QtWidgets.QWizard, Ui_SetupWizard):
settings["hide_setup_wizard"] = True
else:
local_server_settings = LocalServer.instance().localServerSettings()
if local_server_settings["host"] is None:
local_server_settings["host"] = DEFAULT_LOCAL_SERVER_HOST
LocalServer.instance().updateLocalServerSettings(local_server_settings)
LocalServer.instance().updateLocalServerSettings(local_server_settings)
settings["hide_setup_wizard"] = not self.uiShowCheckBox.isChecked()
self.parentWidget().setSettings(settings)
super().done(result)

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

View File

@@ -119,13 +119,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):
"""

View File

@@ -392,7 +392,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 +409,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
@@ -460,25 +460,15 @@ class GraphicsView(QtWidgets.QGraphicsView):
else:
item.setSelected(True)
elif is_not_link and is_not_logo and event.button() == QtCore.Qt.RightButton and not self._adding_link:
if item and not sip.isdeleted(item):
# Prevent right clicking on a selected item from de-selecting all other items
if not item.isSelected():
if not event.modifiers() & QtCore.Qt.ControlModifier:
for it in self.scene().items():
it.setSelected(False)
item.setSelected(True)
self._showDeviceContextualMenu(QtGui.QCursor.pos())
else:
self._showDeviceContextualMenu(QtGui.QCursor.pos())
# when more than one item is selected display the contextual menu even if mouse is not above an item
elif len(self.scene().selectedItems()) > 1:
self._showDeviceContextualMenu(QtGui.QCursor.pos())
pass #TODO: remove this without creating a bug...
elif is_not_link and self._adding_link and event.button() == QtCore.Qt.RightButton:
# send a escape key to the main window to cancel the link addition
key = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Escape, QtCore.Qt.NoModifier)
QtWidgets.QApplication.sendEvent(self._main_window, key)
elif item and isinstance(item, NodeItem) and self._adding_link and event.button() == QtCore.Qt.LeftButton:
self._userNodeLinking(event, item)
#context_event = QtGui.QContextMenuEvent(QtGui.QContextMenuEvent.Mouse, event.pos())
#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)
@@ -512,6 +502,46 @@ class GraphicsView(QtWidgets.QGraphicsView):
self.toggleUiDeviceMenu()
def contextMenuEvent(self, event):
"""
Handles all context menu events.
:param event: QContextMenuEvent instance
"""
is_not_link = True
is_not_logo = True
item = self.itemAt(event.pos())
if item and sip.isdeleted(item):
return
if item and (isinstance(item, LinkItem) or isinstance(item.parentItem(), LinkItem)):
is_not_link = False
if item and (isinstance(item, LogoItem) or isinstance(item.parentItem(), LogoItem)):
is_not_logo = False
else:
for it in self.scene().items():
if isinstance(it, LinkItem):
it.setHovered(False)
if is_not_link and is_not_logo and not self._adding_link:
if item and not sip.isdeleted(item):
# Prevent right clicking on a selected item from de-selecting all other items
if not item.isSelected():
if not event.modifiers() & QtCore.Qt.ControlModifier:
for it in self.scene().items():
it.setSelected(False)
item.setSelected(True)
self._showDeviceContextualMenu(event.globalPos())
# when more than one item is selected display the contextual menu even if mouse is not above an item
elif len(self.scene().selectedItems()) > 1:
self._showDeviceContextualMenu(event.globalPos())
#elif item and isinstance(item, NodeItem) and self._adding_link:
# self._userNodeLinking(event, item)
else:
super().contextMenuEvent(event)
def mouseReleaseEvent(self, event):
"""
Handles all mouse release events.
@@ -547,7 +577,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:
@@ -627,7 +657,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().isAlwaysOn():
if item.node().status() == Node.stopped or item.node().consoleType() == "none":
self.configureSlot()
return
else:
@@ -724,6 +754,11 @@ class GraphicsView(QtWidgets.QGraphicsView):
self.populateDeviceContextualMenu(menu)
menu.exec_(pos)
menu.clear()
# Make sure to deselect all items.
# This is to prevent a bug on Windows
# see https://github.com/GNS3/gns3-gui/issues/2986
for it in self.scene().items():
it.setSelected(False)
def populateDeviceContextualMenu(self, menu):
"""
@@ -826,19 +861,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)
@@ -988,6 +1023,9 @@ class GraphicsView(QtWidgets.QGraphicsView):
if isinstance(item, NodeItem) and item.node().initialized():
new_hostname, ok = QtWidgets.QInputDialog.getText(self, "Change hostname", "Hostname:", QtWidgets.QLineEdit.Normal, item.node().name())
if ok:
if not new_hostname.strip():
QtWidgets.QMessageBox.critical(self, "Change hostname", "Hostname cannot be blank")
continue
if hasattr(item.node(), "validateHostname"):
if not item.node().validateHostname(new_hostname):
QtWidgets.QMessageBox.critical(self, "Change hostname", "Invalid name detected for this node: {}".format(new_hostname))
@@ -1095,11 +1133,21 @@ class GraphicsView(QtWidgets.QGraphicsView):
def consoleFromAllItems(self):
"""
Console from all scene items, except builtin devices.
Console from all scene items with console type different than "none"
"""
items = [item for item in self.scene().items()
if not (isinstance(item, NodeItem) and isinstance(item.node().module(), Builtin))]
if isinstance(item, NodeItem) and item.node().consoleType() != "none"]
nb_items = len(items)
if nb_items > 10:
proceed = QtWidgets.QMessageBox.question(self,
"Console to all nodes",
"You are about to open console windows to {} nodes. Are you sure?".format(nb_items),
QtWidgets.QMessageBox.Yes,
QtWidgets.QMessageBox.No)
if proceed == QtWidgets.QMessageBox.No:
return
self.consoleFromItems(items)
def consoleActionSlot(self):
@@ -1178,7 +1226,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:
@@ -1209,17 +1257,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)
@@ -1234,7 +1282,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:
@@ -1503,6 +1551,9 @@ class GraphicsView(QtWidgets.QGraphicsView):
QtWidgets.QMessageBox.critical(self, "Delete", "Cannot delete node '{}' because it is locked".format(node.name()))
return
selected_nodes.append(node)
if isinstance(item, DrawingItem) and item.locked():
QtWidgets.QMessageBox.critical(self, "Delete", "Cannot delete drawing because it is locked")
return
if selected_nodes:
if len(selected_nodes) > 1:
question = "Do you want to permanently delete these {} nodes?".format(len(selected_nodes))

View File

@@ -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)
@@ -776,6 +798,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):
"""

View File

@@ -212,14 +212,13 @@ class DrawingItem:
self._project.delete("/drawings/" + self._id, None, body=self.__json__())
def itemChange(self, change, value):
if change == QtWidgets.QGraphicsItem.ItemPositionHasChanged and self.isActive() and self._main_window.uiSnapToGridAction.isChecked():
if change == QtWidgets.QGraphicsItem.ItemPositionChange and self.isActive() and self._main_window.uiSnapToGridAction.isChecked():
grid_size = self._graphics_view.drawingGridSize()
mid_x = self.boundingRect().width() / 2
tmp_x = (grid_size * round((self.x() + mid_x) / grid_size)) - mid_x
value.setX((grid_size * round((value.x() + mid_x) / grid_size)) - mid_x)
mid_y = self.boundingRect().height() / 2
tmp_y = (grid_size * round((self.y() + mid_y) / grid_size)) - mid_y
if tmp_x != self.x() and tmp_y != self.y():
self.setPos(tmp_x, tmp_y)
value.setY((grid_size * round((value.y()+mid_y)/grid_size)) - mid_y)
if change == QtWidgets.QGraphicsItem.ItemSelectedChange:
if not value:

View File

@@ -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()

View File

@@ -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'))
@@ -280,23 +302,31 @@ class LinkItem(QtWidgets.QGraphicsPathItem):
:param: QGraphicsSceneMouseEvent instance
"""
if event.button() == QtCore.Qt.RightButton:
if self._adding_flag:
# send a escape key to the main window to cancel the link addition
from ..main_window import MainWindow
key = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Escape, QtCore.Qt.NoModifier)
QtWidgets.QApplication.sendEvent(MainWindow.instance(), key)
return
if event.button() == QtCore.Qt.RightButton and self._adding_flag:
# send a escape key to the main window to cancel the link addition
from ..main_window import MainWindow
key = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Escape, QtCore.Qt.NoModifier)
QtWidgets.QApplication.sendEvent(MainWindow.instance(), key)
return
else:
super().mousePressEvent(event)
if not sip_is_deleted(self):
# create the contextual menu
self.setAcceptHoverEvents(False)
menu = QtWidgets.QMenu()
self.populateLinkContextualMenu(menu)
menu.exec_(QtGui.QCursor.pos())
self.setAcceptHoverEvents(True)
self._hovered = False
self.adjust()
def contextMenuEvent(self, event):
"""
Handles all context menu events.
:param event: QContextMenuEvent instance
"""
if not sip_is_deleted(self):
# create the contextual menu
self.setAcceptHoverEvents(False)
menu = QtWidgets.QMenu()
self.populateLinkContextualMenu(menu)
menu.exec_(QtGui.QCursor.pos())
self.setAcceptHoverEvents(True)
self._hovered = False
self.adjust()
def keyPressEvent(self, event):
"""

View File

@@ -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):

View File

@@ -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()

View File

@@ -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,7 +90,7 @@ class Link(QtCore.QObject):
self._creator = False
self._nodes = []
self._link_style = {}
self._source_node.addLink(self)
self._destination_node.addLink(self)
@@ -119,19 +119,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 +218,7 @@ class Link(QtCore.QObject):
}
],
"filters": self._filters,
"link_style": self._link_style,
"suspend": self._suspend
}
if self._source_port.label():
@@ -356,9 +361,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 +390,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 +473,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

View File

@@ -488,7 +488,7 @@ class LocalConfig(QtCore.QObject):
if pid != my_pid:
try:
process = psutil.Process(pid=pid)
ps_name = process.name()
ps_name = process.name().lower()
except (OSError, psutil.NoSuchProcess, psutil.AccessDenied):
pass
else:

View File

@@ -31,7 +31,7 @@ import subprocess
from gns3.qt import QtWidgets, QtCore, qslot
from gns3.settings import LOCAL_SERVER_SETTINGS
from gns3.settings import LOCAL_SERVER_SETTINGS, DEFAULT_LOCAL_SERVER_HOST
from gns3.local_config import LocalConfig
from gns3.local_server_config import LocalServerConfig
from gns3.utils.wait_for_connection_worker import WaitForConnectionWorker
@@ -246,6 +246,9 @@ class LocalServer(QtCore.QObject):
"""
Update the local server settings. Keep the key not in new_settings
"""
if "host" in new_settings and new_settings["host"] is None:
new_settings["host"] = DEFAULT_LOCAL_SERVER_HOST
old_settings = copy.copy(self._settings)
if not self._settings:
self._settings = new_settings

View File

@@ -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="?")
@@ -255,8 +258,7 @@ def main():
current_year = datetime.date.today().year
log.info("GNS3 GUI version {}".format(__version__))
log.info("Copyright (c) 2007-{} GNS3 Technologies Inc.".format(current_year))
log.info("Application started with {}".format("".join(sys.argv)))
log.info("Application started with {}".format(" ".join(sys.argv)))
# update the exception file path to have it in the same directory as the settings file.
exception_file_path = os.path.join(LocalConfig.instance().configDirectory(), exception_file_path)

View File

@@ -84,6 +84,24 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
self._settings = {}
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
@@ -177,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)
@@ -240,7 +236,6 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
self.uiLockAllAction.triggered.connect(self._lockActionSlot)
# tool menu connections
self.uiWebInterfaceAction.triggered.connect(self._openLightWebInterfaceActionSlot)
self.uiWebUIAction.triggered.connect(self._openWebInterfaceActionSlot)
# control menu connections
@@ -260,6 +255,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
self.uiDrawRectangleAction.triggered.connect(self._drawRectangleActionSlot)
self.uiDrawEllipseAction.triggered.connect(self._drawEllipseActionSlot)
self.uiDrawLineAction.triggered.connect(self._drawLineActionSlot)
self.uiEditReadmeAction.triggered.connect(self._editReadmeActionSlot)
# help menu connections
self.uiOnlineHelpAction.triggered.connect(self._onlineHelpActionSlot)
@@ -322,10 +318,6 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
LocalConfig.instance().saveSectionSettings(self.__class__.__name__, self._settings)
self.settings_updated_signal.emit()
def _openLightWebInterfaceActionSlot(self):
if Controller.instance().connected():
QtGui.QDesktopServices.openUrl(QtCore.QUrl(Controller.instance().httpClient().fullUrl()))
def _openWebInterfaceActionSlot(self):
if Controller.instance().connected():
base_url = Controller.instance().httpClient().fullUrl()
@@ -543,8 +535,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:
@@ -813,6 +803,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()
@@ -822,6 +819,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()
@@ -831,6 +834,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()
@@ -840,6 +849,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()
@@ -914,7 +929,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
Slot to launch a browser pointing to the documentation page.
"""
QtGui.QDesktopServices.openUrl(QtCore.QUrl("https://gns3.com/support/docs"))
QtGui.QDesktopServices.openUrl(QtCore.QUrl("https://docs.gns3.com/"))
def _checkForUpdateActionSlot(self, silent=False):
"""
@@ -1058,11 +1073,17 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
with Progress.instance().context(min_duration=0):
dialog = PreferencesDialog(self)
dialog.restoreGeometry(QtCore.QByteArray().fromBase64(self._settings["preferences_dialog_geometry"].encode()))
#dialog.restoreGeometry(QtCore.QByteArray().fromBase64(self._settings["preferences_dialog_geometry"].encode()))
dialog.show()
dialog.exec_()
self._settings["preferences_dialog_geometry"] = bytes(dialog.saveGeometry().toBase64()).decode()
self.setSettings(self._settings)
#self._settings["preferences_dialog_geometry"] = bytes(dialog.saveGeometry().toBase64()).decode()
#self.setSettings(self._settings)
def _editReadmeActionSlot(self):
"""
Slot to edit the README file
"""
Topology.instance().editReadme()
def resizeEvent(self, event):
self._notif_dialog.resize()
@@ -1182,8 +1203,9 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
# restore debug level
if self._settings["debug_level"]:
print("Activating debugging (use command 'debug 0' to deactivate)")
root = logging.getLogger()
root.addHandler(logging.StreamHandler(sys.stdout))
root.setLevel(logging.DEBUG)
# restore the style
self._setStyle(self._settings.get("style"))

View File

@@ -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):
"""

View File

@@ -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):
"""

View File

@@ -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):
"""

View File

@@ -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):
"""

View File

@@ -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):
"""

View File

@@ -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):
"""
@@ -210,7 +211,7 @@ class IOUDevicePreferencesPage(QtWidgets.QWidget, Ui_IOUDevicePreferencesPageWid
del self._iou_devices[key]
item.setText(0, iou_device["name"])
item.setData(0, QtCore.Qt.UserRole, new_key)
self._refreshInfo(dialog.settings)
self._refreshInfo(dialog.settings())
def _iouDeviceDeleteSlot(self):
"""

View File

@@ -47,7 +47,6 @@ class QemuVMWizard(VMWithImagesWizard, Ui_QemuVMWizard):
# Mandatory fields
self.uiNameWizardPage.registerField("vm_name*", self.uiNameLineEdit)
self.uiDiskWizardPage.registerField("hda_disk_image*", self.uiHdaDiskImageLineEdit)
self.uiInitrdKernelImageWizardPage.registerField("initrd*", self.uiInitrdImageLineEdit)
self.uiInitrdKernelImageWizardPage.registerField("kernel_image*", self.uiKernelImageLineEdit)
@@ -153,17 +152,19 @@ class QemuVMWizard(VMWithImagesWizard, Ui_QemuVMWizard):
"qemu_path": qemu_path,
"compute_id": self._compute_id,
"category": Node.end_devices,
"hda_disk_image": self.uiHdaDiskImageLineEdit.text(),
"console_type": console_type
}
if self.uiHdaDiskImageLineEdit.text().strip():
settings["hda_disk_image"] = self.uiHdaDiskImageLineEdit.text().strip()
if self.uiLegacyASACheckBox.isChecked():
# special settings for legacy ASA VM
settings["adapters"] = 4
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"
@@ -176,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

View File

@@ -78,7 +78,7 @@ class QemuVMConfigurationPage(QtWidgets.QWidget, Ui_QemuVMConfigPageWidget):
self.uiHdcDiskImageResizeToolButton.clicked.connect(self._hdcDiskImageResizeSlot)
self.uiHddDiskImageResizeToolButton.clicked.connect(self._hddDiskImageResizeSlot)
disk_interfaces = ["ide", "sata", "scsi", "sd", "mtd", "floppy", "pflash", "virtio", "none"]
disk_interfaces = ["ide", "sata", "nvme", "scsi", "sd", "mtd", "floppy", "pflash", "virtio", "none"]
self.uiHdaDiskInterfaceComboBox.addItems(disk_interfaces)
self.uiHdbDiskInterfaceComboBox.addItems(disk_interfaces)
self.uiHdcDiskInterfaceComboBox.addItems(disk_interfaces)
@@ -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():
@@ -99,8 +100,14 @@ class QemuVMConfigurationPage(QtWidgets.QWidget, Ui_QemuVMConfigPageWidget):
for name, option_name in Node.onCloseOptions().items():
self.uiOnCloseComboBox.addItem(name, option_name)
# 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"),
("e1000-82545em", "Intel 82545EM Gigabit Ethernet"),
("e1000e", "Intel PCIe Gigabit Ethernet"),
("i82550", "Intel i82550 Ethernet"),
("i82551", "Intel i82551 Ethernet"),
("i82557a", "Intel i82557A Ethernet"),
@@ -116,6 +123,7 @@ class QemuVMConfigurationPage(QtWidgets.QWidget, Ui_QemuVMConfigPageWidget):
("i82801", "Intel i82801 Ethernet"),
("ne2k_pci", "NE2000 Ethernet"),
("pcnet", "AMD PCNet Ethernet"),
("rocker", "Rocker L2 switch device"),
("rtl8139", "Realtek 8139 Ethernet"),
("virtio", "Legacy paravirtualized Network I/O"),
("virtio-net-pci", "Paravirtualized Network I/O"),
@@ -147,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
@@ -360,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
@@ -395,7 +419,17 @@ class QemuVMConfigurationPage(QtWidgets.QWidget, Ui_QemuVMConfigPageWidget):
QtWidgets.QMessageBox.critical(self, "Invalid format", "Invalid port name format")
return
dialog = CustomAdaptersConfigurationDialog(ports, self._custom_adapters, default_adapter, self._qemu_network_devices, base_mac_address, parent=self)
if self.uiLegacyNetworkingCheckBox.isChecked():
network_devices = {}
for nic, desc in self._qemu_network_devices.items():
if nic in self._legacy_devices:
network_devices[nic] = desc
else:
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()
dialog.exec_()
@@ -439,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"])
@@ -511,6 +546,7 @@ class QemuVMConfigurationPage(QtWidgets.QWidget, Ui_QemuVMConfigPageWidget):
self._custom_adapters = settings["custom_adapters"].copy()
self.uiLegacyNetworkingCheckBox.setChecked(settings["legacy_networking"])
self.uiReplicateNetworkConnectionStateCheckBox.setChecked(settings["replicate_network_connection_state"])
# load the MAC address setting
self.uiMacAddrLineEdit.setInputMask("HH:HH:HH:HH:HH:HH;_")
@@ -573,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()
@@ -642,6 +679,8 @@ class QemuVMConfigurationPage(QtWidgets.QWidget, Ui_QemuVMConfigPageWidget):
raise ConfigurationError()
settings["adapters"] = adapters
settings["legacy_networking"] = self.uiLegacyNetworkingCheckBox.isChecked()
settings["replicate_network_connection_state"] = self.uiReplicateNetworkConnectionStateCheckBox.isChecked()
settings["custom_adapters"] = self._custom_adapters.copy()
settings["on_close"] = self.uiOnCloseComboBox.itemData(self.uiOnCloseComboBox.currentIndex())
settings["cpus"] = self.uiCPUSpinBox.value()

View File

@@ -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):
"""

View File

@@ -71,6 +71,8 @@ class QemuVM(Node):
"adapter_type": QEMU_VM_SETTINGS["adapter_type"],
"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"],
@@ -133,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.

View File

@@ -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",
@@ -56,6 +56,8 @@ QEMU_VM_SETTINGS = {
"adapter_type": "e1000",
"mac_address": "",
"legacy_networking": False,
"replicate_network_connection_state": True,
"create_config_disk": False,
"on_close": "power_off",
"platform": "",
"cpu_throttling": 0,

View File

@@ -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>
@@ -526,6 +542,23 @@
<string>Network</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_5">
<item row="3" column="0">
<widget class="QLabel" name="uiPortSegmentSizeLabel">
<property name="text">
<string>Segment size:</string>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<widget class="QSpinBox" name="uiPortSegmentSizeSpinBox">
<property name="maximum">
<number>128</number>
</property>
<property name="singleStep">
<number>4</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="uiAdaptersLabel">
<property name="text">
@@ -560,13 +593,6 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="uiPortSegmentSizeLabel">
<property name="text">
<string>Segment size:</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="uiMacAddrLabel">
<property name="text">
@@ -598,14 +624,14 @@
</property>
</widget>
</item>
<item row="7" column="0" colspan="3">
<item row="8" column="0" colspan="3">
<widget class="QCheckBox" name="uiLegacyNetworkingCheckBox">
<property name="text">
<string>Use the legacy networking mode</string>
</property>
</widget>
</item>
<item row="8" column="2">
<item row="9" column="2">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -628,16 +654,6 @@
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<widget class="QSpinBox" name="uiPortSegmentSizeSpinBox">
<property name="maximum">
<number>128</number>
</property>
<property name="singleStep">
<number>4</number>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QSpinBox" name="uiAdaptersSpinBox">
<property name="sizePolicy">
@@ -654,6 +670,13 @@
</property>
</widget>
</item>
<item row="7" column="0" colspan="3">
<widget class="QCheckBox" name="uiReplicateNetworkConnectionStateCheckBox">
<property name="text">
<string>Replicate network connection states in Qemu</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="uiAdvancedSettingsTab">

View File

@@ -2,16 +2,18 @@
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/modules/qemu/ui/qemu_vm_configuration_page.ui'
#
# Created by: PyQt5 UI code generator 5.9
# Created by: PyQt5 UI code generator 5.13.2
#
# WARNING! All changes made in this file will be lost!
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)
@@ -209,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)
@@ -227,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)
@@ -268,6 +273,14 @@ class Ui_QemuVMConfigPageWidget(object):
self.uiNetworkTab.setObjectName("uiNetworkTab")
self.gridLayout_5 = QtWidgets.QGridLayout(self.uiNetworkTab)
self.gridLayout_5.setObjectName("gridLayout_5")
self.uiPortSegmentSizeLabel = QtWidgets.QLabel(self.uiNetworkTab)
self.uiPortSegmentSizeLabel.setObjectName("uiPortSegmentSizeLabel")
self.gridLayout_5.addWidget(self.uiPortSegmentSizeLabel, 3, 0, 1, 1)
self.uiPortSegmentSizeSpinBox = QtWidgets.QSpinBox(self.uiNetworkTab)
self.uiPortSegmentSizeSpinBox.setMaximum(128)
self.uiPortSegmentSizeSpinBox.setSingleStep(4)
self.uiPortSegmentSizeSpinBox.setObjectName("uiPortSegmentSizeSpinBox")
self.gridLayout_5.addWidget(self.uiPortSegmentSizeSpinBox, 3, 1, 1, 2)
self.uiAdaptersLabel = QtWidgets.QLabel(self.uiNetworkTab)
self.uiAdaptersLabel.setObjectName("uiAdaptersLabel")
self.gridLayout_5.addWidget(self.uiAdaptersLabel, 0, 0, 1, 1)
@@ -284,9 +297,6 @@ class Ui_QemuVMConfigPageWidget(object):
self.uiPortNameFormatLineEdit.setText("")
self.uiPortNameFormatLineEdit.setObjectName("uiPortNameFormatLineEdit")
self.gridLayout_5.addWidget(self.uiPortNameFormatLineEdit, 2, 1, 1, 2)
self.uiPortSegmentSizeLabel = QtWidgets.QLabel(self.uiNetworkTab)
self.uiPortSegmentSizeLabel.setObjectName("uiPortSegmentSizeLabel")
self.gridLayout_5.addWidget(self.uiPortSegmentSizeLabel, 3, 0, 1, 1)
self.uiMacAddrLabel = QtWidgets.QLabel(self.uiNetworkTab)
self.uiMacAddrLabel.setObjectName("uiMacAddrLabel")
self.gridLayout_5.addWidget(self.uiMacAddrLabel, 4, 0, 1, 1)
@@ -304,9 +314,9 @@ class Ui_QemuVMConfigPageWidget(object):
self.gridLayout_5.addWidget(self.uiCustomAdaptersConfigurationPushButton, 6, 1, 1, 2)
self.uiLegacyNetworkingCheckBox = QtWidgets.QCheckBox(self.uiNetworkTab)
self.uiLegacyNetworkingCheckBox.setObjectName("uiLegacyNetworkingCheckBox")
self.gridLayout_5.addWidget(self.uiLegacyNetworkingCheckBox, 7, 0, 1, 3)
self.gridLayout_5.addWidget(self.uiLegacyNetworkingCheckBox, 8, 0, 1, 3)
spacerItem3 = QtWidgets.QSpacerItem(20, 261, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout_5.addItem(spacerItem3, 8, 2, 1, 1)
self.gridLayout_5.addItem(spacerItem3, 9, 2, 1, 1)
self.uiAdapterTypesComboBox = QtWidgets.QComboBox(self.uiNetworkTab)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
@@ -315,11 +325,6 @@ class Ui_QemuVMConfigPageWidget(object):
self.uiAdapterTypesComboBox.setSizePolicy(sizePolicy)
self.uiAdapterTypesComboBox.setObjectName("uiAdapterTypesComboBox")
self.gridLayout_5.addWidget(self.uiAdapterTypesComboBox, 5, 1, 1, 2)
self.uiPortSegmentSizeSpinBox = QtWidgets.QSpinBox(self.uiNetworkTab)
self.uiPortSegmentSizeSpinBox.setMaximum(128)
self.uiPortSegmentSizeSpinBox.setSingleStep(4)
self.uiPortSegmentSizeSpinBox.setObjectName("uiPortSegmentSizeSpinBox")
self.gridLayout_5.addWidget(self.uiPortSegmentSizeSpinBox, 3, 1, 1, 2)
self.uiAdaptersSpinBox = QtWidgets.QSpinBox(self.uiNetworkTab)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
@@ -330,6 +335,9 @@ class Ui_QemuVMConfigPageWidget(object):
self.uiAdaptersSpinBox.setMaximum(275)
self.uiAdaptersSpinBox.setObjectName("uiAdaptersSpinBox")
self.gridLayout_5.addWidget(self.uiAdaptersSpinBox, 0, 1, 1, 2)
self.uiReplicateNetworkConnectionStateCheckBox = QtWidgets.QCheckBox(self.uiNetworkTab)
self.uiReplicateNetworkConnectionStateCheckBox.setObjectName("uiReplicateNetworkConnectionStateCheckBox")
self.gridLayout_5.addWidget(self.uiReplicateNetworkConnectionStateCheckBox, 7, 0, 1, 3)
self.uiQemutabWidget.addTab(self.uiNetworkTab, "")
self.uiAdvancedSettingsTab = QtWidgets.QWidget()
self.uiAdvancedSettingsTab.setObjectName("uiAdvancedSettingsTab")
@@ -492,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..."))
@@ -502,16 +511,17 @@ class Ui_QemuVMConfigPageWidget(object):
self.uiCdromImageLabel.setText(_translate("QemuVMConfigPageWidget", "Image:"))
self.uiCdromImageToolButton.setText(_translate("QemuVMConfigPageWidget", "&Browse..."))
self.uiQemutabWidget.setTabText(self.uiQemutabWidget.indexOf(self.uiCdromTab), _translate("QemuVMConfigPageWidget", "CD/DVD"))
self.uiPortSegmentSizeLabel.setText(_translate("QemuVMConfigPageWidget", "Segment size:"))
self.uiAdaptersLabel.setText(_translate("QemuVMConfigPageWidget", "Adapters:"))
self.uiFirstPortNameLabel.setText(_translate("QemuVMConfigPageWidget", "First port name:"))
self.uiPortNameFormatLabel.setToolTip(_translate("QemuVMConfigPageWidget", "<html><head/><body><p>{0} - the port number, from 0 to the number of adapters-1.</p><p>{1} - the segment number, from 0 to the number of segments-1.</p><p>{port0} - named alias for {0}.</p><p>{port1} - the port number, from 1 to the number of adapters.</p><p>{segment0} - named alias for {1}.</p><p>{segment1} - the segment number, from 1 to the number of segments.</p></body></html>"))
self.uiPortNameFormatLabel.setText(_translate("QemuVMConfigPageWidget", "Name format:"))
self.uiPortSegmentSizeLabel.setText(_translate("QemuVMConfigPageWidget", "Segment size:"))
self.uiMacAddrLabel.setText(_translate("QemuVMConfigPageWidget", "Base MAC:"))
self.uiAdapterTypesLabel.setText(_translate("QemuVMConfigPageWidget", "Type:"))
self.uiCustomAdaptersLabel.setText(_translate("QemuVMConfigPageWidget", "Custom adapters:"))
self.uiCustomAdaptersConfigurationPushButton.setText(_translate("QemuVMConfigPageWidget", "&Configure custom adapters"))
self.uiLegacyNetworkingCheckBox.setText(_translate("QemuVMConfigPageWidget", "Use the legacy networking mode"))
self.uiReplicateNetworkConnectionStateCheckBox.setText(_translate("QemuVMConfigPageWidget", "Replicate network connection states in Qemu"))
self.uiQemutabWidget.setTabText(self.uiQemutabWidget.indexOf(self.uiNetworkTab), _translate("QemuVMConfigPageWidget", "Network"))
self.uiLinuxBootGroupBox.setTitle(_translate("QemuVMConfigPageWidget", "Linux boot specific settings"))
self.uiKernelCommandLineLabel.setText(_translate("QemuVMConfigPageWidget", "Kernel command line:"))
@@ -548,4 +558,3 @@ class Ui_QemuVMConfigPageWidget(object):
self.uiBaseVMCheckBox.setText(_translate("QemuVMConfigPageWidget", "Use as a linked base VM"))
self.uiQemutabWidget.setTabText(self.uiQemutabWidget.indexOf(self.uiAdvancedSettingsTab), _translate("QemuVMConfigPageWidget", "Advanced"))
self.uiQemutabWidget.setTabText(self.uiQemutabWidget.indexOf(self.uiUsageTab), _translate("QemuVMConfigPageWidget", "Usage"))

View File

@@ -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):
"""

View File

@@ -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):
"""

View File

@@ -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):
"""

View File

@@ -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]
@@ -641,7 +661,7 @@ class Node(BaseNode):
Get the console type (serial, telnet or VNC)
"""
console_type = "telnet"
console_type = "none"
if "console_type" in self.settings():
return self.settings()["console_type"]
return console_type
@@ -654,7 +674,7 @@ class Node(BaseNode):
"""
host = self.settings()["console_host"]
if host is None or host == "::" or host == "0.0.0.0":
if host is None or host == "::" or host == "0.0.0.0" or host == "0:0:0:0:0:0:0:0":
host = Controller.instance().host()
return host
@@ -704,10 +724,10 @@ class Node(BaseNode):
nodeTelnetConsole(self, console_port, command)
elif console_type == "vnc":
from .vnc_console import vncConsole
vncConsole(self.consoleHost(), console_port, command)
vncConsole(self, console_port, command)
elif console_type.startswith("spice"):
from .spice_console import spiceConsole
spiceConsole(self.consoleHost(), console_port, command)
spiceConsole(self, console_port, command)
elif console_type == "http" or console_type == "https":
QtGui.QDesktopServices.openUrl(QtCore.QUrl("{console_type}://{host}:{port}{path}".format(console_type=console_type, host=self.consoleHost(), port=console_port, path=self.consoleHttpPath())))
@@ -774,7 +794,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 +833,7 @@ class Node(BaseNode):
:param directory: source directory path
"""
if not hasattr(self, "configFiles"):
if not self.configFiles():
return
try:

View File

@@ -142,19 +142,30 @@ class NodesView(QtWidgets.QTreeWidget):
# when we're in docked mode, outside main window
return self.window().parent()
def mousePressEvent(self, event):
def contextMenuEvent(self, event):
"""
Handles all mouse press events.
Handles all context menu events.
:param: QMouseEvent instance
:param event: QContextMenuEvent instance
"""
# Check that an item has been selected and right click
if event.button() == QtCore.Qt.RightButton:
self._showContextualMenu()
event.accept()
return
super().mousePressEvent(event)
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):
"""
@@ -181,7 +192,7 @@ class NodesView(QtWidgets.QTreeWidget):
drag.exec_(QtCore.Qt.CopyAction)
event.accept()
def _showContextualMenu(self):
def _showContextualMenu(self, pos):
menu = QtWidgets.QMenu()
refresh_action = QtWidgets.QAction("Refresh templates", menu)
@@ -207,16 +218,16 @@ class NodesView(QtWidgets.QTreeWidget):
delete_action.triggered.connect(qpartial(self._deleteSlot, template))
menu.addAction(delete_action)
menu.exec_(QtGui.QCursor.pos())
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)

View File

@@ -38,7 +38,7 @@ class PacketCapture:
def __init__(self):
self._tail_process = {}
self._capture_reader_process = {}
# Auto start the capture program for th link
# Auto start the capture program for this link
self._autostart = {}
Topology.instance().project_changed_signal.connect(self.killAllCapture)
@@ -47,6 +47,7 @@ class PacketCapture:
"""
Kill all running captures (for example when change project)
"""
for process in list(self._tail_process.values()):
try:
process.kill()
@@ -89,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)
@@ -107,7 +107,6 @@ class PacketCapture:
"""
link.stopCapture()
log.debug("Has successfully stopped capturing packets on {}".format(link.id()))
def startPacketCaptureReader(self, link):
"""
@@ -120,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]

View File

@@ -421,8 +421,6 @@ class GeneralPreferencesPage(QtWidgets.QWidget, Ui_GeneralPreferencesPageWidget)
new_graphics_view_settings = {"scene_width": self.uiSceneWidthSpinBox.value(),
"scene_height": self.uiSceneHeightSpinBox.value(),
"grid_size": self.uiNodeGridSizeSpinBox.value(),
"drawing_grid_size": self.uiDrawingGridSizeSpinBox.value(),
"draw_rectangle_selected_item": self.uiRectangleSelectedItemCheckBox.isChecked(),
"draw_link_status_points": self.uiDrawLinkStatusPointsCheckBox.isChecked(),
"show_interface_labels_on_new_project": self.uiShowInterfaceLabelsOnNewProject.isChecked(),
@@ -433,4 +431,12 @@ class GeneralPreferencesPage(QtWidgets.QWidget, Ui_GeneralPreferencesPageWidget)
"default_label_color": self._default_label_color.name(),
"default_note_font": self.uiDefaultNoteStylePlainTextEdit.font().toString(),
"default_note_color": self._default_note_color.name()}
node_grid_size = self.uiNodeGridSizeSpinBox.value()
drawing_grid_size = self.uiDrawingGridSizeSpinBox.value()
if node_grid_size % drawing_grid_size != 0:
QtWidgets.QMessageBox.critical(self, "Grid sizes", "Invalid grid sizes which will create overlapping lines")
else:
new_graphics_view_settings["grid_size"] = node_grid_size
new_graphics_view_settings["drawing_grid_size"] = drawing_grid_size
MainWindow.instance().uiGraphicsView.setSettings(new_graphics_view_settings)

View File

@@ -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):
@@ -66,8 +67,26 @@ class GNS3VMPreferencesPage(QtWidgets.QWidget, Ui_GNS3VMPreferencesPageWidget):
self.uiRamLabel.setVisible(engine["support_ram"])
self.uiRamSpinBox.setVisible(engine["support_ram"])
self.uiCpuSpinBox.setVisible(engine["support_ram"])
if engine_id == "remote":
self.uiPortLabel.setVisible(False)
self.uiPortSpinBox.setVisible(False)
else:
self.uiPortLabel.setVisible(True)
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.
@@ -89,8 +108,10 @@ 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))
self.uiEnableVMCheckBox.setChecked(self._settings["enable"])
if self._settings["when_exit"] == "keep":
self.uiWhenExitKeepRadioButton.setChecked(True)
@@ -167,8 +188,10 @@ 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()
"vcpus": self.uiCpuSpinBox.value(),
"port": self.uiPortSpinBox.value()
}
if self._old_settings != settings:
Controller.instance().put("/gns3vm", self._saveSettingsCallback, settings, timeout=60 * 5)

View File

@@ -67,6 +67,7 @@ class ServerPreferencesPage(QtWidgets.QWidget, Ui_ServerPreferencesPageWidget):
# ignore link-local addresses
continue
self.uiLocalServerHostComboBox.addItem(address_string, address_string)
self.uiLocalServerHostComboBox.addItem("localhost", "localhost") # local host
self.uiLocalServerHostComboBox.addItem("::", "::") # all IPv6 addresses
self.uiLocalServerHostComboBox.addItem("0.0.0.0", "0.0.0.0") # all IPv4 addresses
@@ -190,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"])
@@ -284,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()

View File

@@ -520,10 +520,12 @@ class Project(QtCore.QObject):
def load(self, path=None):
if not path:
path = self.path()
if path:
if not Controller.instance().isRemote() and path:
# load a local project from file
body = {"path": path}
Controller.instance().post("/projects/load", self._projectOpenCallback, body=body, timeout=None)
else:
# open a local/remote project
self.post("/open", self._projectOpenCallback, timeout=None)
def _projectOpenCallback(self, result, error=False, **kwargs):
@@ -630,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):
"""
@@ -646,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:

View File

@@ -115,10 +115,13 @@ class LogQMessageBox(QtWidgets.QMessageBox):
show a stack trace when a critical message box is shown in debug mode
"""
@staticmethod
def critical(parent, title, message, *args):
def critical(parent, title, message, *args, show_stack_info=False):
if message.startswith("QXcbConnection"): # Qt noise not relevant
return
LogQMessageBox._get_logger().critical(re.sub(r"<[^<]+?>", "", message), stack_info=LogQMessageBox.stack_info())
stack_info = None
if show_stack_info:
stack_info = LogQMessageBox.stack_info()
LogQMessageBox._get_logger().critical(re.sub(r"<[^<]+?>", "", message), stack_info=stack_info)
if parent is False:
# special case to display a QMessageBox before the main window is created.
parent = None

View File

@@ -19,7 +19,7 @@
import json
import copy
import os
import collections
import collections.abc
import jsonschema
@@ -30,7 +30,7 @@ class ApplianceError(Exception):
pass
class Appliance(collections.Mapping):
class Appliance(collections.abc.Mapping):
def __init__(self, registry, path):
"""
@@ -115,22 +115,14 @@ class Appliance(collections.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 len(self._appliance["versions"]) == 0:
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):
"""

View File

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

View File

@@ -266,6 +266,9 @@
"adapter_type": {
"enum": [
"e1000",
"e1000-82544gc",
"e1000-82545em",
"e1000e",
"i82550",
"i82551",
"i82557a",
@@ -281,6 +284,7 @@
"i82801",
"ne2k_pci",
"pcnet",
"rocker",
"rtl8139",
"virtio",
"virtio-net-pci",
@@ -301,19 +305,19 @@
"title": "Number of Virtual CPU"
},
"hda_disk_interface": {
"enum": ["ide", "scsi", "sd", "mtd", "floppy", "pflash", "virtio", "sata"],
"enum": ["ide", "sata", "nvme","scsi", "sd", "mtd", "floppy", "pflash", "virtio", "none"],
"title": "Disk interface for the installed hda_disk_image"
},
"hdb_disk_interface": {
"enum": ["ide", "scsi", "sd", "mtd", "floppy", "pflash", "virtio", "sata"],
"enum": ["ide", "sata", "nvme", "scsi", "sd", "mtd", "floppy", "pflash", "virtio", "none"],
"title": "Disk interface for the installed hdb_disk_image"
},
"hdc_disk_interface": {
"enum": ["ide", "scsi", "sd", "mtd", "floppy", "pflash", "virtio", "sata"],
"enum": ["ide", "sata", "nvme", "scsi", "sd", "mtd", "floppy", "pflash", "virtio", "none"],
"title": "Disk interface for the installed hdc_disk_image"
},
"hdd_disk_interface": {
"enum": ["ide", "scsi", "sd", "mtd", "floppy", "pflash", "virtio", "sata"],
"enum": ["ide", "sata", "nvme", "scsi", "sd", "mtd", "floppy", "pflash", "virtio", "none"],
"title": "Disk interface for the installed hdd_disk_image"
},
"arch": {

View File

@@ -40,7 +40,7 @@ DEFAULT_CONFIGS_PATH = os.path.normpath(os.path.expanduser("~/GNS3/configs"))
# Default appliances location
DEFAULT_APPLIANCES_PATH = os.path.normpath(os.path.expanduser("~/GNS3/appliances"))
DEFAULT_LOCAL_SERVER_HOST = "127.0.0.1"
DEFAULT_LOCAL_SERVER_HOST = "localhost"
DEFAULT_LOCAL_SERVER_PORT = 3080
DEFAULT_DELAY_CONSOLE_ALL = 500
@@ -58,7 +58,8 @@ if sys.platform.startswith("win"):
PRECONFIGURED_TELNET_CONSOLE_COMMANDS = {'Putty (normal standalone version)': 'putty_standalone.exe -telnet %h %p -loghost "%d"',
'Putty (custom deprecated version)': 'putty.exe -telnet %h %p -wt "%d" -gns3 5 -skin 4',
'MobaXterm': r'"{}\Mobatek\MobaXterm Personal Edition\MobaXterm.exe" -newtab "telnet %h %p"'.format(program_files_x86),
'Royal TS': r'{}\code4ward.net\Royal TS V3\RTS3App.exe /connectadhoc:%h /adhoctype:terminal /p:IsTelnetConnection="true" /p:ConnectionType="telnet;Telnet Connection" /p:Port="%p" /p:Name="%d"'.format(program_files),
'Royal TS V3': r'{}\code4ward.net\Royal TS V3\RTS3App.exe /connectadhoc:%h /adhoctype:terminal /p:IsTelnetConnection="true" /p:ConnectionType="telnet;Telnet Connection" /p:Port="%p" /p:Name="%d"'.format(program_files),
'Royal TS V5': r'"{}\Royal TS V5\RoyalTS.exe" /protocol:terminal /using:adhoc /uri:"%h" /property:Port="%p" /property:IsTelnetConnection="true" /property:Name="%d"'.format(program_files_x86),
'SuperPutty': r'SuperPutty.exe -telnet "%h -P %p -wt \"%d\""',
'SecureCRT': r'"{}\VanDyke Software\SecureCRT\SecureCRT.exe" /N "%d" /T /TELNET %h %p'.format(program_files),
'SecureCRT (personal profile)': r'"{}\AppData\Local\VanDyke Software\SecureCRT\SecureCRT.exe" /T /N "%d" /TELNET %h %p'.format(userprofile),
@@ -140,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
@@ -156,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"]
@@ -197,7 +202,8 @@ else:
PRECONFIGURED_VNC_CONSOLE_COMMANDS = {
'TightVNC': 'vncviewer %h:%p',
'Vinagre': 'vinagre %h::%p',
'gvncviewer': 'gvncviewer %h:%P'
'gvncviewer': 'gvncviewer %h:%P',
'Remote Viewer': 'remote-viewer vnc://%h:%p'
}
# default VNC console command on other systems
@@ -293,7 +299,7 @@ GENERAL_SETTINGS = {
"recent_projects": [],
"geometry": "",
"state": "",
"preferences_dialog_geometry": "",
#"preferences_dialog_geometry": "",
"debug_level": 0,
"multi_profiles": False,
"hdpi": not sys.platform.startswith("linux"),
@@ -330,7 +336,7 @@ GRAPHICS_VIEW_SETTINGS = {
LOCAL_SERVER_SETTINGS = {
"path": "gns3server",
"ubridge_path": "ubridge",
"host": "0.0.0.0",
"host": "localhost",
"port": DEFAULT_LOCAL_SERVER_PORT,
"images_path": DEFAULT_IMAGES_PATH,
"projects_path": DEFAULT_PROJECTS_PATH,

View File

@@ -24,15 +24,17 @@ import os
import shlex
import subprocess
from .controller import Controller
import logging
log = logging.getLogger(__name__)
def spiceConsole(host, port, command):
def spiceConsole(node, port, command):
"""
Start a SPICE console program.
:param host: host or IP address
:param node: Node instance
:param port: port number
:param command: command to be executed
"""
@@ -41,6 +43,9 @@ def spiceConsole(host, port, command):
log.error("SPICE client is not configured")
return
name = node.name()
host = node.consoleHost()
# ipv6 support
if ":" in host:
host = "[{}]".format(host)
@@ -48,6 +53,9 @@ def spiceConsole(host, port, command):
# replace the place-holders by the actual values
command = command.replace("%h", host)
command = command.replace("%p", str(port))
command = command.replace("%d", name.replace('"', '\\"'))
command = command.replace("%i", node.project().id())
command = command.replace("%n", str(node.id()))
try:
log.debug('starting SPICE program "{}"'.format(command))

View File

@@ -76,6 +76,7 @@ class Style:
self._mw.uiDrawRectangleAction.setIcon(self._getStyleIcon(":/icons/rectangle.svg", ":/icons/rectangle-hover.svg"))
self._mw.uiDrawEllipseAction.setIcon(self._getStyleIcon(":/icons/ellipse.svg", ":/icons/ellipse-hover.svg"))
self._mw.uiDrawLineAction.setIcon(QtGui.QIcon(":/icons/vertically.svg"))
self._mw.uiEditReadmeAction.setIcon(QtGui.QIcon(":/icons/edit.svg"))
self._mw.uiOnlineHelpAction.setIcon(QtGui.QIcon(":/icons/help.svg"))
self._mw.uiBrowseRoutersAction.setIcon(self._getStyleIcon(":/icons/router.png", ":/icons/router-hover.png"))
self._mw.uiBrowseSwitchesAction.setIcon(self._getStyleIcon(":/icons/switch.png", ":/icons/switch-hover.png"))
@@ -127,6 +128,7 @@ class Style:
self._mw.uiDrawRectangleAction.setIcon(self._getStyleIcon(":/classic_icons/rectangle.svg", ":/classic_icons/rectangle-hover.svg"))
self._mw.uiDrawEllipseAction.setIcon(self._getStyleIcon(":/classic_icons/ellipse.svg", ":/classic_icons/ellipse-hover.svg"))
self._mw.uiDrawLineAction.setIcon(self._getStyleIcon(":/classic_icons/line.svg", ":/classic_icons/line-hover.svg"))
self._mw.uiEditReadmeAction.setIcon(self._getStyleIcon(":/classic_icons/edit.svg", ":/classic_icons/edit-hover.svg"))
self._mw.uiOnlineHelpAction.setIcon(self._getStyleIcon(":/classic_icons/help.svg", ":/classic_icons/help-hover.svg"))
self._mw.uiBrowseRoutersAction.setIcon(self._getStyleIcon(":/classic_icons/router.svg", ":/classic_icons/router-hover.svg"))
self._mw.uiBrowseSwitchesAction.setIcon(self._getStyleIcon(":/classic_icons/switch.svg", ":/classic_icons/switch-hover.svg"))
@@ -188,6 +190,7 @@ class Style:
self._mw.uiDrawRectangleAction.setIcon(self._getStyleIcon(":/charcoal_icons/rectangle.svg", ":/charcoal_icons/rectangle-hover.svg"))
self._mw.uiDrawEllipseAction.setIcon(self._getStyleIcon(":/charcoal_icons/ellipse.svg", ":/charcoal_icons/ellipse-hover.svg"))
self._mw.uiDrawLineAction.setIcon(self._getStyleIcon(":/charcoal_icons/line.svg", ":/charcoal_icons/line-hover.svg"))
self._mw.uiEditReadmeAction.setIcon(self._getStyleIcon(":/charcoal_icons/edit.svg", ":/charcoal_icons/edit-hover.svg"))
self._mw.uiOnlineHelpAction.setIcon(self._getStyleIcon(":/charcoal_icons/help.svg", ":/charcoal_icons/help-hover.svg"))
self._mw.uiBrowseRoutersAction.setIcon(self._getStyleIcon(":/charcoal_icons/router.svg", ":/charcoal_icons/router-hover.svg"))
self._mw.uiBrowseSwitchesAction.setIcon(self._getStyleIcon(":/charcoal_icons/switch.svg", ":/charcoal_icons/switch-hover.svg"))

View File

@@ -29,6 +29,7 @@ from .qt import QtCore, QtWidgets
from .utils.progress_dialog import ProgressDialog
from .utils.import_project_worker import ImportProjectWorker
from .dialogs.project_export_wizard import ExportProjectWizard
from .dialogs.file_editor_dialog import FileEditorDialog
from .dialogs.project_welcome_dialog import ProjectWelcomeDialog
from .modules import MODULES
@@ -61,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
@@ -144,7 +145,7 @@ class Topology(QtCore.QObject):
self._main_window.uiGraphicsView.setDrawingGridSize(self._project.drawingGridSize())
self._main_window.uiShowGridAction.setChecked(self._project.showGrid())
self._main_window.showGrid(self._project.showGrid())
if os.path.exists(project_file):
if not Controller.instance().isRemote() and os.path.exists(project_file):
self._main_window.updateRecentFileSettings(project_file)
self._main_window.updateRecentFileActions()
@@ -243,6 +244,13 @@ class Topology(QtCore.QObject):
self._main_window.uiStatusBar.showMessage("Project loaded {}".format(path), 2000)
return True
def editReadme(self):
if self.project() is None:
return
dialog = FileEditorDialog(self.project(), "README.txt", parent=self._main_window, default="Project title\n\nAuthor: Grace Hopper <grace@example.org>\n\nThis project is about...")
dialog.show()
dialog.exec_()
def _projectCreationErrorSlot(self, message):
if self._project:
self._project.project_creation_error_signal.disconnect(self._projectCreationErrorSlot)

View File

@@ -267,19 +267,16 @@ class TopologySummaryView(QtWidgets.QTreeWidget):
if item.link() == link:
view.centerOn(item)
def mousePressEvent(self, event):
def contextMenuEvent(self, event):
"""
Handles all mouse press events.
Handles all context menu events.
:param event: QMouseEvent instance
:param event: QContextMenuEvent instance
"""
if event.button() == QtCore.Qt.RightButton:
self._showContextualMenu()
else:
super().mousePressEvent(event)
self._showContextualMenu(event.globalPos())
def _showContextualMenu(self):
def _showContextualMenu(self, pos):
"""
Contextual menu to expand and collapse the tree.
"""
@@ -322,6 +319,11 @@ class TopologySummaryView(QtWidgets.QTreeWidget):
reset_all_filters.triggered.connect(self._resetAllFiltersSlot)
menu.addAction(reset_all_filters)
resume_suspended_links = QtWidgets.QAction("Resume all suspended links", menu)
resume_suspended_links.setIcon(get_icon("start.svg"))
resume_suspended_links.triggered.connect(self._resumeAllLinksSlot)
menu.addAction(resume_suspended_links)
current_item = self.currentItem()
from .main_window import MainWindow
view = MainWindow.instance().uiGraphicsView
@@ -336,7 +338,7 @@ class TopologySummaryView(QtWidgets.QTreeWidget):
item.populateLinkContextualMenu(menu)
break
menu.exec_(QtGui.QCursor.pos())
menu.exec_(pos)
@qslot
def _expandAllSlot(self, *args):
@@ -403,3 +405,13 @@ class TopologySummaryView(QtWidgets.QTreeWidget):
filters = {}
link.setFilters(filters)
link.update()
@qslot
def _resumeAllLinksSlot(self, *args):
"""
Resume all suspended links.
"""
for link in self._topology.links():
if link.suspended():
link.toggleSuspend()

View File

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

View File

@@ -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:"))

View File

@@ -64,21 +64,21 @@
<item row="1" column="1" colspan="2">
<widget class="QComboBox" name="uiCompressionComboBox"/>
</item>
<item row="2" column="0" colspan="3">
<item row="3" column="0" colspan="3">
<widget class="QCheckBox" name="uiIncludeImagesCheckBox">
<property name="text">
<string>Include base images</string>
<string>&amp;Include base images</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="uiIncludeSnapshotsCheckBox">
<property name="text">
<string>Include snapshots</string>
<string>&amp;Include snapshots</string>
</property>
</widget>
</item>
<item row="4" column="2">
<item row="6" column="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -91,6 +91,13 @@
</property>
</spacer>
</item>
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="uiResetMacAddressesCheckBox">
<property name="text">
<string>&amp;Reset MAC addresses</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWizardPage" name="uiProjectReadmeWizardPage">

View File

@@ -2,12 +2,14 @@
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/export_project_wizard.ui'
#
# Created by: PyQt5 UI code generator 5.9
# Created by: PyQt5 UI code generator 5.13.2
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_ExportProjectWizard(object):
def setupUi(self, ExportProjectWizard):
ExportProjectWizard.setObjectName("ExportProjectWizard")
@@ -43,12 +45,15 @@ class Ui_ExportProjectWizard(object):
self.gridLayout.addWidget(self.uiCompressionComboBox, 1, 1, 1, 2)
self.uiIncludeImagesCheckBox = QtWidgets.QCheckBox(self.uiExportOptionsWizardPage)
self.uiIncludeImagesCheckBox.setObjectName("uiIncludeImagesCheckBox")
self.gridLayout.addWidget(self.uiIncludeImagesCheckBox, 2, 0, 1, 3)
self.gridLayout.addWidget(self.uiIncludeImagesCheckBox, 3, 0, 1, 3)
self.uiIncludeSnapshotsCheckBox = QtWidgets.QCheckBox(self.uiExportOptionsWizardPage)
self.uiIncludeSnapshotsCheckBox.setObjectName("uiIncludeSnapshotsCheckBox")
self.gridLayout.addWidget(self.uiIncludeSnapshotsCheckBox, 3, 0, 1, 2)
self.gridLayout.addWidget(self.uiIncludeSnapshotsCheckBox, 4, 0, 1, 2)
spacerItem = QtWidgets.QSpacerItem(20, 247, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout.addItem(spacerItem, 4, 2, 1, 1)
self.gridLayout.addItem(spacerItem, 6, 2, 1, 1)
self.uiResetMacAddressesCheckBox = QtWidgets.QCheckBox(self.uiExportOptionsWizardPage)
self.uiResetMacAddressesCheckBox.setObjectName("uiResetMacAddressesCheckBox")
self.gridLayout.addWidget(self.uiResetMacAddressesCheckBox, 5, 0, 1, 2)
ExportProjectWizard.addPage(self.uiExportOptionsWizardPage)
self.uiProjectReadmeWizardPage = QtWidgets.QWizardPage()
self.uiProjectReadmeWizardPage.setObjectName("uiProjectReadmeWizardPage")
@@ -70,8 +75,9 @@ class Ui_ExportProjectWizard(object):
self.uiPathLabel.setText(_translate("ExportProjectWizard", "Path:"))
self.uiPathBrowserToolButton.setText(_translate("ExportProjectWizard", "Browse..."))
self.uiCompressionLabel.setText(_translate("ExportProjectWizard", "Compression:"))
self.uiIncludeImagesCheckBox.setText(_translate("ExportProjectWizard", "Include base images"))
self.uiIncludeSnapshotsCheckBox.setText(_translate("ExportProjectWizard", "Include snapshots"))
self.uiIncludeImagesCheckBox.setText(_translate("ExportProjectWizard", "&Include base images"))
self.uiIncludeSnapshotsCheckBox.setText(_translate("ExportProjectWizard", "&Include snapshots"))
self.uiResetMacAddressesCheckBox.setText(_translate("ExportProjectWizard", "&Reset MAC addresses"))
self.uiProjectReadmeWizardPage.setTitle(_translate("ExportProjectWizard", "Readme file"))
self.uiProjectReadmeWizardPage.setSubTitle(_translate("ExportProjectWizard", "Write a summary of the project."))
self.uiReadmeTextEdit.setHtml(_translate("ExportProjectWizard", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
@@ -79,4 +85,3 @@ class Ui_ExportProjectWizard(object):
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'Ubuntu\'; font-size:11pt; font-weight:400; font-style:normal;\">\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:\'.SF NS Text\'; font-size:13pt;\"><br /></p></body></html>"))

View File

@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>931</width>
<height>878</height>
<width>941</width>
<height>910</height>
</rect>
</property>
<property name="windowTitle">
@@ -223,16 +223,7 @@
<string>Binary images</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_7">
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>10</number>
</property>
<item>
@@ -382,16 +373,7 @@
<string>Console applications</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>10</number>
</property>
<item>
@@ -418,17 +400,7 @@
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Command line replacements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;%h = console IP or hostname&lt;/li&gt;
&lt;li&gt;%p = console port&lt;/li&gt;
&lt;li&gt;%P = VNC display&lt;/li&gt;
&lt;li&gt;%s = path of the serial connection&lt;/li&gt;
&lt;li&gt;%d = title of the console&lt;/li&gt;
&lt;li&gt;%i = project UUID&lt;/li&gt;
&lt;li&gt;%c = server URL&lt;/li&gt;
&lt;/ul&gt;
&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Command line replacements:&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;%h = console IP or hostname&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;%p = console port&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;%d = title of the console&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;%i = project UUID&lt;/li&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;%n = node UUID&lt;/li&gt;&lt;/ul&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;%c = server URL&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="readOnly">
<bool>true</bool>
@@ -502,16 +474,7 @@
<string>VNC</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>10</number>
</property>
<item>
@@ -538,17 +501,7 @@
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Command line replacements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;%h = console IP or hostname&lt;/li&gt;
&lt;li&gt;%p = console port&lt;/li&gt;
&lt;li&gt;%P = VNC display&lt;/li&gt;
&lt;li&gt;%s = path of the serial connection&lt;/li&gt;
&lt;li&gt;%d = title of the console&lt;/li&gt;
&lt;li&gt;%i = project UUID&lt;/li&gt;
&lt;li&gt;%c = server URL&lt;/li&gt;
&lt;/ul&gt;
&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Command line replacements:&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;%h = console IP or hostname&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;%p = console port&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;%P = VNC display&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;%d = title of the console&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;%i = project UUID&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;%n = node UUID&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="readOnly">
<bool>true</bool>
@@ -617,17 +570,7 @@
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Command line replacements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;%h = console IP or hostname&lt;/li&gt;
&lt;li&gt;%p = console port&lt;/li&gt;
&lt;li&gt;%P = VNC display&lt;/li&gt;
&lt;li&gt;%s = path of the serial connection&lt;/li&gt;
&lt;li&gt;%d = title of the console&lt;/li&gt;
&lt;li&gt;%i = project UUID&lt;/li&gt;
&lt;li&gt;%c = server URL&lt;/li&gt;
&lt;/ul&gt;
&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Command line replacements:&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;%h = console IP or hostname&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;%p = console port&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;%d = title of the console&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;%i = project UUID&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;%n = node UUID&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="readOnly">
<bool>true</bool>
@@ -1000,16 +943,7 @@
<string>Miscellaneous</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>10</number>
</property>
<item>

View File

@@ -2,16 +2,18 @@
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/general_preferences_page.ui'
#
# Created by: PyQt5 UI code generator 5.9
# Created by: PyQt5 UI code generator 5.13.2
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_GeneralPreferencesPageWidget(object):
def setupUi(self, GeneralPreferencesPageWidget):
GeneralPreferencesPageWidget.setObjectName("GeneralPreferencesPageWidget")
GeneralPreferencesPageWidget.resize(931, 878)
GeneralPreferencesPageWidget.resize(941, 910)
self.verticalLayout = QtWidgets.QVBoxLayout(GeneralPreferencesPageWidget)
self.verticalLayout.setObjectName("verticalLayout")
self.uiMiscTabWidget = QtWidgets.QTabWidget(GeneralPreferencesPageWidget)
@@ -140,6 +142,7 @@ class Ui_GeneralPreferencesPageWidget(object):
self.uiImageDirectoriesLabel.setObjectName("uiImageDirectoriesLabel")
self.verticalLayout_10.addWidget(self.uiImageDirectoriesLabel)
self.uiImageDirectoriesListWidget = QtWidgets.QListWidget(self.uiLocalBinaryImagePathsGroupBox)
self.uiImageDirectoriesListWidget.setFocusPolicy(QtCore.Qt.ClickFocus)
self.uiImageDirectoriesListWidget.setLineWidth(0)
self.uiImageDirectoriesListWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.uiImageDirectoriesListWidget.setAlternatingRowColors(False)
@@ -312,6 +315,7 @@ class Ui_GeneralPreferencesPageWidget(object):
sizePolicy.setHeightForWidth(self.uiDefaultNoteStylePlainTextEdit.sizePolicy().hasHeightForWidth())
self.uiDefaultNoteStylePlainTextEdit.setSizePolicy(sizePolicy)
self.uiDefaultNoteStylePlainTextEdit.setMaximumSize(QtCore.QSize(16777215, 50))
self.uiDefaultNoteStylePlainTextEdit.setFocusPolicy(QtCore.Qt.NoFocus)
self.uiDefaultNoteStylePlainTextEdit.setReadOnly(True)
self.uiDefaultNoteStylePlainTextEdit.setObjectName("uiDefaultNoteStylePlainTextEdit")
self.gridLayout_3.addWidget(self.uiDefaultNoteStylePlainTextEdit, 14, 0, 1, 3)
@@ -329,10 +333,6 @@ class Ui_GeneralPreferencesPageWidget(object):
self.uiLimitSizeNodeSymbolCheckBox = QtWidgets.QCheckBox(self.uiSceneTab)
self.uiLimitSizeNodeSymbolCheckBox.setObjectName("uiLimitSizeNodeSymbolCheckBox")
self.gridLayout_3.addWidget(self.uiLimitSizeNodeSymbolCheckBox, 9, 0, 1, 2)
self.uiDrawLinkStatusPointsCheckBox = QtWidgets.QCheckBox(self.uiSceneTab)
self.uiDrawLinkStatusPointsCheckBox.setChecked(True)
self.uiDrawLinkStatusPointsCheckBox.setObjectName("uiDrawLinkStatusPointsCheckBox")
self.gridLayout_3.addWidget(self.uiDrawLinkStatusPointsCheckBox, 5, 0, 1, 1)
self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
self.horizontalLayout_5.setObjectName("horizontalLayout_5")
self.uiDefaultLabelFontPushButton = QtWidgets.QPushButton(self.uiSceneTab)
@@ -351,6 +351,7 @@ class Ui_GeneralPreferencesPageWidget(object):
sizePolicy.setHeightForWidth(self.uiDefaultLabelStylePlainTextEdit.sizePolicy().hasHeightForWidth())
self.uiDefaultLabelStylePlainTextEdit.setSizePolicy(sizePolicy)
self.uiDefaultLabelStylePlainTextEdit.setMaximumSize(QtCore.QSize(16777215, 50))
self.uiDefaultLabelStylePlainTextEdit.setFocusPolicy(QtCore.Qt.NoFocus)
self.uiDefaultLabelStylePlainTextEdit.setReadOnly(True)
self.uiDefaultLabelStylePlainTextEdit.setObjectName("uiDefaultLabelStylePlainTextEdit")
self.gridLayout_3.addWidget(self.uiDefaultLabelStylePlainTextEdit, 11, 0, 1, 3)
@@ -360,6 +361,7 @@ class Ui_GeneralPreferencesPageWidget(object):
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.uiSceneHeightSpinBox.sizePolicy().hasHeightForWidth())
self.uiSceneHeightSpinBox.setSizePolicy(sizePolicy)
self.uiSceneHeightSpinBox.setFocusPolicy(QtCore.Qt.StrongFocus)
self.uiSceneHeightSpinBox.setMinimum(500)
self.uiSceneHeightSpinBox.setMaximum(1000000)
self.uiSceneHeightSpinBox.setSingleStep(100)
@@ -372,6 +374,7 @@ class Ui_GeneralPreferencesPageWidget(object):
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.uiSceneWidthSpinBox.sizePolicy().hasHeightForWidth())
self.uiSceneWidthSpinBox.setSizePolicy(sizePolicy)
self.uiSceneWidthSpinBox.setFocusPolicy(QtCore.Qt.StrongFocus)
self.uiSceneWidthSpinBox.setMinimum(500)
self.uiSceneWidthSpinBox.setMaximum(1000000)
self.uiSceneWidthSpinBox.setSingleStep(100)
@@ -396,6 +399,7 @@ class Ui_GeneralPreferencesPageWidget(object):
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.uiDrawingGridSizeSpinBox.sizePolicy().hasHeightForWidth())
self.uiDrawingGridSizeSpinBox.setSizePolicy(sizePolicy)
self.uiDrawingGridSizeSpinBox.setFocusPolicy(QtCore.Qt.StrongFocus)
self.uiDrawingGridSizeSpinBox.setMinimum(5)
self.uiDrawingGridSizeSpinBox.setMaximum(100)
self.uiDrawingGridSizeSpinBox.setSingleStep(5)
@@ -408,6 +412,7 @@ class Ui_GeneralPreferencesPageWidget(object):
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.uiNodeGridSizeSpinBox.sizePolicy().hasHeightForWidth())
self.uiNodeGridSizeSpinBox.setSizePolicy(sizePolicy)
self.uiNodeGridSizeSpinBox.setFocusPolicy(QtCore.Qt.StrongFocus)
self.uiNodeGridSizeSpinBox.setMinimum(5)
self.uiNodeGridSizeSpinBox.setMaximum(150)
self.uiNodeGridSizeSpinBox.setSingleStep(5)
@@ -423,6 +428,10 @@ class Ui_GeneralPreferencesPageWidget(object):
self.gridLayout_3.addWidget(self.uiRectangleSelectedItemCheckBox, 4, 0, 1, 3)
spacerItem9 = QtWidgets.QSpacerItem(20, 5, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout_3.addItem(spacerItem9, 16, 0, 1, 1)
self.uiDrawLinkStatusPointsCheckBox = QtWidgets.QCheckBox(self.uiSceneTab)
self.uiDrawLinkStatusPointsCheckBox.setChecked(True)
self.uiDrawLinkStatusPointsCheckBox.setObjectName("uiDrawLinkStatusPointsCheckBox")
self.gridLayout_3.addWidget(self.uiDrawLinkStatusPointsCheckBox, 5, 0, 1, 2)
self.uiMiscTabWidget.addTab(self.uiSceneTab, "")
self.uiMiscTab = QtWidgets.QWidget()
self.uiMiscTab.setObjectName("uiMiscTab")
@@ -472,6 +481,53 @@ class Ui_GeneralPreferencesPageWidget(object):
self.retranslateUi(GeneralPreferencesPageWidget)
self.uiMiscTabWidget.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(GeneralPreferencesPageWidget)
GeneralPreferencesPageWidget.setTabOrder(self.uiProjectsPathLineEdit, self.uiProjectsPathToolButton)
GeneralPreferencesPageWidget.setTabOrder(self.uiProjectsPathToolButton, self.uiSymbolsPathLineEdit)
GeneralPreferencesPageWidget.setTabOrder(self.uiSymbolsPathLineEdit, self.uiSymbolsPathToolButton)
GeneralPreferencesPageWidget.setTabOrder(self.uiSymbolsPathToolButton, self.uiConfigsPathLineEdit)
GeneralPreferencesPageWidget.setTabOrder(self.uiConfigsPathLineEdit, self.uiConfigsPathToolButton)
GeneralPreferencesPageWidget.setTabOrder(self.uiConfigsPathToolButton, self.uiAppliancesPathLineEdit)
GeneralPreferencesPageWidget.setTabOrder(self.uiAppliancesPathLineEdit, self.uiAppliancesPathToolButton)
GeneralPreferencesPageWidget.setTabOrder(self.uiAppliancesPathToolButton, self.uiStyleComboBox)
GeneralPreferencesPageWidget.setTabOrder(self.uiStyleComboBox, self.uiSymbolThemeComboBox)
GeneralPreferencesPageWidget.setTabOrder(self.uiSymbolThemeComboBox, self.uiImportConfigurationFilePushButton)
GeneralPreferencesPageWidget.setTabOrder(self.uiImportConfigurationFilePushButton, self.uiExportConfigurationFilePushButton)
GeneralPreferencesPageWidget.setTabOrder(self.uiExportConfigurationFilePushButton, self.uiBrowseConfigurationPushButton)
GeneralPreferencesPageWidget.setTabOrder(self.uiBrowseConfigurationPushButton, self.uiImagesPathLineEdit)
GeneralPreferencesPageWidget.setTabOrder(self.uiImagesPathLineEdit, self.uiImagesPathToolButton)
GeneralPreferencesPageWidget.setTabOrder(self.uiImagesPathToolButton, self.uiImageDirectoriesAddPushButton)
GeneralPreferencesPageWidget.setTabOrder(self.uiImageDirectoriesAddPushButton, self.uiImageDirectoriesDeletePushButton)
GeneralPreferencesPageWidget.setTabOrder(self.uiImageDirectoriesDeletePushButton, self.uiTelnetConsoleCommandLineEdit)
GeneralPreferencesPageWidget.setTabOrder(self.uiTelnetConsoleCommandLineEdit, self.uiTelnetConsolePreconfiguredCommandPushButton)
GeneralPreferencesPageWidget.setTabOrder(self.uiTelnetConsolePreconfiguredCommandPushButton, self.uiDelayConsoleAllSpinBox)
GeneralPreferencesPageWidget.setTabOrder(self.uiDelayConsoleAllSpinBox, self.uiVNCConsoleCommandLineEdit)
GeneralPreferencesPageWidget.setTabOrder(self.uiVNCConsoleCommandLineEdit, self.uiVNCConsolePreconfiguredCommandPushButton)
GeneralPreferencesPageWidget.setTabOrder(self.uiVNCConsolePreconfiguredCommandPushButton, self.uiSPICEConsoleCommandLineEdit)
GeneralPreferencesPageWidget.setTabOrder(self.uiSPICEConsoleCommandLineEdit, self.uiSPICEConsolePreconfiguredCommandPushButton)
GeneralPreferencesPageWidget.setTabOrder(self.uiSPICEConsolePreconfiguredCommandPushButton, self.uiSceneWidthSpinBox)
GeneralPreferencesPageWidget.setTabOrder(self.uiSceneWidthSpinBox, self.uiSceneHeightSpinBox)
GeneralPreferencesPageWidget.setTabOrder(self.uiSceneHeightSpinBox, self.uiNodeGridSizeSpinBox)
GeneralPreferencesPageWidget.setTabOrder(self.uiNodeGridSizeSpinBox, self.uiDrawingGridSizeSpinBox)
GeneralPreferencesPageWidget.setTabOrder(self.uiDrawingGridSizeSpinBox, self.uiRectangleSelectedItemCheckBox)
GeneralPreferencesPageWidget.setTabOrder(self.uiRectangleSelectedItemCheckBox, self.uiDrawLinkStatusPointsCheckBox)
GeneralPreferencesPageWidget.setTabOrder(self.uiDrawLinkStatusPointsCheckBox, self.uiShowInterfaceLabelsOnNewProject)
GeneralPreferencesPageWidget.setTabOrder(self.uiShowInterfaceLabelsOnNewProject, self.uiShowGridOnNewProject)
GeneralPreferencesPageWidget.setTabOrder(self.uiShowGridOnNewProject, self.uiSnapToGridOnNewProject)
GeneralPreferencesPageWidget.setTabOrder(self.uiSnapToGridOnNewProject, self.uiLimitSizeNodeSymbolCheckBox)
GeneralPreferencesPageWidget.setTabOrder(self.uiLimitSizeNodeSymbolCheckBox, self.uiDefaultLabelFontPushButton)
GeneralPreferencesPageWidget.setTabOrder(self.uiDefaultLabelFontPushButton, self.uiDefaultLabelColorPushButton)
GeneralPreferencesPageWidget.setTabOrder(self.uiDefaultLabelColorPushButton, self.uiDefaultNoteFontPushButton)
GeneralPreferencesPageWidget.setTabOrder(self.uiDefaultNoteFontPushButton, self.uiDefaultNoteColorPushButton)
GeneralPreferencesPageWidget.setTabOrder(self.uiDefaultNoteColorPushButton, self.uiCheckForUpdateCheckBox)
GeneralPreferencesPageWidget.setTabOrder(self.uiCheckForUpdateCheckBox, self.uiCrashReportCheckBox)
GeneralPreferencesPageWidget.setTabOrder(self.uiCrashReportCheckBox, self.uiStatsCheckBox)
GeneralPreferencesPageWidget.setTabOrder(self.uiStatsCheckBox, self.uiOverlayNotificationsCheckBox)
GeneralPreferencesPageWidget.setTabOrder(self.uiOverlayNotificationsCheckBox, self.uiExperimentalFeaturesCheckBox)
GeneralPreferencesPageWidget.setTabOrder(self.uiExperimentalFeaturesCheckBox, self.uiHdpiCheckBox)
GeneralPreferencesPageWidget.setTabOrder(self.uiHdpiCheckBox, self.uiMultiProfilesCheckBox)
GeneralPreferencesPageWidget.setTabOrder(self.uiMultiProfilesCheckBox, self.uiDirectFileUpload)
GeneralPreferencesPageWidget.setTabOrder(self.uiDirectFileUpload, self.uiRestoreDefaultsPushButton)
GeneralPreferencesPageWidget.setTabOrder(self.uiRestoreDefaultsPushButton, self.uiMiscTabWidget)
def retranslateUi(self, GeneralPreferencesPageWidget):
_translate = QtCore.QCoreApplication.translate
@@ -506,17 +562,7 @@ class Ui_GeneralPreferencesPageWidget(object):
self.uiMiscTabWidget.setTabText(self.uiMiscTabWidget.indexOf(self.uiImagesTab), _translate("GeneralPreferencesPageWidget", "Binary images"))
self.uiTelnetConsoleSettingsGroupBox.setTitle(_translate("GeneralPreferencesPageWidget", "Console settings"))
self.uiTelnetConsoleCommandLabel.setText(_translate("GeneralPreferencesPageWidget", "Console application command for Telnet:"))
self.uiTelnetConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "<html><head/><body><p>Command line replacements:</p>\n"
"<ul>\n"
"<li>%h = console IP or hostname</li>\n"
"<li>%p = console port</li>\n"
"<li>%P = VNC display</li>\n"
"<li>%s = path of the serial connection</li>\n"
"<li>%d = title of the console</li>\n"
"<li>%i = project UUID</li>\n"
"<li>%c = server URL</li>\n"
"</ul>\n"
"</body></html>"))
self.uiTelnetConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "<html><head/><body><p>Command line replacements:</p><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%h = console IP or hostname</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%p = console port</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%d = title of the console</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%i = project UUID</li><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%n = node UUID</li></ul><li style=\" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%c = server URL</li></ul></body></html>"))
self.uiTelnetConsolePreconfiguredCommandPushButton.setText(_translate("GeneralPreferencesPageWidget", "&Edit"))
self.uiConsoleMiscGroupBox.setTitle(_translate("GeneralPreferencesPageWidget", "Miscellaneous"))
self.uiDelayConsoleAllSpinBox.setSuffix(_translate("GeneralPreferencesPageWidget", " ms"))
@@ -524,32 +570,12 @@ class Ui_GeneralPreferencesPageWidget(object):
self.uiMiscTabWidget.setTabText(self.uiMiscTabWidget.indexOf(self.uiConsoleTab), _translate("GeneralPreferencesPageWidget", "Console applications"))
self.uiVNCConsoleSettingsGroupBox.setTitle(_translate("GeneralPreferencesPageWidget", "Settings for VNC connections"))
self.uiVNCConsoleCommandLabel.setText(_translate("GeneralPreferencesPageWidget", "Console application command for VNC:"))
self.uiVNCConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "<html><head/><body><p>Command line replacements:</p>\n"
"<ul>\n"
"<li>%h = console IP or hostname</li>\n"
"<li>%p = console port</li>\n"
"<li>%P = VNC display</li>\n"
"<li>%s = path of the serial connection</li>\n"
"<li>%d = title of the console</li>\n"
"<li>%i = project UUID</li>\n"
"<li>%c = server URL</li>\n"
"</ul>\n"
"</body></html>"))
self.uiVNCConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "<html><head/><body><p>Command line replacements:</p><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%h = console IP or hostname</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%p = console port</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%P = VNC display</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%d = title of the console</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%i = project UUID</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%n = node UUID</li></ul></body></html>"))
self.uiVNCConsolePreconfiguredCommandPushButton.setText(_translate("GeneralPreferencesPageWidget", "&Edit"))
self.uiMiscTabWidget.setTabText(self.uiMiscTabWidget.indexOf(self.uiVNCTab), _translate("GeneralPreferencesPageWidget", "VNC"))
self.uiSPICEConsoleSettingsGroupBox.setTitle(_translate("GeneralPreferencesPageWidget", "Settings for SPICE connections"))
self.uiSPICEConsoleCommandLabel.setText(_translate("GeneralPreferencesPageWidget", "Console application command for SPICE:"))
self.uiSPICEConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "<html><head/><body><p>Command line replacements:</p>\n"
"<ul>\n"
"<li>%h = console IP or hostname</li>\n"
"<li>%p = console port</li>\n"
"<li>%P = VNC display</li>\n"
"<li>%s = path of the serial connection</li>\n"
"<li>%d = title of the console</li>\n"
"<li>%i = project UUID</li>\n"
"<li>%c = server URL</li>\n"
"</ul>\n"
"</body></html>"))
self.uiSPICEConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "<html><head/><body><p>Command line replacements:</p><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%h = console IP or hostname</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%p = console port</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%d = title of the console</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%i = project UUID</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%n = node UUID</li></ul><p><br/></p></body></html>"))
self.uiSPICEConsolePreconfiguredCommandPushButton.setText(_translate("GeneralPreferencesPageWidget", "&Edit"))
self.uiMiscTabWidget.setTabText(self.uiMiscTabWidget.indexOf(self.uiSPICETab), _translate("GeneralPreferencesPageWidget", "SPICE"))
self.uiSceneWidthLabel.setText(_translate("GeneralPreferencesPageWidget", "Default width:"))
@@ -560,7 +586,6 @@ class Ui_GeneralPreferencesPageWidget(object):
self.uiDefaultNoteFontPushButton.setText(_translate("GeneralPreferencesPageWidget", "&Select default font"))
self.uiDefaultNoteColorPushButton.setText(_translate("GeneralPreferencesPageWidget", "&Select default color"))
self.uiLimitSizeNodeSymbolCheckBox.setText(_translate("GeneralPreferencesPageWidget", "Limit the size of node symbols"))
self.uiDrawLinkStatusPointsCheckBox.setText(_translate("GeneralPreferencesPageWidget", "Draw link status points"))
self.uiDefaultLabelFontPushButton.setText(_translate("GeneralPreferencesPageWidget", "&Select default font"))
self.uiDefaultLabelColorPushButton.setText(_translate("GeneralPreferencesPageWidget", "&Select default color"))
self.uiDefaultLabelStylePlainTextEdit.setPlainText(_translate("GeneralPreferencesPageWidget", "AaBbYyZz"))
@@ -572,6 +597,7 @@ class Ui_GeneralPreferencesPageWidget(object):
self.uiNodeGridSizeLabel.setText(_translate("GeneralPreferencesPageWidget", "Default node grid size:"))
self.uiShowGridOnNewProject.setText(_translate("GeneralPreferencesPageWidget", "Show grid on new project"))
self.uiRectangleSelectedItemCheckBox.setText(_translate("GeneralPreferencesPageWidget", "Draw a rectangle when an item is selected"))
self.uiDrawLinkStatusPointsCheckBox.setText(_translate("GeneralPreferencesPageWidget", "Draw link status points"))
self.uiMiscTabWidget.setTabText(self.uiMiscTabWidget.indexOf(self.uiSceneTab), _translate("GeneralPreferencesPageWidget", "Topology view"))
self.uiCheckForUpdateCheckBox.setText(_translate("GeneralPreferencesPageWidget", "Automatically check for update"))
self.uiCrashReportCheckBox.setText(_translate("GeneralPreferencesPageWidget", "Send anonymous crash reports"))
@@ -584,4 +610,3 @@ class Ui_GeneralPreferencesPageWidget(object):
self.uiDirectFileUpload.setText(_translate("GeneralPreferencesPageWidget", "Upload files directly to computes (experimental)"))
self.uiMiscTabWidget.setTabText(self.uiMiscTabWidget.indexOf(self.uiMiscTab), _translate("GeneralPreferencesPageWidget", "Miscellaneous"))
self.uiRestoreDefaultsPushButton.setText(_translate("GeneralPreferencesPageWidget", "Restore defaults"))

View File

@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>494</width>
<height>585</height>
<width>467</width>
<height>657</height>
</rect>
</property>
<property name="sizePolicy">
@@ -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,13 +177,30 @@
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QSpinBox" name="uiCpuSpinBox">
<item row="2" column="0">
<widget class="QLabel" name="uiPortLabel">
<property name="text">
<string>Port:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="uiPortSpinBox">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>65635</number>
</property>
<property name="value">
<number>1</number>
<number>80</number>
</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>
@@ -191,6 +211,19 @@
</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>
@@ -214,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>

View File

@@ -2,16 +2,19 @@
# 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.9
# 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
class Ui_GNS3VMPreferencesPageWidget(object):
def setupUi(self, GNS3VMPreferencesPageWidget):
GNS3VMPreferencesPageWidget.setObjectName("GNS3VMPreferencesPageWidget")
GNS3VMPreferencesPageWidget.resize(494, 585)
GNS3VMPreferencesPageWidget.resize(467, 657)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@@ -52,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)
@@ -83,31 +86,52 @@ 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.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)
self.uiPortSpinBox = QtWidgets.QSpinBox(self.uiGNS3VMSettingsGroupBox)
self.uiPortSpinBox.setMinimum(1)
self.uiPortSpinBox.setMaximum(65635)
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.uiCpuLabel = QtWidgets.QLabel(self.uiGNS3VMSettingsGroupBox)
self.uiCpuLabel.setObjectName("uiCpuLabel")
self.gridLayout.addWidget(self.uiCpuLabel, 5, 0, 1, 1)
self.verticalLayout.addWidget(self.uiGNS3VMSettingsGroupBox)
spacerItem = QtWidgets.QSpacerItem(10, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.retranslateUi(GNS3VMPreferencesPageWidget)
QtCore.QMetaObject.connectSlotsByName(GNS3VMPreferencesPageWidget)
GNS3VMPreferencesPageWidget.setTabOrder(self.uiEnableVMCheckBox, self.uiGNS3VMEngineComboBox)
GNS3VMPreferencesPageWidget.setTabOrder(self.uiGNS3VMEngineComboBox, self.uiVMListComboBox)
GNS3VMPreferencesPageWidget.setTabOrder(self.uiVMListComboBox, self.uiRefreshPushButton)
GNS3VMPreferencesPageWidget.setTabOrder(self.uiRefreshPushButton, self.uiRamSpinBox)
GNS3VMPreferencesPageWidget.setTabOrder(self.uiRamSpinBox, self.uiWhenExitKeepRadioButton)
GNS3VMPreferencesPageWidget.setTabOrder(self.uiWhenExitKeepRadioButton, self.uiWhenExitSuspendRadioButton)
GNS3VMPreferencesPageWidget.setTabOrder(self.uiWhenExitSuspendRadioButton, self.uiWhenExitStopRadioButton)
def retranslateUi(self, GNS3VMPreferencesPageWidget):
_translate = QtCore.QCoreApplication.translate
@@ -116,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:"))
@@ -125,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.uiPortLabel.setText(_translate("GNS3VMPreferencesPageWidget", "Port:"))
self.uiAllocatevCPUsRAMCheckBox.setText(_translate("GNS3VMPreferencesPageWidget", "Allocate vCPUs and RAM"))
self.uiCpuLabel.setText(_translate("GNS3VMPreferencesPageWidget", "vCPUs:"))

View File

@@ -62,7 +62,7 @@ background-none;
<x>0</x>
<y>0</y>
<width>986</width>
<height>40</height>
<height>42</height>
</rect>
</property>
<widget class="QMenu" name="uiEditMenu">
@@ -151,6 +151,7 @@ background-none;
<addaction name="uiDrawRectangleAction"/>
<addaction name="uiDrawEllipseAction"/>
<addaction name="uiDrawLineAction"/>
<addaction name="uiEditReadmeAction"/>
</widget>
<widget class="QMenu" name="uiDeviceMenu">
<property name="title">
@@ -163,7 +164,6 @@ background-none;
</property>
<addaction name="uiScreenshotAction"/>
<addaction name="uiImportExportConfigsAction"/>
<addaction name="uiWebInterfaceAction"/>
<addaction name="uiWebUIAction"/>
</widget>
<addaction name="uiFileMenu"/>
@@ -1156,6 +1156,15 @@ background-none;
<string>Import portable project</string>
</property>
</action>
<action name="uiEditReadmeAction">
<property name="icon">
<iconset resource="../../resources/resources.qrc">
<normaloff>:/icons/edit.svg</normaloff>:/icons/edit.svg</iconset>
</property>
<property name="text">
<string>Edit readme</string>
</property>
</action>
<action name="uiAcademyAction">
<property name="text">
<string>GNS3 &amp;Academy</string>
@@ -1187,11 +1196,6 @@ background-none;
<string>Edit project</string>
</property>
</action>
<action name="uiWebInterfaceAction">
<property name="text">
<string>Light Web interface</string>
</property>
</action>
<action name="uiDrawLineAction">
<property name="checkable">
<bool>true</bool>
@@ -1227,7 +1231,7 @@ background-none;
</action>
<action name="uiWebUIAction">
<property name="text">
<string>WebUI - topology preview</string>
<string>Web UI - beta</string>
</property>
</action>
<action name="uiNewTemplateAction">

View File

@@ -2,12 +2,14 @@
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/main_window.ui'
#
# Created by: PyQt5 UI code generator 5.9
# Created by: PyQt5 UI code generator 5.13.2
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
@@ -46,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, 40))
self.uiMenuBar.setGeometry(QtCore.QRect(0, 0, 986, 42))
self.uiMenuBar.setObjectName("uiMenuBar")
self.uiEditMenu = QtWidgets.QMenu(self.uiMenuBar)
self.uiEditMenu.setObjectName("uiEditMenu")
@@ -214,22 +216,22 @@ class Ui_MainWindow(object):
self.uiOnlineHelpAction.setObjectName("uiOnlineHelpAction")
self.uiScreenshotAction = QtWidgets.QAction(MainWindow)
icon4 = QtGui.QIcon()
icon4.addPixmap(QtGui.QPixmap(":/icons/camera-photo-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
icon4.addPixmap(QtGui.QPixmap(":/icons/camera-photo.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon4.addPixmap(QtGui.QPixmap(":/icons/camera-photo-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiScreenshotAction.setIcon(icon4)
self.uiScreenshotAction.setObjectName("uiScreenshotAction")
self.uiStartAllAction = QtWidgets.QAction(MainWindow)
self.uiStartAllAction.setEnabled(True)
icon5 = QtGui.QIcon()
icon5.addPixmap(QtGui.QPixmap(":/icons/start-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
icon5.addPixmap(QtGui.QPixmap(":/icons/start.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon5.addPixmap(QtGui.QPixmap(":/icons/start-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiStartAllAction.setIcon(icon5)
self.uiStartAllAction.setObjectName("uiStartAllAction")
self.uiStopAllAction = QtWidgets.QAction(MainWindow)
self.uiStopAllAction.setEnabled(True)
icon6 = QtGui.QIcon()
icon6.addPixmap(QtGui.QPixmap(":/icons/stop-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
icon6.addPixmap(QtGui.QPixmap(":/icons/stop.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon6.addPixmap(QtGui.QPixmap(":/icons/stop-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiStopAllAction.setIcon(icon6)
self.uiStopAllAction.setObjectName("uiStopAllAction")
self.uiConsoleAllAction = QtWidgets.QAction(MainWindow)
@@ -243,14 +245,14 @@ class Ui_MainWindow(object):
self.uiAboutQtAction.setObjectName("uiAboutQtAction")
self.uiZoomInAction = QtWidgets.QAction(MainWindow)
icon8 = QtGui.QIcon()
icon8.addPixmap(QtGui.QPixmap(":/icons/zoom-in-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
icon8.addPixmap(QtGui.QPixmap(":/icons/zoom-in.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon8.addPixmap(QtGui.QPixmap(":/icons/zoom-in-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiZoomInAction.setIcon(icon8)
self.uiZoomInAction.setObjectName("uiZoomInAction")
self.uiZoomOutAction = QtWidgets.QAction(MainWindow)
icon9 = QtGui.QIcon()
icon9.addPixmap(QtGui.QPixmap(":/icons/zoom-out-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
icon9.addPixmap(QtGui.QPixmap(":/icons/zoom-out.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon9.addPixmap(QtGui.QPixmap(":/icons/zoom-out-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiZoomOutAction.setIcon(icon9)
self.uiZoomOutAction.setObjectName("uiZoomOutAction")
self.uiZoomResetAction = QtWidgets.QAction(MainWindow)
@@ -267,8 +269,8 @@ class Ui_MainWindow(object):
self.uiPreferencesAction.setObjectName("uiPreferencesAction")
self.uiSuspendAllAction = QtWidgets.QAction(MainWindow)
icon11 = QtGui.QIcon()
icon11.addPixmap(QtGui.QPixmap(":/icons/pause-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
icon11.addPixmap(QtGui.QPixmap(":/icons/pause.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon11.addPixmap(QtGui.QPixmap(":/icons/pause-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiSuspendAllAction.setIcon(icon11)
self.uiSuspendAllAction.setObjectName("uiSuspendAllAction")
self.uiAddNoteAction = QtWidgets.QAction(MainWindow)
@@ -296,15 +298,15 @@ class Ui_MainWindow(object):
self.uiDrawRectangleAction = QtWidgets.QAction(MainWindow)
self.uiDrawRectangleAction.setCheckable(True)
icon16 = QtGui.QIcon()
icon16.addPixmap(QtGui.QPixmap(":/icons/rectangle-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
icon16.addPixmap(QtGui.QPixmap(":/icons/rectangle.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon16.addPixmap(QtGui.QPixmap(":/icons/rectangle-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiDrawRectangleAction.setIcon(icon16)
self.uiDrawRectangleAction.setObjectName("uiDrawRectangleAction")
self.uiDrawEllipseAction = QtWidgets.QAction(MainWindow)
self.uiDrawEllipseAction.setCheckable(True)
icon17 = QtGui.QIcon()
icon17.addPixmap(QtGui.QPixmap(":/icons/ellipse-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
icon17.addPixmap(QtGui.QPixmap(":/icons/ellipse.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon17.addPixmap(QtGui.QPixmap(":/icons/ellipse-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiDrawEllipseAction.setIcon(icon17)
self.uiDrawEllipseAction.setObjectName("uiDrawEllipseAction")
self.uiShowPortNamesAction = QtWidgets.QAction(MainWindow)
@@ -346,40 +348,40 @@ class Ui_MainWindow(object):
self.uiCheckForUpdateAction.setObjectName("uiCheckForUpdateAction")
self.uiBrowseRoutersAction = QtWidgets.QAction(MainWindow)
icon23 = QtGui.QIcon()
icon23.addPixmap(QtGui.QPixmap(":/icons/router-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
icon23.addPixmap(QtGui.QPixmap(":/icons/router.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon23.addPixmap(QtGui.QPixmap(":/icons/router-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiBrowseRoutersAction.setIcon(icon23)
self.uiBrowseRoutersAction.setObjectName("uiBrowseRoutersAction")
self.uiBrowseSwitchesAction = QtWidgets.QAction(MainWindow)
icon24 = QtGui.QIcon()
icon24.addPixmap(QtGui.QPixmap(":/icons/switch-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
icon24.addPixmap(QtGui.QPixmap(":/icons/switch.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon24.addPixmap(QtGui.QPixmap(":/icons/switch-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiBrowseSwitchesAction.setIcon(icon24)
self.uiBrowseSwitchesAction.setObjectName("uiBrowseSwitchesAction")
self.uiBrowseEndDevicesAction = QtWidgets.QAction(MainWindow)
icon25 = QtGui.QIcon()
icon25.addPixmap(QtGui.QPixmap(":/icons/PC-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
icon25.addPixmap(QtGui.QPixmap(":/icons/PC.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon25.addPixmap(QtGui.QPixmap(":/icons/PC-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiBrowseEndDevicesAction.setIcon(icon25)
self.uiBrowseEndDevicesAction.setObjectName("uiBrowseEndDevicesAction")
self.uiBrowseSecurityDevicesAction = QtWidgets.QAction(MainWindow)
icon26 = QtGui.QIcon()
icon26.addPixmap(QtGui.QPixmap(":/icons/firewall-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
icon26.addPixmap(QtGui.QPixmap(":/icons/firewall.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon26.addPixmap(QtGui.QPixmap(":/icons/firewall-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiBrowseSecurityDevicesAction.setIcon(icon26)
self.uiBrowseSecurityDevicesAction.setObjectName("uiBrowseSecurityDevicesAction")
self.uiBrowseAllDevicesAction = QtWidgets.QAction(MainWindow)
icon27 = QtGui.QIcon()
icon27.addPixmap(QtGui.QPixmap(":/icons/browse-all-icons-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
icon27.addPixmap(QtGui.QPixmap(":/icons/browse-all-icons.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon27.addPixmap(QtGui.QPixmap(":/icons/browse-all-icons-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiBrowseAllDevicesAction.setIcon(icon27)
self.uiBrowseAllDevicesAction.setObjectName("uiBrowseAllDevicesAction")
self.uiAddLinkAction = QtWidgets.QAction(MainWindow)
self.uiAddLinkAction.setCheckable(True)
icon28 = QtGui.QIcon()
icon28.addPixmap(QtGui.QPixmap(":/icons/connection-new-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
icon28.addPixmap(QtGui.QPixmap(":/icons/connection-new.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon28.addPixmap(QtGui.QPixmap(":/icons/cancel-connection.svg"), QtGui.QIcon.Normal, QtGui.QIcon.On)
icon28.addPixmap(QtGui.QPixmap(":/icons/connection-new-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
icon28.addPixmap(QtGui.QPixmap(":/icons/cancel-connection.svg"), QtGui.QIcon.Active, QtGui.QIcon.On)
self.uiAddLinkAction.setIcon(icon28)
self.uiAddLinkAction.setObjectName("uiAddLinkAction")
@@ -407,23 +409,24 @@ class Ui_MainWindow(object):
icon30.addPixmap(QtGui.QPixmap(":/icons/import.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiImportProjectAction.setIcon(icon30)
self.uiImportProjectAction.setObjectName("uiImportProjectAction")
self.uiEditReadmeAction = QtWidgets.QAction(MainWindow)
icon31 = QtGui.QIcon()
icon31.addPixmap(QtGui.QPixmap(":/icons/edit.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiEditReadmeAction.setIcon(icon31)
self.uiEditReadmeAction.setObjectName("uiEditReadmeAction")
self.uiAcademyAction = QtWidgets.QAction(MainWindow)
self.uiAcademyAction.setObjectName("uiAcademyAction")
self.uiDeleteProjectAction = QtWidgets.QAction(MainWindow)
icon31 = QtGui.QIcon()
icon31.addPixmap(QtGui.QPixmap(":/icons/delete.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiDeleteProjectAction.setIcon(icon31)
icon32 = QtGui.QIcon()
icon32.addPixmap(QtGui.QPixmap(":/icons/delete.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiDeleteProjectAction.setIcon(icon32)
self.uiDeleteProjectAction.setObjectName("uiDeleteProjectAction")
self.uiShowGridAction = QtWidgets.QAction(MainWindow)
self.uiShowGridAction.setCheckable(True)
self.uiShowGridAction.setObjectName("uiShowGridAction")
self.uiEditProjectAction = QtWidgets.QAction(MainWindow)
icon32 = QtGui.QIcon()
icon32.addPixmap(QtGui.QPixmap(":/icons/edit.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiEditProjectAction.setIcon(icon32)
self.uiEditProjectAction.setIcon(icon31)
self.uiEditProjectAction.setObjectName("uiEditProjectAction")
self.uiWebInterfaceAction = QtWidgets.QAction(MainWindow)
self.uiWebInterfaceAction.setObjectName("uiWebInterfaceAction")
self.uiDrawLineAction = QtWidgets.QAction(MainWindow)
self.uiDrawLineAction.setCheckable(True)
icon33 = QtGui.QIcon()
@@ -434,9 +437,9 @@ class Ui_MainWindow(object):
self.uiLockAllAction.setCheckable(True)
self.uiLockAllAction.setChecked(False)
icon34 = QtGui.QIcon()
icon34.addPixmap(QtGui.QPixmap(":/icons/unlock.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
icon34.addPixmap(QtGui.QPixmap(":/icons/unlock.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon34.addPixmap(QtGui.QPixmap(":/icons/lock.svg"), QtGui.QIcon.Normal, QtGui.QIcon.On)
icon34.addPixmap(QtGui.QPixmap(":/icons/unlock.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
icon34.addPixmap(QtGui.QPixmap(":/icons/lock.svg"), QtGui.QIcon.Active, QtGui.QIcon.On)
self.uiLockAllAction.setIcon(icon34)
self.uiLockAllAction.setObjectName("uiLockAllAction")
@@ -497,9 +500,9 @@ class Ui_MainWindow(object):
self.uiAnnotateMenu.addAction(self.uiDrawRectangleAction)
self.uiAnnotateMenu.addAction(self.uiDrawEllipseAction)
self.uiAnnotateMenu.addAction(self.uiDrawLineAction)
self.uiAnnotateMenu.addAction(self.uiEditReadmeAction)
self.uiToolsMenu.addAction(self.uiScreenshotAction)
self.uiToolsMenu.addAction(self.uiImportExportConfigsAction)
self.uiToolsMenu.addAction(self.uiWebInterfaceAction)
self.uiToolsMenu.addAction(self.uiWebUIAction)
self.uiMenuBar.addAction(self.uiFileMenu.menuAction())
self.uiMenuBar.addAction(self.uiEditMenu.menuAction())
@@ -698,17 +701,16 @@ class Ui_MainWindow(object):
self.uiDoctorAction.setText(_translate("MainWindow", "GNS3 &Doctor"))
self.uiExportProjectAction.setText(_translate("MainWindow", "Export portable project"))
self.uiImportProjectAction.setText(_translate("MainWindow", "Import portable project"))
self.uiEditReadmeAction.setText(_translate("MainWindow", "Edit readme"))
self.uiAcademyAction.setText(_translate("MainWindow", "GNS3 &Academy"))
self.uiDeleteProjectAction.setText(_translate("MainWindow", "Delete project"))
self.uiShowGridAction.setText(_translate("MainWindow", "Show the grid"))
self.uiEditProjectAction.setText(_translate("MainWindow", "Edit project"))
self.uiWebInterfaceAction.setText(_translate("MainWindow", "Light Web interface"))
self.uiDrawLineAction.setText(_translate("MainWindow", "Drawn line"))
self.uiLockAllAction.setText(_translate("MainWindow", "Lock or unlock all items"))
self.uiLockAllAction.setToolTip(_translate("MainWindow", "Lock or unlock all items"))
self.uiWebUIAction.setText(_translate("MainWindow", "WebUI - topology preview"))
self.uiWebUIAction.setText(_translate("MainWindow", "Web UI - beta"))
self.uiNewTemplateAction.setText(_translate("MainWindow", "New template"))
from ..compute_summary_view import ComputeSummaryView
from ..console_view import ConsoleView
from ..graphics_view import GraphicsView

View File

@@ -9,8 +9,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>520</width>
<height>301</height>
<width>823</width>
<height>367</height>
</rect>
</property>
<property name="windowTitle">
@@ -29,23 +29,14 @@
<enum>QTabWidget::Rounded</enum>
</property>
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="uiNewProjectTab">
<attribute name="title">
<string>New project</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>10</number>
</property>
<item>
@@ -163,16 +154,7 @@
<string>Projects library</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>10</number>
</property>
<item>
@@ -222,6 +204,16 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="uiResetMacAddressesCheckBox">
<property name="text">
<string>&amp;Reset MAC addresses</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">

View File

@@ -1,20 +1,20 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '/Users/noplay/code/gns3/gns3-gui/gns3/ui/project_dialog.ui'
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/project_dialog.ui'
#
# Created by: PyQt5 UI code generator 5.6
# Created by: PyQt5 UI code generator 5.13.2
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_ProjectDialog(object):
def setupUi(self, ProjectDialog):
ProjectDialog.setObjectName("ProjectDialog")
ProjectDialog.setWindowModality(QtCore.Qt.ApplicationModal)
ProjectDialog.resize(520, 301)
ProjectDialog.resize(823, 367)
ProjectDialog.setModal(True)
self.verticalLayout = QtWidgets.QVBoxLayout(ProjectDialog)
self.verticalLayout.setObjectName("verticalLayout")
@@ -99,6 +99,10 @@ class Ui_ProjectDialog(object):
self.uiDuplicateProjectPushButton = QtWidgets.QPushButton(self.uiProjectsLibraryTab)
self.uiDuplicateProjectPushButton.setObjectName("uiDuplicateProjectPushButton")
self.horizontalLayout_4.addWidget(self.uiDuplicateProjectPushButton)
self.uiResetMacAddressesCheckBox = QtWidgets.QCheckBox(self.uiProjectsLibraryTab)
self.uiResetMacAddressesCheckBox.setChecked(True)
self.uiResetMacAddressesCheckBox.setObjectName("uiResetMacAddressesCheckBox")
self.horizontalLayout_4.addWidget(self.uiResetMacAddressesCheckBox)
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_4.addItem(spacerItem2)
self.uiRefreshProjectsPushButton = QtWidgets.QPushButton(self.uiProjectsLibraryTab)
@@ -116,7 +120,7 @@ class Ui_ProjectDialog(object):
self.horizontalLayout.addItem(spacerItem3)
self.uiButtonBox = QtWidgets.QDialogButtonBox(ProjectDialog)
self.uiButtonBox.setOrientation(QtCore.Qt.Horizontal)
self.uiButtonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok)
self.uiButtonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.uiButtonBox.setObjectName("uiButtonBox")
self.horizontalLayout.addWidget(self.uiButtonBox)
self.verticalLayout.addLayout(self.horizontalLayout)
@@ -128,6 +132,16 @@ class Ui_ProjectDialog(object):
self.uiNameLineEdit.returnPressed.connect(ProjectDialog.accept)
self.uiLocationLineEdit.returnPressed.connect(ProjectDialog.accept)
QtCore.QMetaObject.connectSlotsByName(ProjectDialog)
ProjectDialog.setTabOrder(self.uiProjectTabWidget, self.uiNameLineEdit)
ProjectDialog.setTabOrder(self.uiNameLineEdit, self.uiLocationLineEdit)
ProjectDialog.setTabOrder(self.uiLocationLineEdit, self.uiLocationBrowserToolButton)
ProjectDialog.setTabOrder(self.uiLocationBrowserToolButton, self.uiOpenProjectPushButton)
ProjectDialog.setTabOrder(self.uiOpenProjectPushButton, self.uiRecentProjectsPushButton)
ProjectDialog.setTabOrder(self.uiRecentProjectsPushButton, self.uiSettingsPushButton)
ProjectDialog.setTabOrder(self.uiSettingsPushButton, self.uiProjectsTreeWidget)
ProjectDialog.setTabOrder(self.uiProjectsTreeWidget, self.uiDeleteProjectButton)
ProjectDialog.setTabOrder(self.uiDeleteProjectButton, self.uiDuplicateProjectPushButton)
ProjectDialog.setTabOrder(self.uiDuplicateProjectPushButton, self.uiRefreshProjectsPushButton)
def retranslateUi(self, ProjectDialog):
_translate = QtCore.QCoreApplication.translate
@@ -146,6 +160,7 @@ class Ui_ProjectDialog(object):
self.uiProjectsTreeWidget.headerItem().setText(2, _translate("ProjectDialog", "Path"))
self.uiDeleteProjectButton.setText(_translate("ProjectDialog", "Delete"))
self.uiDuplicateProjectPushButton.setText(_translate("ProjectDialog", "Duplicate"))
self.uiResetMacAddressesCheckBox.setText(_translate("ProjectDialog", "&Reset MAC addresses"))
self.uiRefreshProjectsPushButton.setText(_translate("ProjectDialog", "Refresh list"))
self.uiProjectTabWidget.setTabText(self.uiProjectTabWidget.indexOf(self.uiProjectsLibraryTab), _translate("ProjectDialog", "Projects library"))
self.uiSettingsPushButton.setText(_translate("ProjectDialog", "Settings"))

View File

@@ -9,12 +9,12 @@
<rect>
<x>0</x>
<y>0</y>
<width>607</width>
<height>308</height>
<width>647</width>
<height>214</height>
</rect>
</property>
<property name="windowTitle">
<string>Welcome</string>
<string>Project variables</string>
</property>
<property name="modal">
<bool>true</bool>
@@ -32,7 +32,7 @@
</sizepolicy>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Loading.. Please wait.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Please provide the missing values for the project variables:&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>

View File

@@ -1,18 +1,20 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '/home/dominik/projects/gns3-gui/gns3/ui/project_welcome_dialog.ui'
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/project_welcome_dialog.ui'
#
# Created by: PyQt5 UI code generator 5.8.2
# Created by: PyQt5 UI code generator 5.13.0
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_ProjectWelcomeDialog(object):
def setupUi(self, ProjectWelcomeDialog):
ProjectWelcomeDialog.setObjectName("ProjectWelcomeDialog")
ProjectWelcomeDialog.setWindowModality(QtCore.Qt.WindowModal)
ProjectWelcomeDialog.resize(607, 308)
ProjectWelcomeDialog.resize(659, 220)
ProjectWelcomeDialog.setModal(True)
self.verticalLayout = QtWidgets.QVBoxLayout(ProjectWelcomeDialog)
self.verticalLayout.setContentsMargins(-1, -1, 12, -1)
@@ -48,13 +50,14 @@ class Ui_ProjectWelcomeDialog(object):
self.uiOkButton.setObjectName("uiOkButton")
self.horizontalLayout.addWidget(self.uiOkButton)
self.verticalLayout.addLayout(self.horizontalLayout)
spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem1)
self.retranslateUi(ProjectWelcomeDialog)
QtCore.QMetaObject.connectSlotsByName(ProjectWelcomeDialog)
def retranslateUi(self, ProjectWelcomeDialog):
_translate = QtCore.QCoreApplication.translate
ProjectWelcomeDialog.setWindowTitle(_translate("ProjectWelcomeDialog", "Welcome"))
self.label.setText(_translate("ProjectWelcomeDialog", "<html><head/><body><p>Loading.. Please wait.</p></body></html>"))
ProjectWelcomeDialog.setWindowTitle(_translate("ProjectWelcomeDialog", "Project variables"))
self.label.setText(_translate("ProjectWelcomeDialog", "<html><head/><body><p>Please provide the missing values for the project variables:</p></body></html>"))
from . import resources_rc

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -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"))

View File

@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>1081</width>
<height>534</height>
<width>1104</width>
<height>665</height>
</rect>
</property>
<property name="windowTitle">
@@ -234,33 +234,6 @@
<string>In order to run the GNS3 VM you must first have VMware or VirtualBox installed and the GNS3 VM.ova imported with one of these software.</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="uiVirtualizationSoftwarLabel">
<property name="text">
<string>Virtualization software:</string>
</property>
</widget>
</item>
<item row="0" column="2" rowspan="4">
<widget class="QPushButton" name="uiVMwareBannerButton">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../resources/resources.qrc">
<normaloff>:/images/vmware_fusion_banner.png</normaloff>:/images/vmware_fusion_banner.png</iconset>
</property>
<property name="iconSize">
<size>
<width>300</width>
<height>150</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="uiVmwareRadioButton">
<property name="toolTip">
@@ -274,18 +247,12 @@
</property>
</widget>
</item>
<item row="1" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<item row="0" column="0">
<widget class="QLabel" name="uiVirtualizationSoftwarLabel">
<property name="text">
<string>Virtualization software:</string>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>317</width>
<height>20</height>
</size>
</property>
</spacer>
</widget>
</item>
<item row="2" column="0">
<widget class="QRadioButton" name="uiVirtualBoxRadioButton">
@@ -328,7 +295,7 @@
</property>
</widget>
</item>
<item row="6" column="0" colspan="3">
<item row="6" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QComboBox" name="uiVMListComboBox">
@@ -349,7 +316,7 @@
</item>
</layout>
</item>
<item row="8" column="0" colspan="3">
<item row="8" column="0" colspan="2">
<widget class="QSpinBox" name="uiCPUSpinBox">
<property name="minimum">
<number>1</number>
@@ -362,7 +329,7 @@
</property>
</widget>
</item>
<item row="10" column="0" colspan="3">
<item row="10" column="0" colspan="2">
<widget class="QSpinBox" name="uiRAMSpinBox">
<property name="enabled">
<bool>true</bool>

View File

@@ -2,9 +2,10 @@
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/setup_wizard.ui'
#
# Created by: PyQt5 UI code generator 5.13.0
# 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
@@ -13,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_SetupWizard(object):
def setupUi(self, SetupWizard):
SetupWizard.setObjectName("SetupWizard")
SetupWizard.resize(1081, 534)
SetupWizard.resize(1104, 665)
SetupWizard.setModal(True)
SetupWizard.setWizardStyle(QtWidgets.QWizard.ModernStyle)
SetupWizard.setOptions(QtWidgets.QWizard.NoBackButtonOnStartPage)
@@ -114,24 +115,13 @@ class Ui_SetupWizard(object):
self.uiVMWizardPage.setObjectName("uiVMWizardPage")
self.gridLayout_3 = QtWidgets.QGridLayout(self.uiVMWizardPage)
self.gridLayout_3.setObjectName("gridLayout_3")
self.uiVirtualizationSoftwarLabel = QtWidgets.QLabel(self.uiVMWizardPage)
self.uiVirtualizationSoftwarLabel.setObjectName("uiVirtualizationSoftwarLabel")
self.gridLayout_3.addWidget(self.uiVirtualizationSoftwarLabel, 0, 0, 1, 1)
self.uiVMwareBannerButton = QtWidgets.QPushButton(self.uiVMWizardPage)
self.uiVMwareBannerButton.setText("")
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(":/images/vmware_fusion_banner.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiVMwareBannerButton.setIcon(icon)
self.uiVMwareBannerButton.setIconSize(QtCore.QSize(300, 150))
self.uiVMwareBannerButton.setFlat(True)
self.uiVMwareBannerButton.setObjectName("uiVMwareBannerButton")
self.gridLayout_3.addWidget(self.uiVMwareBannerButton, 0, 2, 4, 1)
self.uiVmwareRadioButton = QtWidgets.QRadioButton(self.uiVMWizardPage)
self.uiVmwareRadioButton.setChecked(True)
self.uiVmwareRadioButton.setObjectName("uiVmwareRadioButton")
self.gridLayout_3.addWidget(self.uiVmwareRadioButton, 1, 0, 1, 1)
spacerItem1 = QtWidgets.QSpacerItem(317, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.gridLayout_3.addItem(spacerItem1, 1, 1, 1, 1)
self.uiVirtualizationSoftwarLabel = QtWidgets.QLabel(self.uiVMWizardPage)
self.uiVirtualizationSoftwarLabel.setObjectName("uiVirtualizationSoftwarLabel")
self.gridLayout_3.addWidget(self.uiVirtualizationSoftwarLabel, 0, 0, 1, 1)
self.uiVirtualBoxRadioButton = QtWidgets.QRadioButton(self.uiVMWizardPage)
self.uiVirtualBoxRadioButton.setObjectName("uiVirtualBoxRadioButton")
self.gridLayout_3.addWidget(self.uiVirtualBoxRadioButton, 2, 0, 1, 1)
@@ -161,13 +151,13 @@ class Ui_SetupWizard(object):
self.uiRefreshPushButton = QtWidgets.QPushButton(self.uiVMWizardPage)
self.uiRefreshPushButton.setObjectName("uiRefreshPushButton")
self.horizontalLayout.addWidget(self.uiRefreshPushButton)
self.gridLayout_3.addLayout(self.horizontalLayout, 6, 0, 1, 3)
self.gridLayout_3.addLayout(self.horizontalLayout, 6, 0, 1, 2)
self.uiCPUSpinBox = QtWidgets.QSpinBox(self.uiVMWizardPage)
self.uiCPUSpinBox.setMinimum(1)
self.uiCPUSpinBox.setMaximum(128)
self.uiCPUSpinBox.setProperty("value", 1)
self.uiCPUSpinBox.setObjectName("uiCPUSpinBox")
self.gridLayout_3.addWidget(self.uiCPUSpinBox, 8, 0, 1, 3)
self.gridLayout_3.addWidget(self.uiCPUSpinBox, 8, 0, 1, 2)
self.uiRAMSpinBox = QtWidgets.QSpinBox(self.uiVMWizardPage)
self.uiRAMSpinBox.setEnabled(True)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
@@ -180,7 +170,7 @@ class Ui_SetupWizard(object):
self.uiRAMSpinBox.setSingleStep(512)
self.uiRAMSpinBox.setProperty("value", 2048)
self.uiRAMSpinBox.setObjectName("uiRAMSpinBox")
self.gridLayout_3.addWidget(self.uiRAMSpinBox, 10, 0, 1, 3)
self.gridLayout_3.addWidget(self.uiRAMSpinBox, 10, 0, 1, 2)
SetupWizard.addPage(self.uiVMWizardPage)
self.uiRemoteControllerWizardPage = QtWidgets.QWizardPage()
self.uiRemoteControllerWizardPage.setObjectName("uiRemoteControllerWizardPage")
@@ -260,9 +250,9 @@ class Ui_SetupWizard(object):
self.uiLocalServerStatusWizardPage.setSubTitle(_translate("SetupWizard", "Validation of the configuration for the local server"))
self.uiVMWizardPage.setTitle(_translate("SetupWizard", "GNS3 VM"))
self.uiVMWizardPage.setSubTitle(_translate("SetupWizard", "In order to run the GNS3 VM you must first have VMware or VirtualBox installed and the GNS3 VM.ova imported with one of these software."))
self.uiVirtualizationSoftwarLabel.setText(_translate("SetupWizard", "Virtualization software:"))
self.uiVmwareRadioButton.setToolTip(_translate("SetupWizard", "VMware is recommended to run Qemu based appliances (required for KVM)."))
self.uiVmwareRadioButton.setText(_translate("SetupWizard", "VMware (recommended)"))
self.uiVirtualizationSoftwarLabel.setText(_translate("SetupWizard", "Virtualization software:"))
self.uiVirtualBoxRadioButton.setToolTip(_translate("SetupWizard", "Use VirtualBox if you intend to only use Dynamips, IOU or VPCS."))
self.uiVirtualBoxRadioButton.setText(_translate("SetupWizard", "VirtualBox"))
self.uiVMNameLabel.setText(_translate("SetupWizard", "VM name:"))

View File

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

View File

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

View File

@@ -28,17 +28,18 @@ class ExportProjectWorker(QtCore.QObject):
finished = QtCore.pyqtSignal()
updated = QtCore.pyqtSignal(int)
def __init__(self, project, path, include_images, include_snapshots, compression):
def __init__(self, project, path, include_images, include_snapshots, reset_mac_addresses, compression):
super().__init__()
self._project = project
self._include_images = include_images
self._include_snapshots = include_snapshots
self._reset_mac_addresses = reset_mac_addresses
self._path = path
self._compression = compression
def run(self):
if self._project:
self._project.get("/export?include_images={}&include_snapshots={}&compression={}".format(self._include_images, self._include_snapshots, self._compression),
self._project.get("/export?include_images={}&include_snapshots={}&reset_mac_addresses={}&compression={}".format(self._include_images, self._include_snapshots, self._reset_mac_addresses, self._compression),
self._exportReceived,
downloadProgressCallback=self._downloadFileProgress,
timeout=None)

View File

@@ -23,10 +23,9 @@
# or negative for a release candidate or beta (after the base version
# number has been incremented)
__version__ = "2.2.2"
__version_info__ = (2, 2, 2, 0)
__version__ = "2.2.26"
__version_info__ = (2, 2, 26, 0)
# If it's a git checkout try to add the commit
if "dev" in __version__:
try:
import os

View File

@@ -24,15 +24,17 @@ import os
import shlex
import subprocess
from .controller import Controller
import logging
log = logging.getLogger(__name__)
def vncConsole(host, port, command):
def vncConsole(node, port, command):
"""
Start a VNC console program.
:param host: host or IP address
:param node: Node instance
:param port: port number
"""
@@ -40,10 +42,16 @@ def vncConsole(host, port, command):
log.error("VNC client is not configured")
return
name = node.name()
host = node.consoleHost()
# replace the place-holders by the actual values
command = command.replace("%h", host)
command = command.replace("%p", str(port))
command = command.replace("%P", str(port - 5900))
command = command.replace("%d", name.replace('"', '\\"'))
command = command.replace("%i", node.project().id())
command = command.replace("%n", str(node.id()))
try:
log.debug('starting VNC program "{}"'.format(command))

View File

@@ -1,3 +1,3 @@
-rrequirements.txt
#PyQt5==5.7
PyQt5==5.15.4

View File

@@ -1,4 +1,5 @@
jsonschema==2.6.0 # pyup: ignore
raven>=5.23.0
psutil>=2.2.1
distro>=1.3.0
jsonschema==3.2.0
sentry-sdk==1.3.1
psutil==5.8.0
distro==1.6.0
setuptools

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -0,0 +1,11 @@
[Desktop Entry]
Version=1.0
Type=Application
Terminal=false
Exec=gns3 %f
Name=GNS3
Comment=GNS3 Graphical Network Simulator
Icon=gns3
Categories=Education;Network;
MimeType=application/x-gns3;application/x-gns3appliance;application/x-gns3project;
Keywords=simulator;network;netsim;

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/x-gns3">
<comment>GNS3 Project File</comment>
<comment xml:lang="en">GNS3 Project File</comment>
<glob pattern="*.gns3"/>
</mime-type>
<mime-type type="application/x-gns3project">
<comment>GNS3 Project File</comment>
<comment xml:lang="en">GNS3 Portable Project File</comment>
<glob pattern="*.gns3project"/>
</mime-type>
<mime-type type="application/x-gns3project">
<comment>GNS3 Project File</comment>
<comment xml:lang="en">GNS3 Portable Project File</comment>
<glob pattern="*.gns3p"/>
</mime-type>
<mime-type type="application/x-gns3appliance">
<comment>GNS3 Appliance File</comment>
<comment xml:lang="en">GNS3 Appliance File</comment>
<glob pattern="*.gns3appliance"/>
</mime-type>
<mime-type type="application/x-gns3appliance">
<comment>GNS3 Appliance File</comment>
<comment xml:lang="en">GNS3 Appliance File</comment>
<glob pattern="*.gns3a"/>
</mime-type>
</mime-info>

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Some files were not shown because too many files have changed in this diff Show More