Merge branch 'master' into 1.5

This commit is contained in:
Julien Duponchelle
2016-02-01 15:46:46 +01:00
41 changed files with 100787 additions and 100766 deletions

View File

@@ -42,7 +42,9 @@ class ConsoleView(PyCutExt, ConsoleCmd):
bitness = struct.calcsize("P") * 8
current_year = datetime.date.today().year
self.intro = "GNS3 management console.\nRunning GNS3 version {} on {} ({}-bit) with Python {} Qt {}.\n" \
"Copyright (c) 2006-{} GNS3 Technologies.".format(__version__, platform.system(), bitness, platform.python_version(), QtCore.QT_VERSION_STR, current_year)
"Copyright (c) 2006-{} GNS3 Technologies.\n" \
"Use Help -> GNS3 Doctor to detect common issues." \
"".format(__version__, platform.system(), bitness, platform.python_version(), QtCore.QT_VERSION_STR, current_year)
if LocalConfig.instance().experimental():
self.intro += "\nWARNING: Experimental features enable. You can use some unfinished features and lost data."

View File

@@ -16,6 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import psutil
import os
import platform
import struct
@@ -109,6 +110,7 @@ class CrashReport:
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

View File

@@ -0,0 +1,173 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 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/>.
import psutil
import platform
import os
import stat
import sys
import struct
from gns3.qt import QtWidgets
from gns3.ui.doctor_dialog_ui import Ui_DoctorDialog
from gns3.servers import Servers
from gns3.local_config import LocalConfig
from gns3 import version
from gns3.modules.vmware import VMware
import logging
log = logging.getLogger(__name__)
class DoctorDialog(QtWidgets.QDialog, Ui_DoctorDialog):
"""
This dialog allow user to detect error in his GNS3 installation.
If you want to add a test add a method starting by check. The
check return a tuple result and a message in case of failure.
"""
def __init__(self, parent, console=False):
super().__init__(parent)
self._console = console
self.setupUi(self)
self.uiOkButton.clicked.connect(self._okButtonClickedSlot)
for method in sorted(dir(self)):
if method.startswith('check'):
self.write(getattr(self, method).__doc__ + "...")
(res, msg) = getattr(self, method)()
if res == 0:
self.write('<span style="color: green"><strong>OK</strong></span>')
elif res == 1:
self.write('<span style="color: orange"><strong>WARNING</strong> {}</span>'.format(msg))
elif res == 2:
self.write('<span style="color: red"><strong>ERROR</strong> {}</span>'.format(msg))
self.write("<br/>")
def write(self, text):
"""
Add text to the text windows
"""
if self._console:
print(text)
self.uiDoctorResultTextEdit.setHtml(self.uiDoctorResultTextEdit.toHtml() + text)
def _okButtonClickedSlot(self):
self.accept()
def checkLocalServerEnabled(self):
"""Checking if the local server is enabled"""
if Servers.instance().shouldLocalServerAutoStart() is False:
return (2, "The local server is disabled. Go to Preferences -> Server -> Local Server and enable the local server.")
return (0, None)
def checkDevVersionOfGNS3(self):
"""Checking for stable GNS3 version"""
if version.__version_info__[3] != 0:
return (1, "You are using a unstable version of GNS3.")
return (0, None)
def checkExperimentalFeaturesEnabled(self):
"""Checking if experimental features are not enabled"""
if LocalConfig.instance().experimental():
return (1, "Experimental features are enabled. Turn them off by going to Preferences -> General -> Miscellaneous.")
return (0, None)
def checkAVGInstalled(self):
"""Checking if AVG software is not installed"""
for proc in psutil.process_iter():
try:
psinfo = proc.as_dict(["exe"])
if psinfo["exe"] and "AVG\\" in psinfo["exe"]:
return (2, "AVG has known issues with GNS3, even after you disable it. You must whitelist dynamips.exe in the AVG preferences.")
except psutil.NoSuchProcess:
pass
return (0, None)
def checkFreeRam(self):
"""Checking for amount of free virtual memory"""
if int(psutil.virtual_memory().available / (1024 * 1024)) < 600:
return (2, "You have less than 600MB of available virtual memory, this could prevent nodes to start")
return (0, None)
def checkVmrun(self):
"""Checking if vmrun is installed"""
vmrun = VMware.instance().findVmrun()
if len(vmrun) == 0:
return (1, "The vmrun executable could not be found, VMware VMs cannot be used")
return (0, None)
def check64Bit(self):
"""Check if processor is 64 bit"""
if platform.architecture()[0] != "64bit":
return (2, "The architecture {} is not supported.".format(platform.architecture()[0]))
return (0, None)
def checkUbridgePermission(self):
"""Check if ubridge has the correct permission"""
if os.geteuid() == 0:
# we are root, so we should have privileged access.
return (0, None)
path = Servers.instance().localServerSettings().get("ubridge_path")
if path is None:
return (0, None)
request_setuid = False
if sys.platform.startswith("linux"):
if "security.capability" in os.listxattr(path):
caps = os.getxattr(path, "security.capability")
# test the 2nd byte and check if the 13th bit (CAP_NET_RAW) is set
if not struct.unpack("<IIIII", caps)[1] & 1 << 13:
return(2, "Ubridge require CAP_NET_RAW. Run sudo setcap cap_net_admin,cap_net_raw=ep {path}".format(path=path))
else:
# capabilities not supported
request_setuid = True
if sys.platform.startswith("darwin") or request_setuid:
if os.stat(path).st_uid != 0 or not os.stat(path).st_mode & stat.S_ISUID:
return (2, "Ubridge should be setuid. Run sudo chown root {path} and sudo chmod 4755 {path}".format(path=path))
return (0, None)
def checkDynamipsPermission(self):
"""Check if dynamips has the correct permission"""
if os.geteuid() == 0:
# we are root, so we should have privileged access.
return (0, None)
path = Servers.instance().localServerSettings().get("dynamips_path")
if path is None:
return (0, None)
if sys.platform.startswith("linux") and "security.capability" in os.listxattr(path):
caps = os.getxattr(path, "security.capability")
# test the 2nd byte and check if the 13th bit (CAP_NET_RAW) is set
if not struct.unpack("<IIIII", caps)[1] & 1 << 13:
return(2, "Dynamips require CAP_NET_RAW. Run sudo setcap cap_net_raw,cap_net_admin+eip {path}".format(path=path))
return (0, None)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
main = QtWidgets.QMainWindow()
dialog = DoctorDialog(main, console=True)
#dialog.show()
#exit_code = app.exec_()

View File

@@ -80,7 +80,7 @@ class SetupWizard(QtWidgets.QWizard, Ui_SetupWizard):
from gns3.modules import VMware
settings = VMware.instance().settings()
if not os.path.exists(settings["vmrun_path"]):
QtWidgets.QMessageBox.critical(self, "VMware", "VMware vmrun tool could not be found, VMware or the VIX API (required for VMware player) is probably not installed")
QtWidgets.QMessageBox.critical(self, "VMware", "VMware vmrun tool could not be found, VMware or the VIX API (required for VMware player) is probably not installed. You can download it from https://www.vmware.com/support/developer/vix-api/")
return
self._refreshVMListSlot()

View File

@@ -52,6 +52,10 @@ class TextEditorDialog(QtWidgets.QDialog, Ui_TextEditorDialog):
self.uiPlainTextEdit.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
if len(self._items) == 1:
self.uiApplyColorToAllItemsCheckBox.setChecked(True)
self.uiApplyColorToAllItemsCheckBox.hide()
self.uiApplyRotationToAllItemsCheckBox.setChecked(True)
self.uiApplyRotationToAllItemsCheckBox.hide()
self.uiApplyTextToAllItemsCheckBox.setChecked(True)
self.uiApplyTextToAllItemsCheckBox.hide()
@@ -90,9 +94,11 @@ class TextEditorDialog(QtWidgets.QDialog, Ui_TextEditorDialog):
"""
for item in self._items:
item.setDefaultTextColor(self._color)
item.setFont(self.uiPlainTextEdit.font())
item.setRotation(self.uiRotationSpinBox.value())
if self.uiApplyColorToAllItemsCheckBox.isChecked():
item.setDefaultTextColor(self._color)
if self.uiApplyRotationToAllItemsCheckBox.isChecked():
item.setRotation(self.uiRotationSpinBox.value())
if item.editable() and self.uiApplyTextToAllItemsCheckBox.isChecked():
item.setPlainText(self.uiPlainTextEdit.toPlainText())

View File

@@ -293,36 +293,36 @@ class GraphicsView(QtWidgets.QGraphicsView):
self.deleteLinkSlot(link_id)
return
# ugly multi-link management
# FIXME: taken from old GNS3 and has a bug!
multi = 0
d1 = 0
d2 = 1
link_items = source_item.links()
for link_item in link_items:
if link_item.destinationItem().node().id() == destination_item.node().id():
d1 += 1
if link_item.sourceItem().node().id() == destination_item.node().id():
d2 += 1
if len(link_items) > 0:
if d2 - d1 == 2:
source_port, destination_port = destination_port, source_port
source_item, destination_item = destination_item, source_item
multi = d1 + 1
elif d1 >= d2:
source_port, destination_port = destination_port, source_port
source_item, destination_item = destination_item, source_item
multi = d2
else:
multi = d1
# MAX 7 links on the scene between 2 nodes
if multi > 3:
multi = 0
# Multi-link management
#
# multi is the offset of the link
# +------+ multi = -1 Link 2 +-------+
# | +-----------------------------+ |
# | R1 | | R2 |
# | | multi = 0 Link 1 | |
# | +-----------------------------+ |
# | | multi = 1 Link 3 | |
# +------+-----------------------------+-------+
if source_item == destination_item:
multi = 0
else:
multi = 0
link_items = source_item.links()
for link_item in link_items:
if link_item.destinationItem().node().id() == destination_item.node().id():
multi += 1
if link_item.sourceItem().node().id() == destination_item.node().id():
multi += 1
# MAX 7 links on the scene between 2 nodes
if multi > 7:
multi = 0
# Pair item represent the bottom links
elif multi % 2 == 0:
multi = multi // 2
else:
multi = -multi // 2
if link.sourcePort().linkType() == "Serial" or (source_port.isStub() and link.destinationPort().linkType() == "Serial"):
link_item = SerialLinkItem(source_item, source_port, destination_item, destination_port, link, multilink=multi)

View File

@@ -54,7 +54,9 @@ class HTTPClient(QtCore.QObject):
# Callback class used for displaying progress
_progress_callback = None
connected_signal = QtCore.Signal()
connection_connected_signal = QtCore.Signal()
connection_closed_signal = QtCore.Signal()
system_usage_updated_signal = QtCore.Signal()
connection_error_signal = QtCore.Signal(str)
def __init__(self, settings, network_manager):
@@ -79,6 +81,7 @@ class HTTPClient(QtCore.QObject):
self._ram_limit = settings.get("ram_limit", 0)
self._allocated_ram = 0
self._accept_insecure_certificate = settings.get("accept_insecure_certificate", None)
self._usage = None
self._network_manager = network_manager
@@ -89,25 +92,6 @@ class HTTPClient(QtCore.QObject):
self._id = HTTPClient._instance_count
HTTPClient._instance_count += 1
def getTunnel(self, port):
"""
Get a tunnel to the remote port.
For HTTP standard client it's the same port. For SSH it will create a new tunnel.
:param port: Remote port
:returns: Tuple host, port to connect
"""
return self._host, port
def releaseTunnel(self, port):
"""
Release a tunnel to the remote port.
For HTTP standard client it's do nothing
:param port: Allocated remote port
"""
pass
def settings(self):
"""
Return a dictionnary with server settings
@@ -286,6 +270,7 @@ class HTTPClient(QtCore.QObject):
"""
log.info("Connection to %s closed", self.url())
self._connected = False
self.connection_closed_signal.emit()
def isLocalServerRunning(self):
"""
@@ -507,6 +492,7 @@ class HTTPClient(QtCore.QObject):
return
self._connected = True
self.connection_connected_signal.emit()
kwargs["context"] = original_context
self.executeHTTPQuery(method, path, callback, body, **kwargs)
self._version = params["version"]
@@ -787,5 +773,14 @@ class HTTPClient(QtCore.QObject):
server["accept_insecure_certificate"] = self._accept_insecure_certificate
return server
def isCloud(self):
return False
def systemUsage(self):
"""
Get information about current system usage
:returns: None or dict
"""
return self._usage
def setSystemUsage(self, usage):
self._usage = usage
self.system_usage_updated_signal.emit()

View File

@@ -172,6 +172,20 @@ class LinkItem(QtWidgets.QGraphicsPathItem):
cls._draw_port_labels = state
def resetPortLabels(self):
"""
Resets the port label positions.
"""
source_port_label = self._source_port.label()
destination_port_label = self._destination_port.label()
if source_port_label is not None:
source_port_label.delete()
self._source_port.setLabel(None)
if destination_port_label is not None:
destination_port_label.delete()
self._destination_port.setLabel(None)
def populateLinkContextualMenu(self, menu):
"""
Adds device actions to the link contextual menu.

View File

@@ -27,7 +27,6 @@ from .qt import QtCore
from .version import __version__
from .utils import parse_version
import logging
log = logging.getLogger(__name__)
@@ -147,6 +146,15 @@ class LocalConfig(QtCore.QObject):
main_window["hide_getting_started_dialog"] = self._settings["GUI"].get("hide_getting_started_dialog", False)
self._settings["MainWindow"] = main_window
if "version" not in self._settings or parse_version(self._settings["version"]) < parse_version("1.4.1dev2"):
if sys.platform.startswith("darwin"):
from .settings import PRECONFIGURED_TELNET_CONSOLE_COMMANDS, DEFAULT_TELNET_CONSOLE_COMMAND
if "MainWindow" in self._settings:
if self._settings["MainWindow"]["telnet_console_command"] not in PRECONFIGURED_TELNET_CONSOLE_COMMANDS.values():
self._settings["MainWindow"]["telnet_console_command"] = DEFAULT_TELNET_CONSOLE_COMMAND
def _readConfig(self, config_path):
"""
Read the configuration file.

View File

@@ -198,6 +198,10 @@ def main():
if DEFAULT_BINDING == "PyQt5" and version(QtCore.BINDING_VERSION_STR) < version("5.0.0"):
raise SystemExit("Requirement is PyQt5 version 5.0.0 or higher, got version {}".format(QtCore.BINDING_VERSION_STR))
import psutil
if version(psutil.__version__) < version("2.2.1"):
raise SystemExit("Requirement is psutil version 2.2.1 or higher, got version {}".format(psutil.__version__))
# check for the correct locale
# (UNIX/Linux only)
locale_check()

View File

@@ -43,6 +43,7 @@ from .dialogs.new_project_dialog import NewProjectDialog
from .dialogs.preferences_dialog import PreferencesDialog
from .dialogs.snapshots_dialog import SnapshotsDialog
from .dialogs.export_debug_dialog import ExportDebugDialog
from .dialogs.doctor_dialog import DoctorDialog
from .dialogs.setup_wizard import SetupWizard
from .settings import GENERAL_SETTINGS
from .utils.progress_dialog import ProgressDialog
@@ -119,6 +120,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
# populate the view -> docks menu
self.uiDocksMenu.addAction(self.uiTopologySummaryDockWidget.toggleViewAction())
self.uiDocksMenu.addAction(self.uiServerSummaryDockWidget.toggleViewAction())
self.uiDocksMenu.addAction(self.uiConsoleDockWidget.toggleViewAction())
self.uiDocksMenu.addAction(self.uiNodesDockWidget.toggleViewAction())
@@ -218,7 +220,6 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
self.uiFitInViewAction.triggered.connect(self._fitInViewActionSlot)
self.uiShowLayersAction.triggered.connect(self._showLayersActionSlot)
self.uiResetPortLabelsAction.triggered.connect(self._resetPortLabelsActionSlot)
self.uiShowNamesAction.triggered.connect(self._showNamesActionSlot)
self.uiShowPortNamesAction.triggered.connect(self._showPortNamesActionSlot)
# control menu connections
@@ -249,6 +250,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
self.uiAboutQtAction.triggered.connect(self._aboutQtActionSlot)
self.uiAboutAction.triggered.connect(self._aboutActionSlot)
self.uiExportDebugInformationAction.triggered.connect(self._exportDebugInformationSlot)
self.uiDoctorAction.triggered.connect(self._doctorSlot)
self.uiIOUVMConverterAction.triggered.connect(self._IOUVMConverterActionSlot)
# browsers tool bar connections
@@ -674,16 +676,10 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
Slot called to reset the port labels on the scene.
"""
# TODO: reset port labels
pass
def _showNamesActionSlot(self):
"""
Slot called to show the node names on the scene.
"""
# TODO: show/hide node names
pass
for item in self.uiGraphicsView.scene().items():
if isinstance(item, LinkItem):
item.resetPortLabels()
item.adjust()
def _showPortNamesActionSlot(self):
"""
@@ -923,6 +919,15 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
dialog.show()
dialog.exec_()
def _doctorSlot(self):
"""
Slot to display a window for exporting debug information
"""
dialog = DoctorDialog(self)
dialog.show()
dialog.exec_()
def _showNodesDockWidget(self, title, category):
"""
Makes the NodesDockWidget appear with the appropriate title and the devices

View File

@@ -74,7 +74,7 @@ class VMware(Module):
return None
@staticmethod
def _findVmrun(self):
def findVmrun():
"""
Finds the vmrun path.
@@ -91,7 +91,7 @@ class VMware(Module):
vmrun_path = vmrun_ws
else:
# look for vmrun.exe using the directory listed in the registry
vmrun_path = self._findVmrunRegistry(r"SOFTWARE\Wow6432Node\VMware, Inc.\VMware Workstation")
vmrun_path = VMware._findVmrunRegistry(r"SOFTWARE\Wow6432Node\VMware, Inc.\VMware Workstation")
if vmrun_path is None:
# look for vmrun.exe in default VMware VIX directory
vmrun_vix = os.path.expandvars(r"%PROGRAMFILES(X86)%\VMware\VMware VIX\vmrun.exe")
@@ -99,7 +99,7 @@ class VMware(Module):
vmrun_path = vmrun_vix
else:
# look for vmrun.exe using the directory listed in the registry
vmrun_path = self._findVmrunRegistry(r"SOFTWARE\Wow6432Node\VMware, Inc.\VMware VIX")
vmrun_path = VMware._findVmrunRegistry(r"SOFTWARE\Wow6432Node\VMware, Inc.\VMware VIX")
elif sys.platform.startswith("darwin"):
vmware_fusion_vmrun_path = "/Applications/VMware Fusion.app/Contents/Library/vmrun"
if os.path.exists(vmware_fusion_vmrun_path):
@@ -120,6 +120,10 @@ class VMware(Module):
return "fusion"
else:
vmware_path = shutil.which("vmware")
if vmware_path is None:
vmware_path = shutil.which("vmplayer")
if vmware_path is not None:
return "player"
if vmware_path:
command = [vmware_path, "-v"]
log.debug("Executing vmware with command: {}".format(command))
@@ -144,7 +148,7 @@ class VMware(Module):
local_config = LocalConfig.instance()
self._settings = local_config.loadSectionSettings(self.__class__.__name__, VMWARE_SETTINGS)
if not os.path.exists(self._settings["vmrun_path"]):
self._settings["vmrun_path"] = self._findVmrun(self)
self._settings["vmrun_path"] = self.findVmrun()
self._settings["host_type"] = self._determineHostType(self)
self._loadVMwareVMs()

View File

@@ -18,34 +18,19 @@
import ipaddress
def getNetworkClientInstance(settings, network_manager):
"""
Based on url return a network client instance
"""
if settings.get("protocol", "http") == "ssh":
from gns3.ssh_client import SSHClient
return SSHClient(settings, network_manager)
else:
from gns3.http_client import HTTPClient
return HTTPClient(settings, network_manager)
def getNetworkUrl(protocol, host, port, user=None, settings={}):
"""
Return a network url from settings
:param protocol: server protocol (http/ssh)
:param protocol: server protocol (http/https)
:param host: host address
:param port: port
:param user: the username
:param settings: Additional settings
"""
if protocol == "ssh":
return "{protocol}://{user}@{host}:{ssh_port}:{port}".format(protocol=protocol, user=user, host=host, port=port, ssh_port=settings["ssh_port"])
# 64 character autogenerated user name, we hide it, it's more user friendly
elif user and len(user) != 64:
if user and len(user) != 64:
try:
ipaddress.IPv6Address(host.rsplit('%', 1)[0]) # remove any scope ID

View File

@@ -59,8 +59,6 @@ class ServerPreferencesPage(QtWidgets.QWidget, Ui_ServerPreferencesPageWidget):
self.uiRemoteServersTreeWidget.itemSelectionChanged.connect(self._remoteServerChangedSlot)
self.uiRestoreDefaultsPushButton.clicked.connect(self._restoreDefaultsSlot)
self.uiLocalServerAutoStartCheckBox.stateChanged.connect(self._useLocalServerAutoStartSlot)
self.uiRemoteServerProtocolComboBox.currentIndexChanged.connect(self._remoteServerProtocolCurrentIndexSlot)
self.uiRemoteServerSSHKeyPushButton.clicked.connect(self._remoteServerSSHKeyPushButtonSlot)
self.uiEnableVMCheckBox.stateChanged.connect(self._enableGNS3VMSlot)
self.uiRefreshPushButton.clicked.connect(self._refreshVMListSlot)
self.uiVmwareRadioButton.clicked.connect(self._listVMwareVMsSlot)
@@ -79,8 +77,6 @@ class ServerPreferencesPage(QtWidgets.QWidget, Ui_ServerPreferencesPageWidget):
if index != -1:
self.uiLocalServerHostComboBox.setCurrentIndex(index)
self._remoteServerProtocolCurrentIndexSlot(0)
def _tabChangedSlot(self, index):
if index == 1:
self._refreshVMListSlot()
@@ -151,36 +147,6 @@ class ServerPreferencesPage(QtWidgets.QWidget, Ui_ServerPreferencesPageWidget):
else:
self.uiGNS3VMSettingsGroupBox.setEnabled(False)
def _remoteServerSSHKeyPushButtonSlot(self):
"""
Slot to open a file browser and select an ssh key.
"""
filter = ""
ssh_dir = os.path.join(os.path.expanduser("~"), ".ssh")
path, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Select the SSH key", ssh_dir, filter)
if not path:
return
self.uiRemoteServerSSHKeyLineEdit.setText(path)
def _remoteServerProtocolCurrentIndexSlot(self, index):
if self.uiRemoteServerProtocolComboBox.currentText() == "SSH":
self.uiRemoteServerPasswordLabel.hide()
self.uiRemoteServerPasswordLineEdit.hide()
self.uiRemoteServerSSHPortLabel.show()
self.uiRemoteServerSSHPortSpinBox.show()
self.uiRemoteServerSSHKeyLabel.show()
self.uiRemoteServerSSHKeyLineEdit.show()
self.uiRemoteServerSSHKeyPushButton.show()
else:
self.uiRemoteServerPasswordLabel.show()
self.uiRemoteServerPasswordLineEdit.show()
self.uiRemoteServerSSHPortLabel.hide()
self.uiRemoteServerSSHPortSpinBox.hide()
self.uiRemoteServerSSHKeyLabel.hide()
self.uiRemoteServerSSHKeyLineEdit.hide()
self.uiRemoteServerSSHKeyPushButton.hide()
def _useLocalServerAutoStartSlot(self, state):
"""
@@ -258,8 +224,6 @@ class ServerPreferencesPage(QtWidgets.QWidget, Ui_ServerPreferencesPageWidget):
self.uiRemoteServerPortSpinBox.setValue(port)
self.uiRAMLimitSpinBox.setValue(settings["ram_limit"])
self.uiRemoteServerUserLineEdit.setText(settings["user"])
self.uiRemoteServerSSHKeyLineEdit.setText(settings.get("ssh_key", None))
self.uiRemoteServerSSHPortSpinBox.setValue(settings.get("ssh_port", 22))
def _remoteServerChangedSlot(self):
"""
@@ -283,8 +247,6 @@ class ServerPreferencesPage(QtWidgets.QWidget, Ui_ServerPreferencesPageWidget):
ram_limit = self.uiRAMLimitSpinBox.value()
user = self.uiRemoteServerUserLineEdit.text().strip()
password = self.uiRemoteServerPasswordLineEdit.text().strip()
ssh_port = self.uiRemoteServerSSHPortSpinBox.value()
ssh_key = self.uiRemoteServerSSHKeyLineEdit.text().strip()
if not re.match(r"^[a-zA-Z0-9\.{}-]+$".format("\u0370-\u1CDF\u2C00-\u30FF\u4E00-\u9FBF"), host):
QtWidgets.QMessageBox.critical(self, "Remote server", "Invalid remote server hostname {}".format(host))
@@ -293,14 +255,6 @@ class ServerPreferencesPage(QtWidgets.QWidget, Ui_ServerPreferencesPageWidget):
QtWidgets.QMessageBox.critical(self, "Remote server", "Invalid remote server port {}".format(port))
return
if protocol == "ssh" and len(user) == 0:
QtWidgets.QMessageBox.critical(self, "Remote server", "Missing user login")
return
if protocol == "ssh" and len(ssh_key) == 0:
QtWidgets.QMessageBox.critical(self, "Remote server", "Missing SSH key")
return
# check if the remote server is already defined
for server in self._remote_servers.values():
if server["protocol"] == protocol and server["host"] == host and server["port"] == port and server["user"] == user:
@@ -312,9 +266,7 @@ class ServerPreferencesPage(QtWidgets.QWidget, Ui_ServerPreferencesPageWidget):
"port": port,
"ram_limit": ram_limit,
"user": user,
"password": password,
"ssh_port": ssh_port,
"ssh_key": ssh_key}
"password": password}
# add a new entry in the tree widget
item = QtWidgets.QTreeWidgetItem(self.uiRemoteServersTreeWidget)

View File

@@ -369,7 +369,7 @@ class Project(QtCore.QObject):
path = "/projects/{project_id}/notifications".format(project_id=self._id)
self._notifications_stream.add(server.createHTTPQuery("GET", path, None, downloadProgressCallback=self._event_received, showProgress=False, ignoreErrors=True))
def _event_received(self, result, **kwargs):
def _event_received(self, result, server=None, **kwargs):
log.debug("Event received: %s", result)
if result["action"] in ["vm.started", "vm.stopped"]:
@@ -390,4 +390,7 @@ class Project(QtCore.QObject):
elif result["action"] == "log.info":
log.info(result["event"]["message"])
print("Info: " + result["event"]["message"])
elif result["action"] == "ping":
# Compatible with 1.4.0 server
if "event" in result:
server.setSystemUsage(result["event"])

View File

@@ -228,36 +228,6 @@
"additionalProperties": false
},
"server_ssh": {
"properties": {
"protocol": { "enum": ["ssh"] },
"cloud": { "type": "boolean" },
"vm": { "type": "boolean" },
"host": { "$ref": "#/definitions/mandatory_string" },
"id": { "$ref": "#/definitions/numeric_id" },
"local": { "type": "boolean" },
"ram_limit": {
"type": "integer",
"minimum": 0
},
"port": { "$ref": "#/definitions/network_port" },
"ssh_key": { "$ref": "#/definitions/mandatory_string" },
"ssh_port": { "$ref": "#/definitions/network_port" },
"user": { "$ref": "#/definitions/mandatory_string" }
},
"required": [
"protocol",
"host",
"id",
"local",
"port",
"ssh_key",
"ssh_port",
"user"
],
"additionalProperties": false
},
"node": {
"type": "object",
"properties": {
@@ -692,13 +662,7 @@
},
"servers": {
"type": "array",
"items": {
"type": "object",
"oneOf": [
{ "$ref": "#/definitions/server_http" },
{ "$ref": "#/definitions/server_ssh" }
]
}
"items": { "$ref": "#/definitions/server_http" }
}
},
"additionalProperties": false

View File

@@ -20,6 +20,7 @@ Functions to start external serial console terminals.
"""
import sys
import os
import shlex
import subprocess
from .main_window import MainWindow
@@ -54,7 +55,7 @@ def serialConsole(vmname, pipe_path):
else:
# use arguments on other platforms
args = shlex.split(command)
subprocess.Popen(args)
subprocess.Popen(args, env=os.environ)
except (OSError, subprocess.SubprocessError) as e:
log.warning('could not start serial console "{}": {}'.format(command, e))
raise

108
gns3/server_summary_view.py Normal file
View File

@@ -0,0 +1,108 @@
# -*- coding: utf-8 -*-
#
# 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/>.
"""
Server summary view that list all the server, their status.
"""
import sip
from .qt import QtGui, QtCore, QtWidgets
from .servers import Servers
import logging
log = logging.getLogger(__name__)
class ServerItem(QtWidgets.QTreeWidgetItem):
"""
Custom item for the QTreeWidget instance
(topology summary view).
:param parent: parent widget
:param server: Server instance
"""
def __init__(self, parent, server):
super().__init__(parent)
self._server = server
self._parent = parent
self._status = "unknown"
self._server.connection_connected_signal.connect(self._refreshStatusSlot)
self._server.connection_closed_signal.connect(self._refreshStatusSlot)
self._server.system_usage_updated_signal.connect(self._refreshStatusSlot)
self._refreshStatusSlot()
def _refreshStatusSlot(self):
"""
Changes the icon to show the node status (started, stopped etc.)
"""
usage = self._server.systemUsage()
if self._server.isLocal():
text = "Local"
elif self._server.isGNS3VM():
text = "GNS3 VM"
else:
text = self._server.url()
if usage is not None and usage["cpu_usage_percent"] > 0.0:
text = "{} CPU {}%, RAM {}%".format(text, usage["cpu_usage_percent"], usage["memory_usage_percent"])
self.setText(0, text)
if self._server.connected():
self._status = "connected"
if usage is None or (usage["cpu_usage_percent"] < 90 and usage["memory_usage_percent"] < 90):
self.setIcon(0, QtGui.QIcon(':/icons/led_green.svg'))
else:
self.setIcon(0, QtGui.QIcon(':/icons/led_yellow.svg'))
else:
if self._status == "unknown":
self.setIcon(0, QtGui.QIcon(':/icons/led_gray.svg'))
else:
self._status = "stopped"
self.setIcon(0, QtGui.QIcon(':/icons/led_red.svg'))
class ServerSummaryView(QtWidgets.QTreeWidget):
"""
Server summary view implementation.
:param parent: parent widget
"""
def __init__(self, parent):
super().__init__(parent)
Servers.instance().server_added_signal.connect(self._serverAddedSlot)
for server in Servers.instance().servers():
self._serverAddedSlot(server.url())
def _serverAddedSlot(self, url):
"""
Called when a server is added to the list of servers
:params url: URL of the server
"""
server = Servers.instance().getServerFromString(url)
ServerItem(self, server)

View File

@@ -34,8 +34,8 @@ import stat
import struct
import psutil
from .qt import QtNetwork, QtWidgets
from .network_client import getNetworkClientInstance, getNetworkUrl
from .qt import QtNetwork, QtWidgets, QtCore
from .network_client import getNetworkUrl
from .local_config import LocalConfig
from .settings import SERVERS_SETTINGS
from .local_server_config import LocalServerConfig
@@ -48,14 +48,17 @@ import logging
log = logging.getLogger(__name__)
class Servers():
class Servers(QtCore.QObject):
"""
Server management class.
"""
server_added_signal = QtCore.Signal(str)
def __init__(self):
super().__init__()
self._settings = {}
self._local_server = None
self._vm_server = None
@@ -71,6 +74,17 @@ class Servers():
self._pid_path = os.path.join(LocalConfig.configDirectory(), "gns3_server.pid")
self.registerLocalServer()
def servers(self):
"""
Return the list of all servers, remote, vm and local
"""
servers = list(self._remote_servers.values())
if self._local_server:
servers.append(self._local_server)
if self._vm_server:
servers.append(self._vm_server)
return servers
def registerLocalServer(self):
"""
Register a new local server.
@@ -81,11 +95,13 @@ class Servers():
port = local_server_settings["port"]
user = local_server_settings["user"]
password = local_server_settings["password"]
self._local_server = getNetworkClientInstance({"host": host, "port": port, "user": user, "password": password},
self._local_server = self.getNetworkClientInstance({"host": host, "port": port, "user": user, "password": password},
self._network_manager)
self._local_server.setLocal(True)
self.server_added_signal.emit("local")
log.info("New local server connection {} registered".format(self._local_server.url()))
@staticmethod
def _findLocalServer(self):
"""
@@ -231,8 +247,6 @@ class Servers():
ram_limit=remote_server.get("ram_limit", 0),
user=remote_server.get("user", None),
password=remote_server.get("password", None),
ssh_key=remote_server.get("ssh_key", None),
ssh_port=remote_server.get("ssh_port", None),
accept_insecure_certificate=remote_server.get("accept_insecure_certificate", False))
changed = False
@@ -559,15 +573,15 @@ class Servers():
self._local_server_process.wait(timeout=2)
except subprocess.TimeoutExpired:
# the local server couldn't be stopped with the normal procedure
if sys.platform.startswith("win"):
try:
try:
if sys.platform.startswith("win"):
self._local_server_process.send_signal(signal.CTRL_BREAK_EVENT)
# If the process is already dead we received a permission error
# it's a race condition between the timeout and send signal
except PermissionError:
pass
else:
self._local_server_process.send_signal(signal.SIGINT)
else:
self._local_server_process.send_signal(signal.SIGINT)
# If the process is already dead we received a permission error
# it's a race condition between the timeout and send signal
except PermissionError:
pass
try:
# wait for the server to stop for maximum 2 seconds
self._local_server_process.wait(timeout=2)
@@ -605,10 +619,11 @@ class Servers():
"user": gns3_vm_settings["user"],
"password": gns3_vm_settings["password"]
}
server = getNetworkClientInstance(server_info, self._network_manager)
server = self.getNetworkClientInstance(server_info, self._network_manager)
server.setLocal(False)
server.setGNS3VM(True)
self._vm_server = server
self.server_added_signal.emit("vm")
log.info("GNS3 VM server initialized {}".format(server.url()))
def vmServer(self):
@@ -620,7 +635,7 @@ class Servers():
return self._vm_server
def _addRemoteServer(self, protocol="http", host="localhost", port=8000, ram_limit=0, user=None, password=None, ssh_port=None, ssh_key=None, accept_insecure_certificate=False, id=None):
def _addRemoteServer(self, protocol="http", host="localhost", port=8000, ram_limit=0, user=None, password=None, accept_insecure_certificate=False, id=None):
"""
Adds a new remote server.
@@ -630,8 +645,6 @@ class Servers():
:param ram_limit: maximum RAM to be used (integer)
:param user: user login or None
:param password: user password or None
:param ssh_port: ssh port or None
:param ssh_key: ssh key
:param accept_insecure_certificate: Accept invalid SSL certificate
:returns: the new remote server
@@ -642,23 +655,31 @@ class Servers():
"ram_limit": ram_limit,
"protocol": protocol,
"user": user,
"password": password,
"ssh_port": ssh_port,
"ssh_key": ssh_key}
"password": password}
if accept_insecure_certificate:
server["accept_insecure_certificate"] = accept_insecure_certificate
server = getNetworkClientInstance(server, self._network_manager)
server = self.getNetworkClientInstance(server, self._network_manager)
server.setLocal(False)
self._remote_servers[server.url()] = server
self.server_added_signal.emit(server.url())
log.info("New remote server connection {} registered".format(server.url()))
return server
def getNetworkClientInstance(self, settings, network_manager):
"""
Based on url return a network client instance
"""
from gns3.http_client import HTTPClient
client = HTTPClient(settings, network_manager)
return client
def getRemoteServer(self, protocol, host, port, user, settings={}):
"""
Gets a remote server.
:param protocol: server protocol (http/ssh)
:param protocol: server protocol (http/https)
:param host: host address
:param port: port
:param user: the username
@@ -691,13 +712,12 @@ class Servers():
return self.anyRemoteServer()
if "://" in server_name:
for server in self.servers():
if server.url() == server_name:
return server
url_settings = urllib.parse.urlparse(server_name)
if url_settings.scheme == "ssh":
_, ssh_port, port = url_settings.netloc.split(":")
settings = {"ssh_port": int(ssh_port)}
else:
settings = {}
port = url_settings.port
settings = {}
port = url_settings.port
return self.getRemoteServer(url_settings.scheme, url_settings.hostname, port, url_settings.username, settings=settings)
else:
(host, port) = server_name.split(":")
@@ -742,9 +762,10 @@ class Servers():
if server_id in self._remote_servers:
continue
new_server = getNetworkClientInstance(server, self._network_manager)
new_server = self.getNetworkClientInstance(server, self._network_manager)
new_server.setLocal(False)
self._remote_servers[server_id] = new_server
self.server_added_signal.emit(new_server.url())
log.info("New remote server connection {} registered".format(new_server.url()))
def remoteServers(self):
@@ -801,6 +822,8 @@ class Servers():
if self._local_server.connected():
self._local_server.close()
if self._vm_server is not None and self._vm_server.connected():
self._vm_server.close()
for server in self._remote_servers.values():
if server.connected():
server.close()

View File

@@ -1,144 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 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/>.
import paramiko
from gns3.http_client import HTTPClient
from gns3.tunnel.endpoint import Endpoint
from gns3.qt import QtCore
import logging
log = logging.getLogger(__name__)
class SSHConnectionThread(QtCore.QThread):
error_signal = QtCore.pyqtSignal(str)
connected_signal = QtCore.pyqtSignal()
def __init__(self, ssh_client, parent=None):
self._ssh_client = ssh_client
super().__init__(parent)
def run(self):
port = Endpoint.find_unused_port(1000, 10000)
if port is None:
self.error_signal.emit("No port available in order to create SSH tunnel")
return
try:
self._ssh_client.transport = paramiko.Transport((self._ssh_client.host(), self._ssh_client.ssh_port(), ))
self._ssh_client.transport.set_keepalive(30)
with open(self._ssh_client.ssh_key()) as f:
self._ssh_client.transport.connect(username=self._ssh_client.user(), pkey=paramiko.RSAKey.from_private_key(f))
endpoint = Endpoint(("127.0.0.1", port), ("127.0.0.1", self._ssh_client._http_port), self._ssh_client.transport)
endpoint.enable()
self._ssh_client._endpoints[port] = endpoint
except (paramiko.ssh_exception.SSHException, OSError) as e:
self.error_signal.emit(str(e))
return
self._ssh_client._http_port = port
self.connected_signal.emit()
class SSHClient(HTTPClient):
"""
SSH client.
It's create an SSH tunnel and run HTTP query inside the tunnel
:param settings: Settings to connect to the server
:param network_manager: A QT network manager
"""
def __init__(self, settings, network_manager):
settings["protocol"] = "http"
settings["http_host"] = "127.0.0.1"
self._ssh_port = settings["ssh_port"]
self._ssh_key = settings["ssh_key"]
self._endpoints = {}
assert settings["ssh_port"] is not None
assert settings["ssh_key"] is not None
super().__init__(settings, network_manager)
def _connect(self, query):
"""
Initialize the connection
:param query: The query to execute when all network stack is ready
:param callback: User callback when connection is finish
"""
log.info("SSH connection to %s with key %s", self.url(), self.ssh_key())
thread = SSHConnectionThread(self, parent=self)
thread.error_signal.connect(lambda msg: self._connectionError(None, msg))
thread.connected_signal.connect(lambda: super(SSHClient, self)._connect(query ))
thread.start()
def getTunnel(self, port):
"""
Get a tunnel to the remote port.
For HTTP standard client it's the same port. For SSH it will be different
:param port: Remote port
:returns: Tuple host, port to connect
"""
new_port = Endpoint.find_unused_port(1000, 10000)
endpoint = Endpoint(("127.0.0.1", new_port), ("127.0.0.1", port), self.transport)
endpoint.enable()
self._endpoints[new_port] = endpoint
return ("127.0.0.1", new_port)
def releaseTunnel(self, port):
"""
Release a tunnel
:param port: The previously allocated port
"""
endpoint = self._endpoints[port]
endpoint.disable()
del self._endpoints[port]
def settings(self):
settings = super().settings()
settings["ssh_port"] = self.ssh_port()
settings["ssh_key"] = self.ssh_key()
return settings
def ssh_port(self):
return self._ssh_port
def ssh_key(self):
return self._ssh_key
def protocol(self):
return "ssh"
def close(self):
"""
Close all remote connection
"""
for endpoint in self._endpoints.values():
endpoint.disable()
super().close()

View File

@@ -60,7 +60,8 @@ class ConsoleThread(QtCore.QThread):
def run(self):
(host, port) = self._server.getTunnel(self._port)
host = self._server.host()
port = self._port
# replace the place-holders by the actual values
command = self._command.replace("%h", host)
@@ -81,9 +82,6 @@ class ConsoleThread(QtCore.QThread):
log.info('Telnet console {}:{} closed'.format(host, port))
if sys.platform.startswith("darwin") and "osascript" in command:
console_mutex.unlock()
else:
#TODO: For apple script we can't detect when the console is closed. This mean we leak a port each time you close the console
self._server.releaseTunnel(port)
def nodeTelnetConsole(name, server, port):

View File

@@ -19,6 +19,8 @@
Topology summary view that list all the nodes, their status and connections.
"""
import sip
from .qt import QtGui, QtCore, QtWidgets
from .node import Node
from .topology import Topology
@@ -59,7 +61,8 @@ class TopologyNodeItem(QtWidgets.QTreeWidgetItem):
"""
Changes the icon to show the node status (started, stopped etc.)
"""
if self is None or sip.isdeleted(self):
return
self.setText(0, self._node.name())
if self._node.status() == Node.started:
self.setIcon(0, QtGui.QIcon(':/icons/led_green.svg'))

View File

@@ -1,164 +0,0 @@
import socket
import select
import socketserver
import threading
import logging
log = logging.getLogger(__name__)
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
allow_reuse_address = True
daemon_threads = True # Kill the threads when server is closing
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
try:
chan = self.ssh_transport.open_channel('direct-tcpip',
self.remote_address,
self.request.getpeername())
except Exception as e:
log.critical('Incoming request to %s failed: %s' % (
self.remote_address,
str(e)
)
)
return
if chan is None:
log.critical('Incoming request to %s:%s was rejected by the SSH server.' %
(self.remote_address))
return
log.debug('Connected! Tunnel open %r -> %r -> %r' % (self.request.getpeername(),
chan.getpeername(), self.remote_address))
while True:
r, w, x = select.select([self.request, chan], [], [])
if self.request in r:
data = self.request.recv(1024)
if len(data) == 0:
break
chan.send(data)
if chan in r:
data = chan.recv(1024)
if len(data) == 0:
break
self.request.send(data)
peername = self.request.getpeername()
chan.close()
self.request.close()
log.debug('Tunnel closed from %r' % (peername,))
class Endpoint:
def __init__(self, local_address, remote_address, transport):
"""
Store local and remote tunnel address information in the format:
(ip, port) format.
"""
self.local_address = local_address
self.remote_address = remote_address
self.transport = transport
self.thread = None
self.server = None
def get(self):
return (self.local_address, self.remote_address)
def log_msg(self, msg):
if self.thread:
thread_name = self.thread.name
else:
thread_name = "Creating ID"
log.info("%s: local %s:%s for remote %s:%s - %s" % (
thread_name,
self.local_address[0],
self.local_address[1],
self.remote_address[0],
self.remote_address[1],
msg,
))
def _enable(self, local_address, remote_address, ssh_transport):
# https://github.com/paramiko/paramiko/blob/master/demos/forward.py
# This is a little convoluted, but lets me configure things for the Handler
# object. (SocketServer doesn't give Handlers any way to access the outer
# server normally.)
class EndPointHandler(ThreadedTCPRequestHandler):
remote_address = self.remote_address
local_address = self.local_address
ssh_transport = self.transport
server = ThreadedTCPServer(self.local_address, EndPointHandler)
# https://docs.python.org/3.4/library/socketserver.html
# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.daemon = True
server_thread.start()
self.thread = server_thread
self.server = server
self.log_msg("Server thread running")
def getId(self):
return self.thread.name
def enable(self):
self.log_msg("Starting server thread")
self._enable(self.local_address, self.remote_address, self.transport)
def disable(self):
if self.server:
self.log_msg("Stopping server thread")
self.server.shutdown()
else:
self.log_msg("No server thread running to stop")
@staticmethod
def find_unused_port(start_port, end_port, host="127.0.0.1", socket_type="TCP", ignore_ports=[]):
"""
Finds an unused port in a range.
:param start_port: first port in the range
:param end_port: last port in the range
:param host: host/address for bind()
:param socket_type: TCP (default) or UDP
:param ignore_ports: list of port to ignore within the range
"""
if socket_type == "UDP":
socket_type = socket.SOCK_DGRAM
else:
socket_type = socket.SOCK_STREAM
last_exception = None
for port in range(start_port, end_port + 1):
if port in ignore_ports:
continue
try:
for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket_type, 0, socket.AI_PASSIVE):
af, socktype, proto, _, sa = res
with socket.socket(af, socktype, proto) as s:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(sa) # the port is available if bind is a success
return port
except OSError as e:
last_exception = e
if port + 1 == end_port:
break
else:
continue
raise Exception("Could not find a free port between {} and {} on host {}, last exception: {}".format(start_port,
end_port,
host,
last_exception))

98
gns3/ui/doctor_dialog.ui Executable file
View File

@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DoctorDialog</class>
<widget class="QDialog" name="DoctorDialog">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>607</width>
<height>390</height>
</rect>
</property>
<property name="windowTitle">
<string>GNS3 Doctor</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="rightMargin">
<number>12</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This will list potential problem in your GNS3 installation:&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="uiDoctorResultTextEdit">
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'.SF NS Text'; font-size:13pt; font-weight:600; font-style:italic;&quot;&gt;Starting checks...&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>20</number>
</property>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="uiOkButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="../../resources/resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/doctor_dialog.ui'
#
# Created: Tue Jan 26 16:05:25 2016
# by: PyQt5 UI code generator 5.2.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_DoctorDialog(object):
def setupUi(self, DoctorDialog):
DoctorDialog.setObjectName("DoctorDialog")
DoctorDialog.setWindowModality(QtCore.Qt.WindowModal)
DoctorDialog.resize(607, 390)
DoctorDialog.setModal(True)
self.verticalLayout = QtWidgets.QVBoxLayout(DoctorDialog)
self.verticalLayout.setContentsMargins(-1, -1, 12, -1)
self.verticalLayout.setObjectName("verticalLayout")
self.label = QtWidgets.QLabel(DoctorDialog)
self.label.setTextFormat(QtCore.Qt.RichText)
self.label.setScaledContents(False)
self.label.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
self.label.setWordWrap(True)
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
self.uiDoctorResultTextEdit = QtWidgets.QTextEdit(DoctorDialog)
self.uiDoctorResultTextEdit.setObjectName("uiDoctorResultTextEdit")
self.verticalLayout.addWidget(self.uiDoctorResultTextEdit)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setSpacing(20)
self.horizontalLayout.setObjectName("horizontalLayout")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.uiOkButton = QtWidgets.QDialogButtonBox(DoctorDialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.uiOkButton.sizePolicy().hasHeightForWidth())
self.uiOkButton.setSizePolicy(sizePolicy)
self.uiOkButton.setOrientation(QtCore.Qt.Horizontal)
self.uiOkButton.setStandardButtons(QtWidgets.QDialogButtonBox.Ok)
self.uiOkButton.setObjectName("uiOkButton")
self.horizontalLayout.addWidget(self.uiOkButton)
self.verticalLayout.addLayout(self.horizontalLayout)
self.retranslateUi(DoctorDialog)
QtCore.QMetaObject.connectSlotsByName(DoctorDialog)
def retranslateUi(self, DoctorDialog):
_translate = QtCore.QCoreApplication.translate
DoctorDialog.setWindowTitle(_translate("DoctorDialog", "GNS3 Doctor"))
self.label.setText(_translate("DoctorDialog", "<html><head/><body><p>This will list potential problem in your GNS3 installation:</p></body></html>"))
self.uiDoctorResultTextEdit.setHtml(_translate("DoctorDialog", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"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=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'.SF NS Text\'; font-size:13pt; font-weight:600; font-style:italic;\">Starting checks...</span></p></body></html>"))
from . import resources_rc

View File

@@ -113,7 +113,8 @@ background-none;
<addaction name="uiCheckForUpdateAction"/>
<addaction name="uiSetupWizard"/>
<addaction name="uiLabInstructionsAction"/>
<addaction name="uiExportDebugInformationsAction"/>
<addaction name="uiDoctorAction"/>
<addaction name="uiExportDebugInformationAction"/>
<addaction name="uiAboutQtAction"/>
<addaction name="uiAboutAction"/>
</widget>
@@ -420,7 +421,7 @@ background-none;
</sizepolicy>
</property>
<property name="allowedAreas">
<set>Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea</set>
<set>Qt::AllDockWidgetAreas</set>
</property>
<property name="windowTitle">
<string>Topology Summary</string>
@@ -472,6 +473,48 @@ background-none;
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="uiServerSummaryDockWidget">
<property name="allowedAreas">
<set>Qt::AllDockWidgetAreas</set>
</property>
<property name="windowTitle">
<string>Servers Summary</string>
</property>
<attribute name="dockWidgetArea">
<number>2</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="ServerSummaryView" name="uiServerSummaryTreeWidget">
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</widget>
<action name="uiAboutAction">
<property name="text">
<string>&amp;About</string>
@@ -603,24 +646,6 @@ background-none;
<string>Stop all devices</string>
</property>
</action>
<action name="uiShowNamesAction">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../../resources/resources.qrc">
<normaloff>:/icons/show-hostname.svg</normaloff>:/icons/show-hostname.svg</iconset>
</property>
<property name="text">
<string>Show hostnames</string>
</property>
<property name="toolTip">
<string>Show hostnames</string>
</property>
<property name="statusTip">
<string>Show hostnames</string>
</property>
</action>
<action name="uiConsoleAllAction">
<property name="enabled">
<bool>true</bool>
@@ -970,7 +995,7 @@ background-none;
</action>
<action name="uiCheckForUpdateAction">
<property name="text">
<string>Check for Update</string>
<string>Check for &amp;Update</string>
</property>
<property name="statusTip">
<string>Check for Update</string>
@@ -1121,7 +1146,7 @@ background-none;
</action>
<action name="uiLabInstructionsAction">
<property name="text">
<string>Lab instructions</string>
<string>&amp;Lab instructions</string>
</property>
</action>
<action name="uiFitInViewAction">
@@ -1219,9 +1244,17 @@ background-none;
<string>Import appliance</string>
</property>
</action>
<action name="uiExportDebugInformationsAction">
<action name="uiExportDebugInformationAction">
<property name="text">
<string>Export debug informations</string>
<string>Export debug information</string>
</property>
<property name="toolTip">
<string>&amp;Export debug information</string>
</property>
</action>
<action name="uiDoctorAction">
<property name="text">
<string>GNS3 &amp;Doctor</string>
</property>
</action>
</widget>
@@ -1246,6 +1279,11 @@ background-none;
<extends>QTreeWidget</extends>
<header>..topology_summary_view.h</header>
</customwidget>
<customwidget>
<class>ServerSummaryView</class>
<extends>QTreeWidget</extends>
<header>..server_summary_view.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>uiGraphicsView</tabstop>

View File

@@ -8,30 +8,28 @@
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.setWindowModality(QtCore.Qt.NonModal)
MainWindow.resize(984, 715)
MainWindow.setContextMenuPolicy(QtCore.Qt.PreventContextMenu)
MainWindow.setStyleSheet("#toolBar_Devices QToolButton {\n"
"width: 50px;\n"
"height: 55px;\n"
"border:solid 1px black opacity 0.4;\n"
"background-none;\n"
"}\n"
"\n"
"#toolBar_General QToolButton {\n"
"width: 36px;\n"
"height: 36px;\n"
"border:solid 1px black opacity 0.4;\n"
"background-none;\n"
"}\n"
"\n"
"")
MainWindow.setDockOptions(QtWidgets.QMainWindow.AllowTabbedDocks | QtWidgets.QMainWindow.AnimatedDocks)
"width: 50px;\n"
"height: 55px;\n"
"border:solid 1px black opacity 0.4;\n"
"background-none;\n"
"}\n"
"\n"
"#toolBar_General QToolButton {\n"
"width: 36px;\n"
"height: 36px;\n"
"border:solid 1px black opacity 0.4;\n"
"background-none;\n"
"}\n"
"\n"
"")
MainWindow.setDockOptions(QtWidgets.QMainWindow.AllowTabbedDocks|QtWidgets.QMainWindow.AnimatedDocks)
self.uiCentralWidget = QtWidgets.QWidget(MainWindow)
self.uiCentralWidget.setObjectName("uiCentralWidget")
self.gridlayout = QtWidgets.QGridLayout(self.uiCentralWidget)
@@ -83,7 +81,7 @@ class Ui_MainWindow(object):
self.uiNodesDockWidget.setEnabled(True)
self.uiNodesDockWidget.setVisible(True)
self.uiNodesDockWidget.setFloating(False)
self.uiNodesDockWidget.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.RightDockWidgetArea)
self.uiNodesDockWidget.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea|QtCore.Qt.RightDockWidgetArea)
self.uiNodesDockWidget.setObjectName("uiNodesDockWidget")
self.uiNodesDockWidgetContents = QtWidgets.QWidget()
self.uiNodesDockWidgetContents.setObjectName("uiNodesDockWidgetContents")
@@ -145,7 +143,7 @@ class Ui_MainWindow(object):
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.uiTopologySummaryDockWidget.sizePolicy().hasHeightForWidth())
self.uiTopologySummaryDockWidget.setSizePolicy(sizePolicy)
self.uiTopologySummaryDockWidget.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.RightDockWidgetArea)
self.uiTopologySummaryDockWidget.setAllowedAreas(QtCore.Qt.AllDockWidgetAreas)
self.uiTopologySummaryDockWidget.setObjectName("uiTopologySummaryDockWidget")
self.uiTopologySummaryDockWidgetContents = QtWidgets.QWidget()
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
@@ -169,6 +167,22 @@ class Ui_MainWindow(object):
self.gridlayout1.addWidget(self.uiTopologySummaryTreeWidget, 0, 0, 1, 1)
self.uiTopologySummaryDockWidget.setWidget(self.uiTopologySummaryDockWidgetContents)
MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(2), self.uiTopologySummaryDockWidget)
self.uiServerSummaryDockWidget = QtWidgets.QDockWidget(MainWindow)
self.uiServerSummaryDockWidget.setAllowedAreas(QtCore.Qt.AllDockWidgetAreas)
self.uiServerSummaryDockWidget.setObjectName("uiServerSummaryDockWidget")
self.dockWidgetContents = QtWidgets.QWidget()
self.dockWidgetContents.setObjectName("dockWidgetContents")
self.gridLayout = QtWidgets.QGridLayout(self.dockWidgetContents)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setSpacing(0)
self.gridLayout.setObjectName("gridLayout")
self.uiServerSummaryTreeWidget = ServerSummaryView(self.dockWidgetContents)
self.uiServerSummaryTreeWidget.setObjectName("uiServerSummaryTreeWidget")
self.uiServerSummaryTreeWidget.headerItem().setText(0, "1")
self.uiServerSummaryTreeWidget.header().setVisible(False)
self.gridLayout.addWidget(self.uiServerSummaryTreeWidget, 0, 0, 1, 1)
self.uiServerSummaryDockWidget.setWidget(self.dockWidgetContents)
MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(2), self.uiServerSummaryDockWidget)
self.uiAboutAction = QtWidgets.QAction(MainWindow)
self.uiAboutAction.setMenuRole(QtWidgets.QAction.AboutRole)
self.uiAboutAction.setObjectName("uiAboutAction")
@@ -212,32 +226,26 @@ class Ui_MainWindow(object):
icon6.addPixmap(QtGui.QPixmap(":/icons/stop-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiStopAllAction.setIcon(icon6)
self.uiStopAllAction.setObjectName("uiStopAllAction")
self.uiShowNamesAction = QtWidgets.QAction(MainWindow)
self.uiShowNamesAction.setCheckable(True)
icon7 = QtGui.QIcon()
icon7.addPixmap(QtGui.QPixmap(":/icons/show-hostname.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiShowNamesAction.setIcon(icon7)
self.uiShowNamesAction.setObjectName("uiShowNamesAction")
self.uiConsoleAllAction = QtWidgets.QAction(MainWindow)
self.uiConsoleAllAction.setEnabled(True)
icon8 = QtGui.QIcon()
icon8.addPixmap(QtGui.QPixmap(":/icons/console.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiConsoleAllAction.setIcon(icon8)
icon7 = QtGui.QIcon()
icon7.addPixmap(QtGui.QPixmap(":/icons/console.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiConsoleAllAction.setIcon(icon7)
self.uiConsoleAllAction.setObjectName("uiConsoleAllAction")
self.uiAboutQtAction = QtWidgets.QAction(MainWindow)
self.uiAboutQtAction.setMenuRole(QtWidgets.QAction.AboutQtRole)
self.uiAboutQtAction.setObjectName("uiAboutQtAction")
self.uiZoomInAction = QtWidgets.QAction(MainWindow)
icon9 = QtGui.QIcon()
icon9.addPixmap(QtGui.QPixmap(":/icons/zoom-in.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon9.addPixmap(QtGui.QPixmap(":/icons/zoom-in-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiZoomInAction.setIcon(icon9)
icon8 = QtGui.QIcon()
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)
icon10 = QtGui.QIcon()
icon10.addPixmap(QtGui.QPixmap(":/icons/zoom-out.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon10.addPixmap(QtGui.QPixmap(":/icons/zoom-out-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiZoomOutAction.setIcon(icon10)
icon9 = QtGui.QIcon()
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)
self.uiZoomResetAction.setObjectName("uiZoomResetAction")
@@ -246,82 +254,82 @@ class Ui_MainWindow(object):
self.uiSelectNoneAction = QtWidgets.QAction(MainWindow)
self.uiSelectNoneAction.setObjectName("uiSelectNoneAction")
self.uiPreferencesAction = QtWidgets.QAction(MainWindow)
icon11 = QtGui.QIcon()
icon11.addPixmap(QtGui.QPixmap(":/icons/applications.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiPreferencesAction.setIcon(icon11)
icon10 = QtGui.QIcon()
icon10.addPixmap(QtGui.QPixmap(":/icons/applications.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiPreferencesAction.setIcon(icon10)
self.uiPreferencesAction.setMenuRole(QtWidgets.QAction.PreferencesRole)
self.uiPreferencesAction.setObjectName("uiPreferencesAction")
self.uiSuspendAllAction = QtWidgets.QAction(MainWindow)
icon12 = QtGui.QIcon()
icon12.addPixmap(QtGui.QPixmap(":/icons/pause.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon12.addPixmap(QtGui.QPixmap(":/icons/pause-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiSuspendAllAction.setIcon(icon12)
icon11 = QtGui.QIcon()
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)
self.uiAddNoteAction.setCheckable(True)
icon13 = QtGui.QIcon()
icon13.addPixmap(QtGui.QPixmap(":/icons/add-note.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiAddNoteAction.setIcon(icon13)
icon12 = QtGui.QIcon()
icon12.addPixmap(QtGui.QPixmap(":/icons/add-note.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiAddNoteAction.setIcon(icon12)
self.uiAddNoteAction.setObjectName("uiAddNoteAction")
self.uiNewProjectAction = QtWidgets.QAction(MainWindow)
icon14 = QtGui.QIcon()
icon14.addPixmap(QtGui.QPixmap(":/icons/new-project.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiNewProjectAction.setIcon(icon14)
icon13 = QtGui.QIcon()
icon13.addPixmap(QtGui.QPixmap(":/icons/new-project.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiNewProjectAction.setIcon(icon13)
self.uiNewProjectAction.setObjectName("uiNewProjectAction")
self.uiImportExportConfigsAction = QtWidgets.QAction(MainWindow)
icon15 = QtGui.QIcon()
icon15.addPixmap(QtGui.QPixmap(":/icons/import_export_configs.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiImportExportConfigsAction.setIcon(icon15)
icon14 = QtGui.QIcon()
icon14.addPixmap(QtGui.QPixmap(":/icons/import_export_configs.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiImportExportConfigsAction.setIcon(icon14)
self.uiImportExportConfigsAction.setObjectName("uiImportExportConfigsAction")
self.uiInsertImageAction = QtWidgets.QAction(MainWindow)
self.uiInsertImageAction.setCheckable(False)
icon16 = QtGui.QIcon()
icon16.addPixmap(QtGui.QPixmap(":/icons/image.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiInsertImageAction.setIcon(icon16)
icon15 = QtGui.QIcon()
icon15.addPixmap(QtGui.QPixmap(":/icons/image.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiInsertImageAction.setIcon(icon15)
self.uiInsertImageAction.setObjectName("uiInsertImageAction")
self.uiDrawRectangleAction = QtWidgets.QAction(MainWindow)
self.uiDrawRectangleAction.setCheckable(True)
icon17 = QtGui.QIcon()
icon17.addPixmap(QtGui.QPixmap(":/icons/rectangle.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon17.addPixmap(QtGui.QPixmap(":/icons/rectangle-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiDrawRectangleAction.setIcon(icon17)
icon16 = QtGui.QIcon()
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)
icon18 = QtGui.QIcon()
icon18.addPixmap(QtGui.QPixmap(":/icons/ellipse.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon18.addPixmap(QtGui.QPixmap(":/icons/ellipse-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiDrawEllipseAction.setIcon(icon18)
icon17 = QtGui.QIcon()
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)
self.uiShowPortNamesAction.setCheckable(True)
icon19 = QtGui.QIcon()
icon19.addPixmap(QtGui.QPixmap(":/icons/show-interface-names.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiShowPortNamesAction.setIcon(icon19)
icon18 = QtGui.QIcon()
icon18.addPixmap(QtGui.QPixmap(":/icons/show-interface-names.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiShowPortNamesAction.setIcon(icon18)
self.uiShowPortNamesAction.setObjectName("uiShowPortNamesAction")
self.uiSnapshotAction = QtWidgets.QAction(MainWindow)
icon20 = QtGui.QIcon()
icon20.addPixmap(QtGui.QPixmap(":/icons/snapshot.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiSnapshotAction.setIcon(icon20)
icon19 = QtGui.QIcon()
icon19.addPixmap(QtGui.QPixmap(":/icons/snapshot.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiSnapshotAction.setIcon(icon19)
self.uiSnapshotAction.setObjectName("uiSnapshotAction")
self.uiShowLayersAction = QtWidgets.QAction(MainWindow)
self.uiShowLayersAction.setCheckable(True)
self.uiShowLayersAction.setObjectName("uiShowLayersAction")
self.uiSaveProjectAsAction = QtWidgets.QAction(MainWindow)
icon21 = QtGui.QIcon()
icon21.addPixmap(QtGui.QPixmap(":/icons/save-as-project.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiSaveProjectAsAction.setIcon(icon21)
icon20 = QtGui.QIcon()
icon20.addPixmap(QtGui.QPixmap(":/icons/save-as-project.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiSaveProjectAsAction.setIcon(icon20)
self.uiSaveProjectAsAction.setObjectName("uiSaveProjectAsAction")
self.uiReloadAllAction = QtWidgets.QAction(MainWindow)
icon22 = QtGui.QIcon()
icon22.addPixmap(QtGui.QPixmap(":/icons/reload.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiReloadAllAction.setIcon(icon22)
icon21 = QtGui.QIcon()
icon21.addPixmap(QtGui.QPixmap(":/icons/reload.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiReloadAllAction.setIcon(icon21)
self.uiReloadAllAction.setObjectName("uiReloadAllAction")
self.uiAuxConsoleAllAction = QtWidgets.QAction(MainWindow)
self.uiAuxConsoleAllAction.setEnabled(True)
icon23 = QtGui.QIcon()
icon23.addPixmap(QtGui.QPixmap(":/icons/aux-console.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiAuxConsoleAllAction.setIcon(icon23)
icon22 = QtGui.QIcon()
icon22.addPixmap(QtGui.QPixmap(":/icons/aux-console.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiAuxConsoleAllAction.setIcon(icon22)
self.uiAuxConsoleAllAction.setObjectName("uiAuxConsoleAllAction")
self.uiResetPortLabelsAction = QtWidgets.QAction(MainWindow)
self.uiResetPortLabelsAction.setObjectName("uiResetPortLabelsAction")
@@ -335,43 +343,43 @@ class Ui_MainWindow(object):
self.uiDefaultStyleAction.setChecked(True)
self.uiDefaultStyleAction.setObjectName("uiDefaultStyleAction")
self.uiBrowseRoutersAction = QtWidgets.QAction(MainWindow)
icon24 = QtGui.QIcon()
icon24.addPixmap(QtGui.QPixmap(":/icons/router.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon24.addPixmap(QtGui.QPixmap(":/icons/router-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiBrowseRoutersAction.setIcon(icon24)
icon23 = QtGui.QIcon()
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)
icon25 = QtGui.QIcon()
icon25.addPixmap(QtGui.QPixmap(":/icons/switch.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon25.addPixmap(QtGui.QPixmap(":/icons/switch-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiBrowseSwitchesAction.setIcon(icon25)
icon24 = QtGui.QIcon()
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)
icon26 = QtGui.QIcon()
icon26.addPixmap(QtGui.QPixmap(":/icons/PC.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon26.addPixmap(QtGui.QPixmap(":/icons/PC-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiBrowseEndDevicesAction.setIcon(icon26)
icon25 = QtGui.QIcon()
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)
icon27 = QtGui.QIcon()
icon27.addPixmap(QtGui.QPixmap(":/icons/firewall.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon27.addPixmap(QtGui.QPixmap(":/icons/firewall-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiBrowseSecurityDevicesAction.setIcon(icon27)
icon26 = QtGui.QIcon()
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)
icon28 = QtGui.QIcon()
icon28.addPixmap(QtGui.QPixmap(":/icons/browse-all-icons.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon28.addPixmap(QtGui.QPixmap(":/icons/browse-all-icons-hover.png"), QtGui.QIcon.Active, QtGui.QIcon.Off)
self.uiBrowseAllDevicesAction.setIcon(icon28)
icon27 = QtGui.QIcon()
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)
icon29 = QtGui.QIcon()
icon29.addPixmap(QtGui.QPixmap(":/icons/connection-new.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon29.addPixmap(QtGui.QPixmap(":/icons/cancel-connection.svg"), QtGui.QIcon.Normal, QtGui.QIcon.On)
icon29.addPixmap(QtGui.QPixmap(":/icons/connection-new-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
icon29.addPixmap(QtGui.QPixmap(":/icons/cancel-connection.svg"), QtGui.QIcon.Active, QtGui.QIcon.On)
self.uiAddLinkAction.setIcon(icon29)
icon28 = QtGui.QIcon()
icon28.addPixmap(QtGui.QPixmap(":/icons/connection-new.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
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)
icon28.addPixmap(QtGui.QPixmap(":/icons/cancel-connection.svg"), QtGui.QIcon.Normal, QtGui.QIcon.On)
self.uiAddLinkAction.setIcon(icon28)
self.uiAddLinkAction.setObjectName("uiAddLinkAction")
self.uiGettingStartedAction = QtWidgets.QAction(MainWindow)
self.uiGettingStartedAction.setObjectName("uiGettingStartedAction")
@@ -398,14 +406,14 @@ class Ui_MainWindow(object):
self.uiVPCSAction = QtWidgets.QAction(MainWindow)
self.uiVPCSAction.setObjectName("uiVPCSAction")
self.uiDownloadRemoteProject = QtWidgets.QAction(MainWindow)
icon30 = QtGui.QIcon()
icon30.addPixmap(QtGui.QPixmap(":/classic_icons/save-as-project.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiDownloadRemoteProject.setIcon(icon30)
icon29 = QtGui.QIcon()
icon29.addPixmap(QtGui.QPixmap(":/classic_icons/save-as-project.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiDownloadRemoteProject.setIcon(icon29)
self.uiDownloadRemoteProject.setObjectName("uiDownloadRemoteProject")
self.uiQemuImgWizardAction = QtWidgets.QAction(MainWindow)
icon31 = QtGui.QIcon()
icon31.addPixmap(QtGui.QPixmap(":/icons/qemu.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiQemuImgWizardAction.setIcon(icon31)
icon30 = QtGui.QIcon()
icon30.addPixmap(QtGui.QPixmap(":/icons/qemu.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.uiQemuImgWizardAction.setIcon(icon30)
self.uiQemuImgWizardAction.setObjectName("uiQemuImgWizardAction")
self.uiSetupWizard = QtWidgets.QAction(MainWindow)
self.uiSetupWizard.setMenuRole(QtWidgets.QAction.NoRole)
@@ -417,6 +425,8 @@ class Ui_MainWindow(object):
self.uiOpenApplianceAction.setObjectName("uiOpenApplianceAction")
self.uiExportDebugInformationAction = QtWidgets.QAction(MainWindow)
self.uiExportDebugInformationAction.setObjectName("uiExportDebugInformationAction")
self.uiDoctorAction = QtWidgets.QAction(MainWindow)
self.uiDoctorAction.setObjectName("uiDoctorAction")
self.uiEditMenu.addAction(self.uiSelectAllAction)
self.uiEditMenu.addAction(self.uiSelectNoneAction)
self.uiEditMenu.addSeparator()
@@ -442,6 +452,7 @@ class Ui_MainWindow(object):
self.uiHelpMenu.addAction(self.uiCheckForUpdateAction)
self.uiHelpMenu.addAction(self.uiSetupWizard)
self.uiHelpMenu.addAction(self.uiLabInstructionsAction)
self.uiHelpMenu.addAction(self.uiDoctorAction)
self.uiHelpMenu.addAction(self.uiExportDebugInformationAction)
self.uiHelpMenu.addAction(self.uiAboutQtAction)
self.uiHelpMenu.addAction(self.uiAboutAction)
@@ -536,6 +547,7 @@ class Ui_MainWindow(object):
self.uiAnnotationToolBar.setWindowTitle(_translate("MainWindow", "Drawing"))
self.uiTopologySummaryDockWidget.setWindowTitle(_translate("MainWindow", "Topology Summary"))
self.uiTopologySummaryTreeWidget.headerItem().setText(0, _translate("MainWindow", "1"))
self.uiServerSummaryDockWidget.setWindowTitle(_translate("MainWindow", "Servers Summary"))
self.uiAboutAction.setText(_translate("MainWindow", "&About"))
self.uiAboutAction.setStatusTip(_translate("MainWindow", "About"))
self.uiQuitAction.setText(_translate("MainWindow", "&Quit"))
@@ -561,9 +573,6 @@ class Ui_MainWindow(object):
self.uiStopAllAction.setText(_translate("MainWindow", "Stop all devices"))
self.uiStopAllAction.setToolTip(_translate("MainWindow", "Stop all devices"))
self.uiStopAllAction.setStatusTip(_translate("MainWindow", "Stop all devices"))
self.uiShowNamesAction.setText(_translate("MainWindow", "Show hostnames"))
self.uiShowNamesAction.setToolTip(_translate("MainWindow", "Show hostnames"))
self.uiShowNamesAction.setStatusTip(_translate("MainWindow", "Show hostnames"))
self.uiConsoleAllAction.setText(_translate("MainWindow", "Console connect to all devices"))
self.uiConsoleAllAction.setToolTip(_translate("MainWindow", "Console connect to all devices"))
self.uiConsoleAllAction.setStatusTip(_translate("MainWindow", "Console to all devices"))
@@ -632,7 +641,7 @@ class Ui_MainWindow(object):
self.uiResetPortLabelsAction.setText(_translate("MainWindow", "Reset interface labels"))
self.uiResetPortLabelsAction.setToolTip(_translate("MainWindow", "Reset interface labels"))
self.uiResetPortLabelsAction.setStatusTip(_translate("MainWindow", "Reset Interface Labels"))
self.uiCheckForUpdateAction.setText(_translate("MainWindow", "Check for Update"))
self.uiCheckForUpdateAction.setText(_translate("MainWindow", "Check for &Update"))
self.uiCheckForUpdateAction.setStatusTip(_translate("MainWindow", "Check for Update"))
self.uiEnergySavingStyleAction.setText(_translate("MainWindow", "Energy Saving"))
self.uiEnergySavingStyleAction.setStatusTip(_translate("MainWindow", "Energy Saving Mode"))
@@ -661,7 +670,7 @@ class Ui_MainWindow(object):
self.uiAddLinkAction.setStatusTip(_translate("MainWindow", "Add a link"))
self.uiGettingStartedAction.setText(_translate("MainWindow", "Getting started"))
self.uiGettingStartedAction.setToolTip(_translate("MainWindow", "Show GNS3 news"))
self.uiLabInstructionsAction.setText(_translate("MainWindow", "Lab instructions"))
self.uiLabInstructionsAction.setText(_translate("MainWindow", "&Lab instructions"))
self.uiFitInViewAction.setText(_translate("MainWindow", "Fit in view"))
self.uiExportProjectAction.setText(_translate("MainWindow", "Backup project to cloud"))
self.uiImportProjectAction.setText(_translate("MainWindow", "Restore backup from cloud"))
@@ -677,9 +686,12 @@ class Ui_MainWindow(object):
self.uiIOUVMConverterAction.setText(_translate("MainWindow", "IOU VM Converter"))
self.uiOpenApplianceAction.setText(_translate("MainWindow", "Import appliance"))
self.uiExportDebugInformationAction.setText(_translate("MainWindow", "Export debug information"))
self.uiExportDebugInformationAction.setToolTip(_translate("MainWindow", "&Export debug information"))
self.uiDoctorAction.setText(_translate("MainWindow", "GNS3 &Doctor"))
from ..console_view import ConsoleView
from ..graphics_view import GraphicsView
from ..nodes_view import NodesView
from ..server_summary_view import ServerSummaryView
from ..topology_summary_view import TopologySummaryView
from . import resources_rc

File diff suppressed because it is too large Load Diff

View File

@@ -6,10 +6,16 @@
<rect>
<x>0</x>
<y>0</y>
<width>500</width>
<height>609</height>
<width>529</width>
<height>645</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
@@ -28,10 +34,22 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="currentIndex">
<number>2</number>
</property>
<widget class="QWidget" name="uiLocalTabWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<attribute name="title">
<string>Local server</string>
</attribute>
@@ -207,19 +225,6 @@
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>363</width>
<height>22</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
@@ -262,24 +267,11 @@
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>363</width>
<height>22</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
@@ -295,10 +287,16 @@
<zorder>uiGeneralSettingsGroupBox</zorder>
<zorder>uiConsolePortRangeGroupBox</zorder>
<zorder>uiUDPPortRangeGroupBox</zorder>
<zorder>verticalSpacer</zorder>
<zorder>uiLocalServerAutoStartCheckBox</zorder>
<zorder>verticalSpacer_4</zorder>
</widget>
<widget class="QWidget" name="uiGNS3VMTabWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<attribute name="title">
<string>Local GNS3 VM</string>
</attribute>
@@ -343,6 +341,19 @@
</item>
<item row="1" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QRadioButton" name="uiVmwareRadioButton">
<property name="text">
@@ -360,19 +371,6 @@
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="3" column="0">
@@ -460,14 +458,14 @@
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>320</height>
<height>40</height>
</size>
</property>
</spacer>
@@ -475,102 +473,23 @@
</layout>
</widget>
<widget class="QWidget" name="uiRemoteTabWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<attribute name="title">
<string>Remote servers</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_5">
<item row="5" column="0">
<widget class="QLabel" name="uiRemoteServerUserLabel">
<item row="2" column="0">
<widget class="QLabel" name="uiRemoteServerHostLabel">
<property name="text">
<string>User:</string>
<string>Host:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="uiRemoteServerUserLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="uiRemoteServerSSHPortLabel">
<property name="text">
<string>SSH port:</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="uiRemoteServerSSHKeyLabel">
<property name="text">
<string>SSH key:</string>
</property>
</widget>
</item>
<item row="8" column="1">
<layout class="QHBoxLayout" name="uiRemoteServerSSHKeyHorizontalLayout">
<item>
<widget class="QLineEdit" name="uiRemoteServerSSHKeyLineEdit"/>
</item>
<item>
<widget class="QPushButton" name="uiRemoteServerSSHKeyPushButton">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="9" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="uiAddRemoteServerPushButton">
<property name="text">
<string>&amp;Add</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="uiDeleteRemoteServerPushButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Delete</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>206</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="10" column="0" colspan="2">
<spacer name="spacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>390</width>
<height>12</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" colspan="2">
<widget class="QTreeWidget" name="uiRemoteServersTreeWidget">
<property name="sizePolicy">
@@ -632,18 +551,6 @@
<string>HTTPS</string>
</property>
</item>
<item>
<property name="text">
<string>SSH</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="uiRemoteServerHostLabel">
<property name="text">
<string>Host:</string>
</property>
</widget>
</item>
<item row="2" column="1">
@@ -653,6 +560,16 @@
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="uiRemoteServerUserLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="uiRemoteServerPortLabel">
<property name="text">
@@ -660,6 +577,47 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="uiRemoteServerUserLabel">
<property name="text">
<string>User:</string>
</property>
</widget>
</item>
<item row="7" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="uiAddRemoteServerPushButton">
<property name="text">
<string>&amp;Add</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="uiDeleteRemoteServerPushButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Delete</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="uiRemoteServerPortSpinBox">
<property name="sizePolicy">
@@ -699,22 +657,10 @@
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QSpinBox" name="uiRemoteServerSSHPortSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="suffix">
<string> TCP</string>
</property>
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>22</number>
<item row="6" column="0">
<widget class="QLabel" name="uiRemoteServerPasswordLabel">
<property name="text">
<string>Password:</string>
</property>
</widget>
</item>
@@ -731,12 +677,18 @@
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="uiRemoteServerPasswordLabel">
<property name="text">
<string>Password:</string>
<item row="8" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
<zorder>uiRemoteServerProtocolComboBox</zorder>
@@ -748,16 +700,19 @@
<zorder>uiRAMLimitSpinBox</zorder>
<zorder>uiRemoteServerUserLabel</zorder>
<zorder>uiRemoteServerUserLineEdit</zorder>
<zorder>uiRemoteServerSSHPortLabel</zorder>
<zorder>uiRemoteServerSSHPortSpinBox</zorder>
<zorder>uiRemoteServerSSHKeyLabel</zorder>
<zorder>spacer_2</zorder>
<zorder>uiRemoteServersTreeWidget</zorder>
<zorder>uiRemoteServerProtocolLabel</zorder>
<zorder>uiRemoteServerPasswordLineEdit</zorder>
<zorder>uiRemoteServerPasswordLabel</zorder>
<zorder>verticalSpacer_3</zorder>
</widget>
<widget class="QWidget" name="uiLoadBalancingTabWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<attribute name="title">
<string>Load Balancing</string>
</attribute>
@@ -799,14 +754,14 @@
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>382</height>
<height>40</height>
</size>
</property>
</spacer>
@@ -824,7 +779,7 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>164</width>
<width>40</width>
<height>20</height>
</size>
</property>
@@ -872,9 +827,6 @@
<tabstop>uiRemoteServerPortSpinBox</tabstop>
<tabstop>uiRemoteServerUserLineEdit</tabstop>
<tabstop>uiRemoteServerPasswordLineEdit</tabstop>
<tabstop>uiRemoteServerSSHPortSpinBox</tabstop>
<tabstop>uiRemoteServerSSHKeyLineEdit</tabstop>
<tabstop>uiRemoteServerSSHKeyPushButton</tabstop>
<tabstop>uiAddRemoteServerPushButton</tabstop>
<tabstop>uiDeleteRemoteServerPushButton</tabstop>
<tabstop>uiRAMLimitSpinBox</tabstop>

View File

@@ -11,7 +11,12 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_ServerPreferencesPageWidget(object):
def setupUi(self, ServerPreferencesPageWidget):
ServerPreferencesPageWidget.setObjectName("ServerPreferencesPageWidget")
ServerPreferencesPageWidget.resize(500, 609)
ServerPreferencesPageWidget.resize(529, 645)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(ServerPreferencesPageWidget.sizePolicy().hasHeightForWidth())
ServerPreferencesPageWidget.setSizePolicy(sizePolicy)
ServerPreferencesPageWidget.setMinimumSize(QtCore.QSize(0, 0))
self.verticalLayout_2 = QtWidgets.QVBoxLayout(ServerPreferencesPageWidget)
self.verticalLayout_2.setObjectName("verticalLayout_2")
@@ -21,8 +26,14 @@ class Ui_ServerPreferencesPageWidget(object):
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.uiServerPreferenceTabWidget.sizePolicy().hasHeightForWidth())
self.uiServerPreferenceTabWidget.setSizePolicy(sizePolicy)
self.uiServerPreferenceTabWidget.setMaximumSize(QtCore.QSize(16777215, 16777215))
self.uiServerPreferenceTabWidget.setObjectName("uiServerPreferenceTabWidget")
self.uiLocalTabWidget = QtWidgets.QWidget()
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.uiLocalTabWidget.sizePolicy().hasHeightForWidth())
self.uiLocalTabWidget.setSizePolicy(sizePolicy)
self.uiLocalTabWidget.setObjectName("uiLocalTabWidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.uiLocalTabWidget)
self.verticalLayout.setObjectName("verticalLayout")
@@ -113,8 +124,6 @@ class Ui_ServerPreferencesPageWidget(object):
self.uiConsoleEndPortSpinBox.setProperty("value", 5000)
self.uiConsoleEndPortSpinBox.setObjectName("uiConsoleEndPortSpinBox")
self.horizontalLayout_7.addWidget(self.uiConsoleEndPortSpinBox)
spacerItem = QtWidgets.QSpacerItem(363, 22, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_7.addItem(spacerItem)
self.verticalLayout.addWidget(self.uiConsolePortRangeGroupBox)
self.uiUDPPortRangeGroupBox = QtWidgets.QGroupBox(self.uiLocalTabWidget)
self.uiUDPPortRangeGroupBox.setObjectName("uiUDPPortRangeGroupBox")
@@ -135,17 +144,20 @@ class Ui_ServerPreferencesPageWidget(object):
self.uiUDPEndPortSpinBox.setProperty("value", 20000)
self.uiUDPEndPortSpinBox.setObjectName("uiUDPEndPortSpinBox")
self.horizontalLayout_8.addWidget(self.uiUDPEndPortSpinBox)
spacerItem1 = QtWidgets.QSpacerItem(363, 22, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_8.addItem(spacerItem1)
self.verticalLayout.addWidget(self.uiUDPPortRangeGroupBox)
spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem2)
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.uiGeneralSettingsGroupBox.raise_()
self.uiConsolePortRangeGroupBox.raise_()
self.uiUDPPortRangeGroupBox.raise_()
self.uiLocalServerAutoStartCheckBox.raise_()
self.uiServerPreferenceTabWidget.addTab(self.uiLocalTabWidget, "")
self.uiGNS3VMTabWidget = QtWidgets.QWidget()
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.uiGNS3VMTabWidget.sizePolicy().hasHeightForWidth())
self.uiGNS3VMTabWidget.setSizePolicy(sizePolicy)
self.uiGNS3VMTabWidget.setObjectName("uiGNS3VMTabWidget")
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.uiGNS3VMTabWidget)
self.verticalLayout_3.setObjectName("verticalLayout_3")
@@ -169,6 +181,8 @@ class Ui_ServerPreferencesPageWidget(object):
self.gridLayout_2.addWidget(self.uiVirtualizationSoftwarLabel, 0, 0, 1, 1)
self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_4.addItem(spacerItem1)
self.uiVmwareRadioButton = QtWidgets.QRadioButton(self.uiGNS3VMSettingsGroupBox)
self.uiVmwareRadioButton.setChecked(True)
self.uiVmwareRadioButton.setObjectName("uiVmwareRadioButton")
@@ -176,8 +190,6 @@ class Ui_ServerPreferencesPageWidget(object):
self.uiVirtualBoxRadioButton = QtWidgets.QRadioButton(self.uiGNS3VMSettingsGroupBox)
self.uiVirtualBoxRadioButton.setObjectName("uiVirtualBoxRadioButton")
self.horizontalLayout_4.addWidget(self.uiVirtualBoxRadioButton)
spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_4.addItem(spacerItem3)
self.gridLayout_2.addLayout(self.horizontalLayout_4, 1, 0, 1, 2)
self.uiVMNameLabel = QtWidgets.QLabel(self.uiGNS3VMSettingsGroupBox)
self.uiVMNameLabel.setObjectName("uiVMNameLabel")
@@ -222,53 +234,21 @@ class Ui_ServerPreferencesPageWidget(object):
self.uiVMPasswordLineEdit.setObjectName("uiVMPasswordLineEdit")
self.gridLayout_3.addWidget(self.uiVMPasswordLineEdit, 1, 1, 1, 1)
self.verticalLayout_3.addWidget(self.groupBox)
spacerItem4 = QtWidgets.QSpacerItem(20, 320, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout_3.addItem(spacerItem4)
spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout_3.addItem(spacerItem2)
self.uiServerPreferenceTabWidget.addTab(self.uiGNS3VMTabWidget, "")
self.uiRemoteTabWidget = QtWidgets.QWidget()
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.uiRemoteTabWidget.sizePolicy().hasHeightForWidth())
self.uiRemoteTabWidget.setSizePolicy(sizePolicy)
self.uiRemoteTabWidget.setObjectName("uiRemoteTabWidget")
self.gridLayout_5 = QtWidgets.QGridLayout(self.uiRemoteTabWidget)
self.gridLayout_5.setObjectName("gridLayout_5")
self.uiRemoteServerUserLabel = QtWidgets.QLabel(self.uiRemoteTabWidget)
self.uiRemoteServerUserLabel.setObjectName("uiRemoteServerUserLabel")
self.gridLayout_5.addWidget(self.uiRemoteServerUserLabel, 5, 0, 1, 1)
self.uiRemoteServerUserLineEdit = QtWidgets.QLineEdit(self.uiRemoteTabWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.uiRemoteServerUserLineEdit.sizePolicy().hasHeightForWidth())
self.uiRemoteServerUserLineEdit.setSizePolicy(sizePolicy)
self.uiRemoteServerUserLineEdit.setObjectName("uiRemoteServerUserLineEdit")
self.gridLayout_5.addWidget(self.uiRemoteServerUserLineEdit, 5, 1, 1, 1)
self.uiRemoteServerSSHPortLabel = QtWidgets.QLabel(self.uiRemoteTabWidget)
self.uiRemoteServerSSHPortLabel.setObjectName("uiRemoteServerSSHPortLabel")
self.gridLayout_5.addWidget(self.uiRemoteServerSSHPortLabel, 7, 0, 1, 1)
self.uiRemoteServerSSHKeyLabel = QtWidgets.QLabel(self.uiRemoteTabWidget)
self.uiRemoteServerSSHKeyLabel.setObjectName("uiRemoteServerSSHKeyLabel")
self.gridLayout_5.addWidget(self.uiRemoteServerSSHKeyLabel, 8, 0, 1, 1)
self.uiRemoteServerSSHKeyHorizontalLayout = QtWidgets.QHBoxLayout()
self.uiRemoteServerSSHKeyHorizontalLayout.setObjectName("uiRemoteServerSSHKeyHorizontalLayout")
self.uiRemoteServerSSHKeyLineEdit = QtWidgets.QLineEdit(self.uiRemoteTabWidget)
self.uiRemoteServerSSHKeyLineEdit.setObjectName("uiRemoteServerSSHKeyLineEdit")
self.uiRemoteServerSSHKeyHorizontalLayout.addWidget(self.uiRemoteServerSSHKeyLineEdit)
self.uiRemoteServerSSHKeyPushButton = QtWidgets.QPushButton(self.uiRemoteTabWidget)
self.uiRemoteServerSSHKeyPushButton.setObjectName("uiRemoteServerSSHKeyPushButton")
self.uiRemoteServerSSHKeyHorizontalLayout.addWidget(self.uiRemoteServerSSHKeyPushButton)
self.gridLayout_5.addLayout(self.uiRemoteServerSSHKeyHorizontalLayout, 8, 1, 1, 1)
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
self.uiAddRemoteServerPushButton = QtWidgets.QPushButton(self.uiRemoteTabWidget)
self.uiAddRemoteServerPushButton.setObjectName("uiAddRemoteServerPushButton")
self.horizontalLayout_3.addWidget(self.uiAddRemoteServerPushButton)
self.uiDeleteRemoteServerPushButton = QtWidgets.QPushButton(self.uiRemoteTabWidget)
self.uiDeleteRemoteServerPushButton.setEnabled(False)
self.uiDeleteRemoteServerPushButton.setObjectName("uiDeleteRemoteServerPushButton")
self.horizontalLayout_3.addWidget(self.uiDeleteRemoteServerPushButton)
spacerItem5 = QtWidgets.QSpacerItem(206, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_3.addItem(spacerItem5)
self.gridLayout_5.addLayout(self.horizontalLayout_3, 9, 0, 1, 2)
spacerItem6 = QtWidgets.QSpacerItem(390, 12, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout_5.addItem(spacerItem6, 10, 0, 1, 2)
self.uiRemoteServerHostLabel = QtWidgets.QLabel(self.uiRemoteTabWidget)
self.uiRemoteServerHostLabel.setObjectName("uiRemoteServerHostLabel")
self.gridLayout_5.addWidget(self.uiRemoteServerHostLabel, 2, 0, 1, 1)
self.uiRemoteServersTreeWidget = QtWidgets.QTreeWidget(self.uiRemoteTabWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
@@ -293,17 +273,36 @@ class Ui_ServerPreferencesPageWidget(object):
self.uiRemoteServerProtocolComboBox.setObjectName("uiRemoteServerProtocolComboBox")
self.uiRemoteServerProtocolComboBox.addItem("")
self.uiRemoteServerProtocolComboBox.addItem("")
self.uiRemoteServerProtocolComboBox.addItem("")
self.gridLayout_5.addWidget(self.uiRemoteServerProtocolComboBox, 1, 1, 1, 1)
self.uiRemoteServerHostLabel = QtWidgets.QLabel(self.uiRemoteTabWidget)
self.uiRemoteServerHostLabel.setObjectName("uiRemoteServerHostLabel")
self.gridLayout_5.addWidget(self.uiRemoteServerHostLabel, 2, 0, 1, 1)
self.uiRemoteServerPortLineEdit = QtWidgets.QLineEdit(self.uiRemoteTabWidget)
self.uiRemoteServerPortLineEdit.setObjectName("uiRemoteServerPortLineEdit")
self.gridLayout_5.addWidget(self.uiRemoteServerPortLineEdit, 2, 1, 1, 1)
self.uiRemoteServerUserLineEdit = QtWidgets.QLineEdit(self.uiRemoteTabWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.uiRemoteServerUserLineEdit.sizePolicy().hasHeightForWidth())
self.uiRemoteServerUserLineEdit.setSizePolicy(sizePolicy)
self.uiRemoteServerUserLineEdit.setObjectName("uiRemoteServerUserLineEdit")
self.gridLayout_5.addWidget(self.uiRemoteServerUserLineEdit, 5, 1, 1, 1)
self.uiRemoteServerPortLabel = QtWidgets.QLabel(self.uiRemoteTabWidget)
self.uiRemoteServerPortLabel.setObjectName("uiRemoteServerPortLabel")
self.gridLayout_5.addWidget(self.uiRemoteServerPortLabel, 3, 0, 1, 1)
self.uiRemoteServerUserLabel = QtWidgets.QLabel(self.uiRemoteTabWidget)
self.uiRemoteServerUserLabel.setObjectName("uiRemoteServerUserLabel")
self.gridLayout_5.addWidget(self.uiRemoteServerUserLabel, 5, 0, 1, 1)
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
self.uiAddRemoteServerPushButton = QtWidgets.QPushButton(self.uiRemoteTabWidget)
self.uiAddRemoteServerPushButton.setObjectName("uiAddRemoteServerPushButton")
self.horizontalLayout_3.addWidget(self.uiAddRemoteServerPushButton)
self.uiDeleteRemoteServerPushButton = QtWidgets.QPushButton(self.uiRemoteTabWidget)
self.uiDeleteRemoteServerPushButton.setEnabled(False)
self.uiDeleteRemoteServerPushButton.setObjectName("uiDeleteRemoteServerPushButton")
self.horizontalLayout_3.addWidget(self.uiDeleteRemoteServerPushButton)
spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_3.addItem(spacerItem3)
self.gridLayout_5.addLayout(self.horizontalLayout_3, 7, 0, 1, 2)
self.uiRemoteServerPortSpinBox = QtWidgets.QSpinBox(self.uiRemoteTabWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
@@ -323,25 +322,17 @@ class Ui_ServerPreferencesPageWidget(object):
self.uiRAMLimitSpinBox.setSingleStep(512)
self.uiRAMLimitSpinBox.setObjectName("uiRAMLimitSpinBox")
self.gridLayout_5.addWidget(self.uiRAMLimitSpinBox, 4, 1, 1, 1)
self.uiRemoteServerSSHPortSpinBox = QtWidgets.QSpinBox(self.uiRemoteTabWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.uiRemoteServerSSHPortSpinBox.sizePolicy().hasHeightForWidth())
self.uiRemoteServerSSHPortSpinBox.setSizePolicy(sizePolicy)
self.uiRemoteServerSSHPortSpinBox.setMaximum(65535)
self.uiRemoteServerSSHPortSpinBox.setProperty("value", 22)
self.uiRemoteServerSSHPortSpinBox.setObjectName("uiRemoteServerSSHPortSpinBox")
self.gridLayout_5.addWidget(self.uiRemoteServerSSHPortSpinBox, 7, 1, 1, 1)
self.uiRemoteServerPasswordLabel = QtWidgets.QLabel(self.uiRemoteTabWidget)
self.uiRemoteServerPasswordLabel.setObjectName("uiRemoteServerPasswordLabel")
self.gridLayout_5.addWidget(self.uiRemoteServerPasswordLabel, 6, 0, 1, 1)
self.uiRemoteServerPasswordLineEdit = QtWidgets.QLineEdit(self.uiRemoteTabWidget)
self.uiRemoteServerPasswordLineEdit.setInputMethodHints(QtCore.Qt.ImhHiddenText|QtCore.Qt.ImhNoAutoUppercase|QtCore.Qt.ImhNoPredictiveText|QtCore.Qt.ImhSensitiveData)
self.uiRemoteServerPasswordLineEdit.setText("")
self.uiRemoteServerPasswordLineEdit.setEchoMode(QtWidgets.QLineEdit.Password)
self.uiRemoteServerPasswordLineEdit.setObjectName("uiRemoteServerPasswordLineEdit")
self.gridLayout_5.addWidget(self.uiRemoteServerPasswordLineEdit, 6, 1, 1, 1)
self.uiRemoteServerPasswordLabel = QtWidgets.QLabel(self.uiRemoteTabWidget)
self.uiRemoteServerPasswordLabel.setObjectName("uiRemoteServerPasswordLabel")
self.gridLayout_5.addWidget(self.uiRemoteServerPasswordLabel, 6, 0, 1, 1)
spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout_5.addItem(spacerItem4, 8, 0, 1, 1)
self.uiRemoteServerProtocolComboBox.raise_()
self.uiRemoteServerHostLabel.raise_()
self.uiRemoteServerPortLineEdit.raise_()
@@ -351,15 +342,17 @@ class Ui_ServerPreferencesPageWidget(object):
self.uiRAMLimitSpinBox.raise_()
self.uiRemoteServerUserLabel.raise_()
self.uiRemoteServerUserLineEdit.raise_()
self.uiRemoteServerSSHPortLabel.raise_()
self.uiRemoteServerSSHPortSpinBox.raise_()
self.uiRemoteServerSSHKeyLabel.raise_()
self.uiRemoteServersTreeWidget.raise_()
self.uiRemoteServerProtocolLabel.raise_()
self.uiRemoteServerPasswordLineEdit.raise_()
self.uiRemoteServerPasswordLabel.raise_()
self.uiServerPreferenceTabWidget.addTab(self.uiRemoteTabWidget, "")
self.uiLoadBalancingTabWidget = QtWidgets.QWidget()
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.uiLoadBalancingTabWidget.sizePolicy().hasHeightForWidth())
self.uiLoadBalancingTabWidget.setSizePolicy(sizePolicy)
self.uiLoadBalancingTabWidget.setObjectName("uiLoadBalancingTabWidget")
self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.uiLoadBalancingTabWidget)
self.verticalLayout_4.setObjectName("verticalLayout_4")
@@ -379,14 +372,14 @@ class Ui_ServerPreferencesPageWidget(object):
self.uiRendezVousHashingRadioButton.setObjectName("uiRendezVousHashingRadioButton")
self.gridLayout_4.addWidget(self.uiRendezVousHashingRadioButton, 2, 0, 1, 1)
self.verticalLayout_4.addWidget(self.uiMethodGroupBox)
spacerItem7 = QtWidgets.QSpacerItem(20, 382, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout_4.addItem(spacerItem7)
spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout_4.addItem(spacerItem5)
self.uiServerPreferenceTabWidget.addTab(self.uiLoadBalancingTabWidget, "")
self.verticalLayout_2.addWidget(self.uiServerPreferenceTabWidget)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
spacerItem8 = QtWidgets.QSpacerItem(164, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_2.addItem(spacerItem8)
spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_2.addItem(spacerItem6)
self.uiRestoreDefaultsPushButton = QtWidgets.QPushButton(ServerPreferencesPageWidget)
self.uiRestoreDefaultsPushButton.setObjectName("uiRestoreDefaultsPushButton")
self.horizontalLayout_2.addWidget(self.uiRestoreDefaultsPushButton)
@@ -424,10 +417,7 @@ class Ui_ServerPreferencesPageWidget(object):
ServerPreferencesPageWidget.setTabOrder(self.uiRemoteServerPortLineEdit, self.uiRemoteServerPortSpinBox)
ServerPreferencesPageWidget.setTabOrder(self.uiRemoteServerPortSpinBox, self.uiRemoteServerUserLineEdit)
ServerPreferencesPageWidget.setTabOrder(self.uiRemoteServerUserLineEdit, self.uiRemoteServerPasswordLineEdit)
ServerPreferencesPageWidget.setTabOrder(self.uiRemoteServerPasswordLineEdit, self.uiRemoteServerSSHPortSpinBox)
ServerPreferencesPageWidget.setTabOrder(self.uiRemoteServerSSHPortSpinBox, self.uiRemoteServerSSHKeyLineEdit)
ServerPreferencesPageWidget.setTabOrder(self.uiRemoteServerSSHKeyLineEdit, self.uiRemoteServerSSHKeyPushButton)
ServerPreferencesPageWidget.setTabOrder(self.uiRemoteServerSSHKeyPushButton, self.uiAddRemoteServerPushButton)
ServerPreferencesPageWidget.setTabOrder(self.uiRemoteServerPasswordLineEdit, self.uiAddRemoteServerPushButton)
ServerPreferencesPageWidget.setTabOrder(self.uiAddRemoteServerPushButton, self.uiDeleteRemoteServerPushButton)
ServerPreferencesPageWidget.setTabOrder(self.uiDeleteRemoteServerPushButton, self.uiRAMLimitSpinBox)
ServerPreferencesPageWidget.setTabOrder(self.uiRAMLimitSpinBox, self.uiRAMUsageRadioButton)
@@ -466,24 +456,19 @@ class Ui_ServerPreferencesPageWidget(object):
self.uiVMUserLabel.setText(_translate("ServerPreferencesPageWidget", "User:"))
self.uiVMPasswordLabel.setText(_translate("ServerPreferencesPageWidget", "Password:"))
self.uiServerPreferenceTabWidget.setTabText(self.uiServerPreferenceTabWidget.indexOf(self.uiGNS3VMTabWidget), _translate("ServerPreferencesPageWidget", "Local GNS3 VM"))
self.uiRemoteServerUserLabel.setText(_translate("ServerPreferencesPageWidget", "User:"))
self.uiRemoteServerSSHPortLabel.setText(_translate("ServerPreferencesPageWidget", "SSH port:"))
self.uiRemoteServerSSHKeyLabel.setText(_translate("ServerPreferencesPageWidget", "SSH key:"))
self.uiRemoteServerSSHKeyPushButton.setText(_translate("ServerPreferencesPageWidget", "Browse"))
self.uiAddRemoteServerPushButton.setText(_translate("ServerPreferencesPageWidget", "&Add"))
self.uiDeleteRemoteServerPushButton.setText(_translate("ServerPreferencesPageWidget", "&Delete"))
self.uiRemoteServerHostLabel.setText(_translate("ServerPreferencesPageWidget", "Host:"))
self.uiRemoteServersTreeWidget.headerItem().setText(3, _translate("ServerPreferencesPageWidget", "User"))
self.uiRemoteServerProtocolLabel.setText(_translate("ServerPreferencesPageWidget", "Protocol:"))
self.uiRemoteServerProtocolComboBox.setCurrentText(_translate("ServerPreferencesPageWidget", "HTTP"))
self.uiRemoteServerProtocolComboBox.setItemText(0, _translate("ServerPreferencesPageWidget", "HTTP"))
self.uiRemoteServerProtocolComboBox.setItemText(1, _translate("ServerPreferencesPageWidget", "HTTPS"))
self.uiRemoteServerProtocolComboBox.setItemText(2, _translate("ServerPreferencesPageWidget", "SSH"))
self.uiRemoteServerHostLabel.setText(_translate("ServerPreferencesPageWidget", "Host:"))
self.uiRemoteServerPortLineEdit.setText(_translate("ServerPreferencesPageWidget", "192.168.56.101"))
self.uiRemoteServerPortLabel.setText(_translate("ServerPreferencesPageWidget", "Port:"))
self.uiRemoteServerUserLabel.setText(_translate("ServerPreferencesPageWidget", "User:"))
self.uiAddRemoteServerPushButton.setText(_translate("ServerPreferencesPageWidget", "&Add"))
self.uiDeleteRemoteServerPushButton.setText(_translate("ServerPreferencesPageWidget", "&Delete"))
self.uiRAMLimitLabel.setText(_translate("ServerPreferencesPageWidget", "RAM limit:"))
self.uiRAMLimitSpinBox.setSuffix(_translate("ServerPreferencesPageWidget", " MB"))
self.uiRemoteServerSSHPortSpinBox.setSuffix(_translate("ServerPreferencesPageWidget", " TCP"))
self.uiRemoteServerPasswordLabel.setText(_translate("ServerPreferencesPageWidget", "Password:"))
self.uiServerPreferenceTabWidget.setTabText(self.uiServerPreferenceTabWidget.indexOf(self.uiRemoteTabWidget), _translate("ServerPreferencesPageWidget", "Remote servers"))
self.uiMethodGroupBox.setTitle(_translate("ServerPreferencesPageWidget", "Method"))

View File

@@ -37,14 +37,14 @@
</property>
</widget>
</item>
<item row="1" column="0">
<item row="2" column="0">
<widget class="QLabel" name="uiRotationLabel">
<property name="text">
<string>Rotation:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="QSpinBox" name="uiRotationSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@@ -70,6 +70,20 @@ editing (notes only) with ALT and '+' (or P) / ALT and '-' (or M)</string>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="uiApplyColorToAllItemsCheckBox">
<property name="text">
<string>Apply the color to all selected items</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="uiApplyRotationToAllItemsCheckBox">
<property name="text">
<string>Apply the rotation to all selected items</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="uiApplyTextToAllItemsCheckBox">
<property name="text">

View File

@@ -2,15 +2,13 @@
# Form implementation generated from reading ui file '/Users/noplay/code/gns3/gns3-gui/gns3/ui/text_editor_dialog.ui'
#
# Created by: PyQt5 UI code generator 5.4.2
# Created by: PyQt5 UI code generator 5.5.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_TextEditorDialog(object):
def setupUi(self, TextEditorDialog):
TextEditorDialog.setObjectName("TextEditorDialog")
TextEditorDialog.resize(457, 333)
@@ -30,7 +28,7 @@ class Ui_TextEditorDialog(object):
self.gridLayout.addWidget(self.uiColorPushButton, 0, 1, 1, 1)
self.uiRotationLabel = QtWidgets.QLabel(self.uiTextSettingsGroupBox)
self.uiRotationLabel.setObjectName("uiRotationLabel")
self.gridLayout.addWidget(self.uiRotationLabel, 1, 0, 1, 1)
self.gridLayout.addWidget(self.uiRotationLabel, 2, 0, 1, 1)
self.uiRotationSpinBox = QtWidgets.QSpinBox(self.uiTextSettingsGroupBox)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
@@ -40,8 +38,14 @@ class Ui_TextEditorDialog(object):
self.uiRotationSpinBox.setMinimum(-360)
self.uiRotationSpinBox.setMaximum(360)
self.uiRotationSpinBox.setObjectName("uiRotationSpinBox")
self.gridLayout.addWidget(self.uiRotationSpinBox, 1, 1, 1, 1)
self.gridLayout.addWidget(self.uiRotationSpinBox, 2, 1, 1, 1)
self.verticalLayout.addWidget(self.uiTextSettingsGroupBox)
self.uiApplyColorToAllItemsCheckBox = QtWidgets.QCheckBox(TextEditorDialog)
self.uiApplyColorToAllItemsCheckBox.setObjectName("uiApplyColorToAllItemsCheckBox")
self.verticalLayout.addWidget(self.uiApplyColorToAllItemsCheckBox)
self.uiApplyRotationToAllItemsCheckBox = QtWidgets.QCheckBox(TextEditorDialog)
self.uiApplyRotationToAllItemsCheckBox.setObjectName("uiApplyRotationToAllItemsCheckBox")
self.verticalLayout.addWidget(self.uiApplyRotationToAllItemsCheckBox)
self.uiApplyTextToAllItemsCheckBox = QtWidgets.QCheckBox(TextEditorDialog)
self.uiApplyTextToAllItemsCheckBox.setObjectName("uiApplyTextToAllItemsCheckBox")
self.verticalLayout.addWidget(self.uiApplyTextToAllItemsCheckBox)
@@ -57,7 +61,7 @@ class Ui_TextEditorDialog(object):
self.horizontalLayout.addItem(spacerItem)
self.uiButtonBox = QtWidgets.QDialogButtonBox(TextEditorDialog)
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.horizontalLayout.addWidget(self.uiButtonBox)
self.verticalLayout.addLayout(self.horizontalLayout)
@@ -76,8 +80,10 @@ class Ui_TextEditorDialog(object):
self.uiColorLabel.setText(_translate("TextEditorDialog", "Color:"))
self.uiRotationLabel.setText(_translate("TextEditorDialog", "Rotation:"))
self.uiRotationSpinBox.setToolTip(_translate("TextEditorDialog", "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("TextEditorDialog", "°"))
self.uiApplyColorToAllItemsCheckBox.setText(_translate("TextEditorDialog", "Apply the color to all selected items"))
self.uiApplyRotationToAllItemsCheckBox.setText(_translate("TextEditorDialog", "Apply the rotation to all selected items"))
self.uiApplyTextToAllItemsCheckBox.setText(_translate("TextEditorDialog", "Apply the text below to all selected items"))
self.uiFontPushButton.setText(_translate("TextEditorDialog", "&Select font"))

View File

@@ -20,6 +20,7 @@ Functions to start VNC console programs.
"""
import sys
import os
import shlex
import subprocess
from .main_window import MainWindow
@@ -52,7 +53,7 @@ def vncConsole(host, port):
else:
# use arguments on other platforms
args = shlex.split(command)
subprocess.Popen(args)
subprocess.Popen(args, env=os.environ)
except (OSError, ValueError, subprocess.SubprocessError) as e:
log.warning('could not start VNC program "{}": {}'.format(command, e))
raise

View File

@@ -1,5 +1,4 @@
jsonschema>=2.4.0
paramiko>=1.15.1
raven>=5.2.0
psutil>=2.2.1
gns3-converter>=1.2.4

View File

@@ -0,0 +1,286 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="32"
id="svg9493"
inkscape:export-filename="/datas/Projs/Cliparts Stocker/led/led_circle_red.png"
inkscape:export-xdpi="90.000000"
inkscape:export-ydpi="90.000000"
inkscape:version="0.91 r13725"
sodipodi:docname="led_gray.svg"
sodipodi:version="0.32"
width="32"
version="1.0">
<metadata
id="metadata3">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:title></dc:title>
<dc:description>jean.victor.balin@gmail.com</dc:description>
<dc:subject>
<rdf:Bag>
<rdf:li>led</rdf:li>
<rdf:li>shape</rdf:li>
</rdf:Bag>
</dc:subject>
<dc:publisher>
<cc:Agent
rdf:about="http://www.openclipart.org/">
<dc:title>Open Clip Art Library</dc:title>
</cc:Agent>
</dc:publisher>
<dc:creator>
<cc:Agent>
<dc:title>Jean-Victor Balin</dc:title>
</cc:Agent>
</dc:creator>
<dc:rights>
<cc:Agent>
<dc:title>Jean-Victor Balin</dc:title>
</cc:Agent>
</dc:rights>
<dc:date>2005-08-21</dc:date>
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<cc:license
rdf:resource="http://web.resource.org/cc/PublicDomain" />
<dc:language>en</dc:language>
</cc:Work>
<cc:License
rdf:about="http://web.resource.org/cc/PublicDomain">
<cc:permits
rdf:resource="http://web.resource.org/cc/Reproduction" />
<cc:permits
rdf:resource="http://web.resource.org/cc/Distribution" />
<cc:permits
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
</cc:License>
</rdf:RDF>
</metadata>
<defs
id="defs9495">
<linearGradient
gradientUnits="userSpaceOnUse"
id="linearGradient6650"
inkscape:collect="always"
x1="23.402565"
x2="23.389874"
xlink:href="#linearGradient6506"
y1="44.066776"
y2="42.883698"
gradientTransform="matrix(0.494844,0,0,0.38268,9.310292,26.12426)" />
<linearGradient
id="linearGradient6494">
<stop
id="stop6496"
offset="0.0000000"
style="stop-color:red;stop-opacity:1.0000000" />
<stop
id="stop6498"
offset="1.0000000"
style="stop-color:#ff8ba4;stop-opacity:1.0000000;" />
</linearGradient>
<linearGradient
gradientUnits="userSpaceOnUse"
id="linearGradient6648"
inkscape:collect="always"
x1="23.194286"
x2="23.20129"
xlink:href="#linearGradient5756"
y1="42.794029"
y2="43.892632"
gradientTransform="matrix(0.620206,0,0,0.620204,6.388612,15.9637)" />
<linearGradient
gradientUnits="userSpaceOnUse"
id="linearGradient6646"
inkscape:collect="always"
x1="23.349695"
x2="23.44058"
xlink:href="#linearGradient5756"
y1="42.767944"
y2="43.710873"
gradientTransform="matrix(0.692782,0,0,0.692782,4.696832,12.82138)" />
<linearGradient
gradientUnits="userSpaceOnUse"
id="linearGradient6644"
inkscape:collect="always"
x1="23.193102"
x2="23.200001"
xlink:href="#linearGradient5742"
y1="42.42923"
y2="44"
gradientTransform="matrix(0.64,0,0,0.64,5.997572,15.16826)" />
<linearGradient
id="linearGradient6506">
<stop
id="stop6508"
offset="0.0000000"
style="stop-color:#ffffff;stop-opacity:0.0000000;" />
<stop
id="stop6510"
offset="1.0000000"
style="stop-color:#ffffff;stop-opacity:0.87450981;" />
</linearGradient>
<linearGradient
gradientUnits="userSpaceOnUse"
id="linearGradient7498"
inkscape:collect="always"
x1="23.402565"
x2="23.389874"
xlink:href="#linearGradient6506"
y1="44.066776"
y2="42.883698" />
<linearGradient
id="linearGradient7464">
<stop
id="stop7466"
offset="0.0000000"
style="stop-color:#00039a;stop-opacity:1.0000000;" />
<stop
id="stop7468"
offset="1.0000000"
style="stop-color:#afa5ff;stop-opacity:1.0000000;" />
</linearGradient>
<linearGradient
gradientUnits="userSpaceOnUse"
id="linearGradient7496"
inkscape:collect="always"
x1="23.21398"
x2="23.20129"
xlink:href="#linearGradient7464"
y1="42.754631"
y2="43.892632" />
<linearGradient
id="linearGradient5756">
<stop
id="stop5758"
offset="0.0000000"
style="stop-color:#828282;stop-opacity:1.0000000;" />
<stop
id="stop5760"
offset="1.0000000"
style="stop-color:#929292;stop-opacity:0.35294119;" />
</linearGradient>
<linearGradient
gradientUnits="userSpaceOnUse"
id="linearGradient9321"
inkscape:collect="always"
x1="22.93503"
x2="23.662106"
xlink:href="#linearGradient5756"
y1="42.699776"
y2="43.892632" />
<linearGradient
id="linearGradient5742">
<stop
id="stop5744"
offset="0.0000000"
style="stop-color:#adadad;stop-opacity:1.0000000;" />
<stop
id="stop5746"
offset="1.0000000"
style="stop-color:#f0f0f0;stop-opacity:1.0000000;" />
</linearGradient>
<linearGradient
gradientUnits="userSpaceOnUse"
id="linearGradient7492"
inkscape:collect="always"
x1="23.193102"
x2="23.200001"
xlink:href="#linearGradient5742"
y1="42.42923"
y2="44" />
<linearGradient
gradientUnits="userSpaceOnUse"
id="linearGradient9527"
inkscape:collect="always"
x1="23.193102"
x2="23.200001"
xlink:href="#linearGradient5742"
y1="42.42923"
y2="44" />
<linearGradient
gradientUnits="userSpaceOnUse"
id="linearGradient9529"
inkscape:collect="always"
x1="22.93503"
x2="23.662106"
xlink:href="#linearGradient5756"
y1="42.699776"
y2="43.892632" />
<linearGradient
gradientUnits="userSpaceOnUse"
id="linearGradient9531"
inkscape:collect="always"
x1="23.21398"
x2="23.20129"
xlink:href="#linearGradient7464"
y1="42.754631"
y2="43.892632" />
<linearGradient
gradientUnits="userSpaceOnUse"
id="linearGradient9533"
inkscape:collect="always"
x1="23.402565"
x2="23.389874"
xlink:href="#linearGradient6506"
y1="44.066776"
y2="42.883698" />
</defs>
<sodipodi:namedview
bordercolor="#666666"
borderopacity="1.0"
id="base"
inkscape:current-layer="g9447"
inkscape:cx="8.9694656"
inkscape:cy="13.454198"
inkscape:document-units="px"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:window-height="970"
inkscape:window-width="1390"
inkscape:window-x="1372"
inkscape:window-y="0"
inkscape:zoom="10.48"
pagecolor="#ffffff"
showgrid="false"
inkscape:window-maximized="0" />
<g
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Calque 1"
transform="translate(-10.4008,2.992344)">
<g
id="g9447"
style="overflow:visible"
transform="matrix(31.25,0,0,31.25,-625.0232,-1325)">
<path
d="M 21.357568,42.816245 C 21.357568,43.098869 21.128192,43.328245 20.845568,43.328245 C 20.562944,43.328245 20.333568,43.098869 20.333568,42.816245 C 20.333568,42.533621 20.562944,42.304245 20.845568,42.304245 C 21.128192,42.304245 21.357568,42.533621 21.357568,42.816245 z "
id="path6596"
style="fill:url(#linearGradient6644);fill-opacity:1;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;overflow:visible" />
<path
d="M 21.258764,42.816245 C 21.258764,43.044329 21.073652,43.229441 20.845568,43.229441 C 20.617482,43.229441 20.432372,43.044329 20.432372,42.816245 C 20.432372,42.588161 20.617482,42.403049 20.845568,42.403049 C 21.073652,42.403049 21.258764,42.588161 21.258764,42.816245 z "
id="path6598"
style="fill:url(#linearGradient6646);fill-opacity:1;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;overflow:visible" />
<path
d="M 21.215476,42.816245 C 21.215476,43.020435 21.049758,43.186153 20.845568,43.186153 C 20.641378,43.186153 20.475658,43.020435 20.475658,42.816245 C 20.475658,42.612055 20.641378,42.446335 20.845568,42.446335 C 21.049758,42.446335 21.215476,42.612055 21.215476,42.816245 z "
id="path6600"
style="fill:url(#linearGradient6648);fill-opacity:1.0;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;overflow:visible" />
<path
d="M 21.140232,42.692857 C 21.140232,42.818847 21.00801,42.921099 20.845092,42.921099 C 20.682174,42.921099 20.549952,42.818847 20.549952,42.692857 C 20.549952,42.566867 20.682174,42.464615 20.845092,42.464615 C 21.00801,42.464615 21.140232,42.566867 21.140232,42.692857 z "
id="path6602"
style="fill:url(#linearGradient6650);fill-opacity:1;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;overflow:visible" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@@ -52,6 +52,7 @@
<file>icons/delete.svg</file>
<file>icons/led_green.svg</file>
<file>icons/led_red.svg</file>
<file>icons/led_gray.svg</file>
<file>icons/led_yellow.svg</file>
<file>icons/open.svg</file>
<file>icons/start.svg</file>

View File

@@ -88,14 +88,6 @@ def gns3vm_server():
return Servers.instance().vmServer()
@pytest.fixture
def ssh_server():
from gns3.servers import Servers
return Servers.instance().getRemoteServer("ssh", "127.0.0.1", 8001, "gns3", settings={"ssh_port": 22, "ssh_key": "/tmp/key.ssh"})
@pytest.fixture
def vpcs_device(local_server, project):

View File

@@ -26,6 +26,3 @@ def test_getNetworkUrl():
assert getNetworkUrl("http", "localhost", 8000, "rsWfk49a15KipT9o8tx4vKmGRo6NtwYJ3Q2Yff6imf6PplX1hJWHJQ6ayi0XfdoF") == "http://localhost:8000"
def test_ssh_getNetworkUrl():
settings = {"ssh_port": 22}
assert getNetworkUrl("ssh", "localhost", 8000, "root", settings=settings) == "ssh://root@localhost:22:8000"

View File

@@ -98,6 +98,10 @@ def test_loadSettingsWith13LocalServerSetting(tmpdir, local_config):
assert local_server["user"] == "world"
assert local_server["password"] == "hello"
def testServers():
servers = Servers.instance()
http_server = servers.getRemoteServer("http", "localhost", 8000, None)
assert len(servers.servers()) == 2
def test_getRemoteServer():
servers = Servers.instance()
@@ -107,14 +111,6 @@ def test_getRemoteServer():
assert http_server.port() == 8000
assert http_server.user() is None
ssh_server = servers.getRemoteServer("ssh", "127.0.0.1", 4000, "gns3", settings={"ssh_port": 22, "ssh_key": "/tmp/test.ssh"})
assert ssh_server.protocol() == "ssh"
assert ssh_server.host() == "127.0.0.1"
assert ssh_server.port() == 4000
assert ssh_server.user() == "gns3"
assert ssh_server.ssh_port() == 22
assert ssh_server.ssh_key() == "/tmp/test.ssh"
def test_getServerFromString():
@@ -136,19 +132,6 @@ def test_getServerFromString_with_user():
assert server.user() == "root"
def test_getServerFromString_with_ssh():
servers = Servers.instance()
servers._addRemoteServer("ssh", "127.0.0.1", "4000", user="root", ssh_port=22, ssh_key="/tmp/test.ssh")
server = servers.getServerFromString("ssh://root@127.0.0.1:22:4000")
assert server.protocol() == "ssh"
assert server.host() == "127.0.0.1"
assert server.port() == 4000
assert server.user() == "root"
assert server.ssh_port() == 22
assert server.ssh_key() == "/tmp/test.ssh"
def test_is_non_local_server_configured():
servers = Servers.instance()
@@ -159,9 +142,6 @@ def test_is_non_local_server_configured():
servers._vm_server = None
assert servers.isNonLocalServerConfigured() is False
servers._addRemoteServer("ssh", "127.0.0.1", "4000", user="root", ssh_port=22, ssh_key="/tmp/test.ssh")
assert servers.isNonLocalServerConfigured() is True
def test_handle_handleSslErrors():
"""

View File

@@ -149,67 +149,6 @@ def test_dump_http_auth(vpcs_device, project, remote_server):
}
def test_dump_ssh_server(project, ssh_server):
from gns3.modules.vpcs.vpcs_device import VPCSDevice
from gns3.modules.vpcs import VPCS
vpcs_device = VPCSDevice(VPCS(), ssh_server, project)
vpcs_device._vpcs_device_id = str(uuid.uuid4())
vpcs_device._settings = {"name": "VPCS 1", "script_file": "", "console": None, "startup_script": None}
vpcs_device.setInitialized(True)
topology = Topology()
topology.project = project
topology.addNode(vpcs_device)
dump = topology.dump(include_gui_data=False)
assert dict(dump) == {
"project_id": project.id(),
"auto_start": False,
"name": project.name(),
"version": __version__,
"revision": 4,
"topology": {
"nodes": [
{
"description": "VPCS device",
"id": vpcs_device.id(),
"ports": [
{
"id": vpcs_device.ports()[0].id(),
"name": "Ethernet0",
"port_number": 0,
"adapter_number": 0
}
],
"properties": {
"name": vpcs_device.name()
},
"server_id": ssh_server.id(),
"type": "VPCSDevice",
"vm_id": None
}
],
"servers": [
{
"vm": False,
"host": "127.0.0.1",
"id": ssh_server.id(),
"local": False,
"port": 8001,
"protocol": "ssh",
"ram_limit": 0,
"user": "gns3",
"ssh_port": 22,
"ssh_key": "/tmp/key.ssh"
}
]
},
"type": "topology"
}
def test_randomize_id(project, tmpdir):
project.setTopologyFile(str(tmpdir / "test.gns3"))