mirror of
https://github.com/GNS3/gns3-gui.git
synced 2026-05-17 00:46:01 +03:00
Merge 2.1 to 2.2
This commit is contained in:
@@ -6,6 +6,8 @@ notifications:
|
||||
script:
|
||||
- docker build -t gns3-gui-test .
|
||||
- docker run gns3-gui-test
|
||||
before_deploy:
|
||||
pip install twine
|
||||
deploy:
|
||||
provider: pypi
|
||||
user: noplay
|
||||
|
||||
34
CHANGELOG
34
CHANGELOG
@@ -1,5 +1,39 @@
|
||||
# Change Log
|
||||
|
||||
## 2.1.0rc2 04/10/2017
|
||||
|
||||
* Only show "can't get settings from controller" message in debug mode.
|
||||
* Remove explicit Telnet path on OS X. Ref #2274
|
||||
* Disable WebSocket notification for lower PyQT version than 5.6. Fixes #2272
|
||||
* Increase timeout to 5 minutes when creating and restoring a snapshot.
|
||||
* Add more information when a request timeouts. Ref #2277.
|
||||
* Do not show the progress dialog when moving a node. Ref #2275.
|
||||
* Increase timer before showing a progress dialog from 250ms to 500ms. Ref #2275.
|
||||
* Use embedded Telnet client on OS X. Ref #2274.
|
||||
* Fix small bug when adding an appliance template and the name already exists.
|
||||
* Use RAW sockets by default on Linux for VMware VM connections.
|
||||
* Increase timeout to get compute servers from controller. Ref #2269.
|
||||
* Fix "Node doesn't exist" after deletion, but still on the canvas. Fixes #2266.
|
||||
* Make sure the warning button icon appears in cloud properties dialog on Windows. Fixes #2245.
|
||||
* Fix bug when cancelling the importation of a configuration file. Fixes #2260.
|
||||
|
||||
## 2.1.0rc1 13/09/2017
|
||||
|
||||
* Fix missing spice console option in appliance template schema. Fixes #2255.
|
||||
|
||||
## 2.1.0b2 05/09/2017
|
||||
|
||||
* Fix resources dependencies for cloud configuration page (Fixes: #2251)
|
||||
* Disabled possibility of moving items under zero layer (Fixes #2220)
|
||||
* dialog-warning.svg fallback for themed icon (Ref. #2245)
|
||||
* Change width of packet filters dialog (Fixes #2244)
|
||||
* Fix high CPU usage when using packet filters. Fixes #2240.
|
||||
* Toggle Node menu item (Fixes #2227)
|
||||
* Fixes multiselection styles change crash on LineItem (#2216)
|
||||
* Fixes loading symbols for QEMU at Edit Page (#2214)
|
||||
* Fixes exception when right click on Dynamips router in the device dock (#2211)
|
||||
* Update frame_relay_switch_configuration_page.ui
|
||||
|
||||
## 2.1.0b1 04/08/2017
|
||||
|
||||
* Info added to the Nat node
|
||||
|
||||
@@ -58,12 +58,12 @@ class ComputeManager(QtCore.QObject):
|
||||
if self._controller.connected() and datetime.datetime.now().timestamp() - self._last_computes_refresh > 5:
|
||||
self._last_computes_refresh = datetime.datetime.now().timestamp()
|
||||
self._refreshingComputes = True
|
||||
self._controller.get("/computes", self._listComputesCallback, showProgress=False, timeout=15)
|
||||
self._controller.get("/computes", self._listComputesCallback, showProgress=False, timeout=30)
|
||||
|
||||
def _controllerConnectedSlot(self):
|
||||
if self._controller.connected():
|
||||
self._refreshingComputes = True
|
||||
self._controller.get("/computes", self._listComputesCallback, showProgress=False, timeout=15)
|
||||
self._controller.get("/computes", self._listComputesCallback, showProgress=False, timeout=30)
|
||||
|
||||
def _controllerDisconnectedSlot(self):
|
||||
for compute_id in list(self._computes):
|
||||
|
||||
@@ -51,7 +51,7 @@ class CrashReport:
|
||||
Report crash to a third party service
|
||||
"""
|
||||
|
||||
DSN = "sync+https://11f1de2cf38745ed8075e492c8a274e9:1035b6adddef40c88acd71346241072e@sentry.io/38506"
|
||||
DSN = "sync+https://8b9c164183434bd7a7a76a64e92f3721:f6e37f470bfe4e1cb60e0e63a87cf72c@sentry.io/38506"
|
||||
if hasattr(sys, "frozen"):
|
||||
cacert = get_resource("cacert.pem")
|
||||
if cacert is not None and os.path.isfile(cacert):
|
||||
|
||||
@@ -470,6 +470,8 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
while len(appliance_configuration["name"]) == 0 or not config.is_name_available(appliance_configuration["name"]):
|
||||
QtWidgets.QMessageBox.warning(self.parent(), "Add appliance", "The name \"{}\" is already used by another appliance".format(appliance_configuration["name"]))
|
||||
appliance_configuration["name"], ok = QtWidgets.QInputDialog.getText(self.parent(), "Add appliance", "New name:", QtWidgets.QLineEdit.Normal, appliance_configuration["name"])
|
||||
if not ok:
|
||||
return False
|
||||
appliance_configuration["name"] = appliance_configuration["name"].strip()
|
||||
|
||||
if "qemu" in appliance_configuration:
|
||||
|
||||
@@ -85,7 +85,7 @@ class SnapshotsDialog(QtWidgets.QDialog, Ui_SnapshotsDialog):
|
||||
|
||||
snapshot_name, ok = QtWidgets.QInputDialog.getText(self, "Snapshot", "Snapshot name:", QtWidgets.QLineEdit.Normal, "Unnamed")
|
||||
if ok and snapshot_name and self._project:
|
||||
Controller.instance().post("/projects/{}/snapshots".format(self._project.id()), self._createSnapshotsCallback, {"name": snapshot_name})
|
||||
Controller.instance().post("/projects/{}/snapshots".format(self._project.id()), self._createSnapshotsCallback, {"name": snapshot_name}, timeout=300)
|
||||
|
||||
def _createSnapshotsCallback(self, result, error=False, server=None, context={}, **kwargs):
|
||||
if error:
|
||||
@@ -131,7 +131,7 @@ class SnapshotsDialog(QtWidgets.QDialog, Ui_SnapshotsDialog):
|
||||
if reply == QtWidgets.QMessageBox.Cancel:
|
||||
return
|
||||
|
||||
Controller.instance().post("/projects/{}/snapshots/{}/restore".format(self._project.id(), snapshot_id), self._restoreSnapshotsCallback)
|
||||
Controller.instance().post("/projects/{}/snapshots/{}/restore".format(self._project.id(), snapshot_id), self._restoreSnapshotsCallback, timeout=300)
|
||||
|
||||
def _restoreSnapshotsCallback(self, result, error=False, server=None, context={}, **kwargs):
|
||||
if error:
|
||||
|
||||
@@ -21,6 +21,7 @@ Style editor to edit Shape items.
|
||||
|
||||
from ..qt import QtCore, QtWidgets, QtGui
|
||||
from ..ui.style_editor_dialog_ui import Ui_StyleEditorDialog
|
||||
from ..items.shape_item import ShapeItem
|
||||
|
||||
|
||||
class StyleEditorDialog(QtWidgets.QDialog, Ui_StyleEditorDialog):
|
||||
@@ -115,7 +116,9 @@ class StyleEditorDialog(QtWidgets.QDialog, Ui_StyleEditorDialog):
|
||||
|
||||
for item in self._items:
|
||||
item.setPen(pen)
|
||||
if brush:
|
||||
# on multiselection it's possible to select many type of items
|
||||
# but brush can be applied only on ShapeItem,
|
||||
if brush and isinstance(item, ShapeItem):
|
||||
item.setBrush(brush)
|
||||
item.setRotation(self.uiRotationSpinBox.value())
|
||||
|
||||
|
||||
@@ -135,6 +135,8 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
self.scene().addItem(item)
|
||||
super().setEnabled(enabled)
|
||||
|
||||
self.toggleUiDeviceMenu()
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Remove all the items from the scene and
|
||||
@@ -476,6 +478,8 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
else:
|
||||
super().mousePressEvent(event)
|
||||
|
||||
self.toggleUiDeviceMenu()
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
"""
|
||||
Handles all mouse release events.
|
||||
@@ -498,6 +502,8 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
item.setSelected(True)
|
||||
super().mouseReleaseEvent(event)
|
||||
|
||||
self.toggleUiDeviceMenu()
|
||||
|
||||
def wheelEvent(self, event):
|
||||
"""
|
||||
Handles zoom in or out using the mouse wheel.
|
||||
@@ -1174,6 +1180,8 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
self._import_config_dir,
|
||||
"All files (*.*);;Config files (*.cfg)",
|
||||
"Config files (*.cfg)")
|
||||
if not path:
|
||||
continue
|
||||
self._import_config_dir = os.path.dirname(path)
|
||||
item.node().importFile(config_file, path)
|
||||
|
||||
@@ -1221,12 +1229,9 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
for item in items:
|
||||
for config_file in item.node().configFiles():
|
||||
path, ok = QtWidgets.QFileDialog.getSaveFileName(self, "Export file", os.path.join(self._export_configs_to_dir, item.node().name() + "_" + os.path.basename(config_file)), "All files (*.*);;Config files (*.cfg)")
|
||||
|
||||
if not path:
|
||||
continue
|
||||
|
||||
self._export_configs_to_dir = os.path.dirname(path)
|
||||
|
||||
item.node().exportFile(config_file, path)
|
||||
|
||||
def getCommandLineSlot(self):
|
||||
@@ -1500,6 +1505,9 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
elif item.parentItem() is None:
|
||||
item.delete()
|
||||
|
||||
self.scene().clearSelection()
|
||||
self.toggleUiDeviceMenu()
|
||||
|
||||
def allocateCompute(self, node_data, module_instance):
|
||||
"""
|
||||
Allocates a server.
|
||||
@@ -1547,9 +1555,8 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
"""
|
||||
node = Topology.instance().getNode(node_id)
|
||||
name = "Node"
|
||||
if node:
|
||||
if node.name():
|
||||
name = node.name()
|
||||
if node and node.name():
|
||||
name = node.name()
|
||||
if self._main_window and not sip.isdeleted(self._main_window):
|
||||
QtWidgets.QMessageBox.critical(self._main_window, name, message.strip())
|
||||
|
||||
@@ -1592,3 +1599,11 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
painter.drawLine(rect.left(), y, rect.right(), y)
|
||||
y += gridSize
|
||||
painter.restore()
|
||||
|
||||
def toggleUiDeviceMenu(self):
|
||||
""" Hook which enables/disables uiDeviceMenu based on the current items selection"""
|
||||
items = self.scene().selectedItems()
|
||||
if len(items) > 0:
|
||||
self._main_window.uiDeviceMenu.setEnabled(True)
|
||||
else:
|
||||
self._main_window.uiDeviceMenu.setEnabled(False)
|
||||
|
||||
@@ -309,10 +309,10 @@ class HTTPClient(QtCore.QObject):
|
||||
return request()
|
||||
else:
|
||||
self._query_waiting_connections.append((request, callback))
|
||||
# If we are not connected and we enqueue the first query we open the conection
|
||||
# enqueue the first query and open the connection if we are not connected
|
||||
if len(self._query_waiting_connections) == 1:
|
||||
log.debug("Connection to {}".format(self.url()))
|
||||
self._executeHTTPQuery("GET", "/version", self._callbackConnect, {}, server=server, timeout=5, showProgress=False)
|
||||
self._executeHTTPQuery("GET", "/version", self._callbackConnect, {}, server=server, timeout=10, showProgress=False)
|
||||
|
||||
def _connectionError(self, callback, msg="", server=None):
|
||||
"""
|
||||
@@ -550,7 +550,7 @@ class HTTPClient(QtCore.QObject):
|
||||
self._notify_progress_start_query(context["query_id"], progressText, response)
|
||||
|
||||
if timeout is not None:
|
||||
QtCore.QTimer.singleShot(timeout * 1000, qpartial(self._timeoutSlot, response))
|
||||
QtCore.QTimer.singleShot(timeout * 1000, qpartial(self._timeoutSlot, response, timeout))
|
||||
|
||||
return response
|
||||
|
||||
@@ -585,14 +585,14 @@ class HTTPClient(QtCore.QObject):
|
||||
else:
|
||||
callback(content, server=server, context=context)
|
||||
|
||||
def _timeoutSlot(self, response):
|
||||
def _timeoutSlot(self, response, timeout):
|
||||
"""
|
||||
Beware it's call for all request you need to check the status of the response
|
||||
"""
|
||||
# We check if we received HTTP headers
|
||||
if not sip.isdeleted(response) and response.isRunning() and not len(response.rawHeaderList()) > 0:
|
||||
if not response.error() != QtNetwork.QNetworkReply.NoError:
|
||||
log.warn("Timeout request {}".format(response.url().toString()))
|
||||
log.warning("Timeout after {} seconds for request {}".format(timeout, response.url().toString()))
|
||||
response.abort()
|
||||
|
||||
def disconnect(self):
|
||||
|
||||
@@ -88,7 +88,7 @@ class DrawingItem:
|
||||
|
||||
def updateDrawing(self):
|
||||
if self._id:
|
||||
self._project.put("/drawings/" + self._id, self.updateDrawingCallback, body=self.__json__())
|
||||
self._project.put("/drawings/" + self._id, self.updateDrawingCallback, body=self.__json__(), showProgress=False)
|
||||
|
||||
@qslot
|
||||
def updateDrawingCallback(self, result, error=False, **kwargs):
|
||||
@@ -165,6 +165,7 @@ class DrawingItem:
|
||||
"""
|
||||
|
||||
QtWidgets.QGraphicsItem.setZValue(self, value)
|
||||
|
||||
if self.zValue() < 0:
|
||||
self.setFlag(self.ItemIsSelectable, False)
|
||||
self.setFlag(self.ItemIsMovable, False)
|
||||
|
||||
@@ -48,6 +48,13 @@ class EllipseItem(QtWidgets.QGraphicsEllipseItem, ShapeItem):
|
||||
super().paint(painter, option, widget)
|
||||
self.drawLayerInfo(painter)
|
||||
|
||||
def setZValue(self, value):
|
||||
"""
|
||||
Sets Z value of the item
|
||||
:param value: z layer
|
||||
"""
|
||||
return ShapeItem.setZValue(self, value)
|
||||
|
||||
def toSvg(self):
|
||||
"""
|
||||
Return an SVG version of the shape
|
||||
|
||||
@@ -64,6 +64,13 @@ class ImageItem(QtSvg.QGraphicsSvgItem, DrawingItem):
|
||||
super().paint(painter, option, widget)
|
||||
self.drawLayerInfo(painter)
|
||||
|
||||
def setZValue(self, value):
|
||||
"""
|
||||
Sets Z value of the item
|
||||
:param value: z layer
|
||||
"""
|
||||
return DrawingItem.setZValue(self, value)
|
||||
|
||||
def fromSvg(self, svg):
|
||||
renderer = QImageSvgRenderer(svg)
|
||||
self.setSharedRenderer(renderer)
|
||||
|
||||
@@ -63,6 +63,13 @@ class LineItem(QtWidgets.QGraphicsLineItem, DrawingItem):
|
||||
super().paint(painter, option, widget)
|
||||
self.drawLayerInfo(painter)
|
||||
|
||||
def setZValue(self, value):
|
||||
"""
|
||||
Sets Z value of the item
|
||||
:param value: z layer
|
||||
"""
|
||||
return DrawingItem.setZValue(self, value)
|
||||
|
||||
def toSvg(self):
|
||||
"""
|
||||
Return an SVG version of the shape
|
||||
|
||||
@@ -483,7 +483,7 @@ class LinkItem(QtWidgets.QGraphicsPathItem):
|
||||
link_center = QtCore.QPointF(self.source.x() + self.dx / 2.0 - 11, self.source.y() + self.dy / 2.0 - 11)
|
||||
if self._suspend_item is None:
|
||||
self._suspend_item = SvgIconItem(':/icons/pause.svg', self)
|
||||
self._suspend_item.setScale(0.6)
|
||||
self._suspend_item.setScale(0.6)
|
||||
if not self._suspend_item.isVisible():
|
||||
self._suspend_item.show()
|
||||
self._suspend_item.setPos(link_center)
|
||||
@@ -537,7 +537,7 @@ class LinkItem(QtWidgets.QGraphicsPathItem):
|
||||
link_center = QtCore.QPointF(self.source.x() + self.dx / 2.0 - 11, self.source.y() + self.dy / 2.0 - 11)
|
||||
if self._filter_item is None:
|
||||
self._filter_item = SvgIconItem(':/icons/filter.svg', self)
|
||||
self._filter_item.setScale(0.6)
|
||||
self._filter_item.setScale(0.6)
|
||||
if not self._filter_item.isVisible():
|
||||
self._filter_item.show()
|
||||
self._filter_item.setPos(link_center)
|
||||
|
||||
@@ -46,6 +46,13 @@ class RectangleItem(QtWidgets.QGraphicsRectItem, ShapeItem):
|
||||
super().paint(painter, option, widget)
|
||||
self.drawLayerInfo(painter)
|
||||
|
||||
def setZValue(self, value):
|
||||
"""
|
||||
Sets Z value of the item
|
||||
:param value: z layer
|
||||
"""
|
||||
return ShapeItem.setZValue(self, value)
|
||||
|
||||
def toSvg(self):
|
||||
"""
|
||||
Return an SVG version of the shape
|
||||
@@ -61,4 +68,3 @@ class RectangleItem(QtWidgets.QGraphicsRectItem, ShapeItem):
|
||||
rect = self._styleSvg(rect)
|
||||
|
||||
return ET.tostring(svg, encoding="utf-8").decode("utf-8")
|
||||
|
||||
|
||||
@@ -111,6 +111,13 @@ class TextItem(QtWidgets.QGraphicsTextItem, DrawingItem):
|
||||
super().paint(painter, option, widget)
|
||||
self.drawLayerInfo(painter)
|
||||
|
||||
def setZValue(self, value):
|
||||
"""
|
||||
Sets Z value of the item
|
||||
:param value: z layer
|
||||
"""
|
||||
return DrawingItem.setZValue(self, value)
|
||||
|
||||
def toSvg(self):
|
||||
"""
|
||||
Return an SVG version of the text
|
||||
|
||||
@@ -150,7 +150,7 @@ class LocalConfig(QtCore.QObject):
|
||||
def _getSettingsCallback(self, result, error=False, **kwargs):
|
||||
self._refreshingSettings = False
|
||||
if error:
|
||||
log.error("Can't get settings from controller")
|
||||
log.debug("Can't get settings from controller")
|
||||
return
|
||||
if result == {} and self._settings != {}:
|
||||
self._settings_retrieved_from_controller = True
|
||||
|
||||
@@ -132,7 +132,7 @@ class LocalServer(QtCore.QObject):
|
||||
if win32serviceutil.QueryServiceStatus(service_name, None)[1] != win32service.SERVICE_RUNNING:
|
||||
return False
|
||||
except pywintypes.error as e:
|
||||
if e.winerror == 1060:
|
||||
if e.winerror == 1060: # service is not installed
|
||||
return False
|
||||
else:
|
||||
log.error("Could not check if the {} service is running: {}".format(service_name, e.strerror))
|
||||
|
||||
@@ -651,10 +651,11 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
return
|
||||
self._screenshots_dir = os.path.dirname(path)
|
||||
|
||||
# add the extension if missing
|
||||
file_format = "." + selected_filter[:4].lower().strip()
|
||||
if not path.endswith(file_format):
|
||||
path += file_format
|
||||
# add the extension if missing (Mac OS automatically adds an extension already)
|
||||
if not sys.platform.startswith("darwin"):
|
||||
file_format = "." + selected_filter[:4].lower().strip()
|
||||
if not path.endswith(file_format):
|
||||
path += file_format
|
||||
|
||||
if not self.createScreenshot(path):
|
||||
QtWidgets.QMessageBox.critical(self, "Screenshot", "Could not create screenshot file {}".format(path))
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
Configuration page for clouds.
|
||||
"""
|
||||
|
||||
from gns3.qt import QtCore, QtWidgets
|
||||
from gns3.qt import QtCore, QtGui, QtWidgets
|
||||
from gns3.dialogs.symbol_selection_dialog import SymbolSelectionDialog
|
||||
from gns3.controller import Controller
|
||||
from gns3.node import Node
|
||||
@@ -68,6 +68,12 @@ class CloudConfigurationPage(QtWidgets.QWidget, Ui_cloudConfigPageWidget):
|
||||
self.uiShowSpecialInterfacesCheckBox.stateChanged.connect(self._showSpecialInterfacesSlot)
|
||||
self.uiSymbolToolButton.clicked.connect(self._symbolBrowserSlot)
|
||||
|
||||
# add an icon to warning button
|
||||
icon = QtGui.QIcon.fromTheme("dialog-warning")
|
||||
if icon.isNull():
|
||||
icon = QtGui.QIcon(':/icons/dialog-warning.svg')
|
||||
self.uiEthernetWarningPushButton.setIcon(icon)
|
||||
|
||||
def _EthernetChangedSlot(self):
|
||||
"""
|
||||
Enables the use of the delete button.
|
||||
|
||||
@@ -82,9 +82,6 @@
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="dialog-warning"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/modules/builtin/ui/cloud_configuration_page.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.5.1
|
||||
# Created by: PyQt5 UI code generator 5.9
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
@@ -11,7 +11,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
class Ui_cloudConfigPageWidget(object):
|
||||
def setupUi(self, cloudConfigPageWidget):
|
||||
cloudConfigPageWidget.setObjectName("cloudConfigPageWidget")
|
||||
cloudConfigPageWidget.resize(758, 299)
|
||||
cloudConfigPageWidget.resize(821, 363)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(cloudConfigPageWidget)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.uiTabWidget = QtWidgets.QTabWidget(cloudConfigPageWidget)
|
||||
@@ -46,8 +46,6 @@ class Ui_cloudConfigPageWidget(object):
|
||||
self.gridLayout_3.addWidget(self.uiEthernetListWidget, 1, 0, 1, 5)
|
||||
self.uiEthernetWarningPushButton = QtWidgets.QPushButton(self.EthernetTab)
|
||||
self.uiEthernetWarningPushButton.setText("")
|
||||
icon = QtGui.QIcon.fromTheme("dialog-warning")
|
||||
self.uiEthernetWarningPushButton.setIcon(icon)
|
||||
self.uiEthernetWarningPushButton.setObjectName("uiEthernetWarningPushButton")
|
||||
self.gridLayout_3.addWidget(self.uiEthernetWarningPushButton, 0, 1, 1, 1)
|
||||
self.uiShowSpecialInterfacesCheckBox = QtWidgets.QCheckBox(self.EthernetTab)
|
||||
|
||||
@@ -199,7 +199,8 @@ class QemuVMPreferencesPage(QtWidgets.QWidget, Ui_QemuVMPreferencesPageWidget):
|
||||
dialog.show()
|
||||
if dialog.exec_():
|
||||
# update the icon
|
||||
item.setIcon(0, QtGui.QIcon(qemu_vm["symbol"]))
|
||||
Controller.instance().getSymbolIcon(qemu_vm["symbol"], qpartial(self._setItemIcon, item))
|
||||
|
||||
if qemu_vm["name"] != item.text(0):
|
||||
new_key = "{server}:{name}".format(server=qemu_vm["server"], name=qemu_vm["name"])
|
||||
if new_key in self._qemu_vms:
|
||||
|
||||
@@ -54,8 +54,6 @@ class VMwarePreferencesPage(QtWidgets.QWidget, Ui_VMwarePreferencesPageWidget):
|
||||
else:
|
||||
# VMnet limit on Linux is 255
|
||||
self.uiVMnetEndRangeSpinBox.setMaximum(255)
|
||||
# Block host network traffic is only supported on Windows for now
|
||||
self.uiBlockHostTrafficCheckBox.setEnabled(False)
|
||||
|
||||
def _vmrunPathBrowserSlot(self):
|
||||
"""
|
||||
|
||||
@@ -32,7 +32,7 @@ VMWARE_SETTINGS = {
|
||||
"host_type": "ws",
|
||||
"vmnet_start_range": 2,
|
||||
"vmnet_end_range": DEFAULT_VMNET_END_RANGE,
|
||||
"block_host_traffic": True,
|
||||
"block_host_traffic": sys.platform.startswith("win"), # block host traffic on Windows only (due to winpcap packet duplication issue).
|
||||
}
|
||||
|
||||
VMWARE_VM_SETTINGS = {
|
||||
|
||||
@@ -230,7 +230,7 @@ class Node(BaseNode):
|
||||
if self.initialized():
|
||||
log.debug("{} is updating settings: {}".format(self.name(), params))
|
||||
body = self._prepareBody(params)
|
||||
self.controllerHttpPut("/nodes/{node_id}".format(node_id=self._node_id), self.updateNodeCallback, body=body, timeout=timeout)
|
||||
self.controllerHttpPut("/nodes/{node_id}".format(node_id=self._node_id), self.updateNodeCallback, body=body, timeout=timeout, showProgress=False)
|
||||
|
||||
def updateNodeCallback(self, result, error=False, **kwargs):
|
||||
"""
|
||||
@@ -402,7 +402,7 @@ class Node(BaseNode):
|
||||
if error:
|
||||
log.error("error while deleting {}: {}".format(self.name(), result["message"]))
|
||||
self.server_error_signal.emit(self.id(), result["message"])
|
||||
return
|
||||
# delete the node even if there is an error on server side
|
||||
self.deleted_signal.emit()
|
||||
self._module.removeNode(self)
|
||||
|
||||
|
||||
@@ -195,7 +195,11 @@ class NodesView(QtWidgets.QTreeWidget):
|
||||
if not node:
|
||||
return
|
||||
for module in MODULES:
|
||||
node_class = module.getNodeType(node["node_type"])
|
||||
if node["node_type"] == "dynamips":
|
||||
node_class = module.getNodeType(node["node_type"], node["platform"])
|
||||
else:
|
||||
node_class = module.getNodeType(node["node_type"])
|
||||
|
||||
if node_class:
|
||||
break
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class Progress(QtCore.QObject):
|
||||
show_signal = QtCore.Signal()
|
||||
hide_signal = QtCore.Signal()
|
||||
|
||||
def __init__(self, parent, min_duration=1000, delay=250):
|
||||
def __init__(self, parent, min_duration=1000, delay=500):
|
||||
"""
|
||||
:param min_duration: When the windows is display the windows is display for at least min_duration
|
||||
:param delay: Delay before display the first dialog
|
||||
@@ -48,11 +48,6 @@ class Progress(QtCore.QObject):
|
||||
self._progress_dialog = None
|
||||
self._show_lock = False
|
||||
|
||||
# Timer called for refreshing the progress dialog status
|
||||
self._rtimer = QtCore.QTimer()
|
||||
self._rtimer.timeout.connect(self.update)
|
||||
self._rtimer.start(250)
|
||||
|
||||
# When in millisecond we started to show the progress dialog
|
||||
self._display_start_time = 0
|
||||
|
||||
|
||||
@@ -531,7 +531,7 @@ class Project(QtCore.QObject):
|
||||
return
|
||||
|
||||
# Qt websocket before Qt 5.6 doesn't support auth
|
||||
if parse_version(QtCore.QT_VERSION_STR) < parse_version("5.6.0"):
|
||||
if parse_version(QtCore.QT_VERSION_STR) < parse_version("5.6.0") or parse_version(QtCore.PYQT_VERSION_STR) < parse_version("5.6.0"):
|
||||
path = "/projects/{project_id}/notifications".format(project_id=self._id)
|
||||
self._notification_stream = Controller.instance().createHTTPQuery("GET", path, self._endListenNotificationCallback,
|
||||
downloadProgressCallback=self._event_received,
|
||||
|
||||
@@ -288,12 +288,12 @@ def qslot(func):
|
||||
return func_wrapper
|
||||
|
||||
|
||||
# Log qt error to Python log
|
||||
# Log Qt messages to Python log
|
||||
def myQtMsgHandler(msg_type, msg_log_context, msg_string):
|
||||
if "_COMPIZ_TOOLKIT_ACTION" in msg_string:
|
||||
# Qt < 5.6 issue: https://github.com/GNS3/gns3-gui/issues/2020
|
||||
return
|
||||
log.error(msg_string)
|
||||
log.info(msg_string)
|
||||
|
||||
|
||||
QtCore.qInstallMessageHandler(myQtMsgHandler)
|
||||
|
||||
@@ -279,7 +279,7 @@
|
||||
"title": "Architecture emulated"
|
||||
},
|
||||
"console_type": {
|
||||
"enum": ["telnet", "vnc"],
|
||||
"enum": ["telnet", "vnc", "spice"],
|
||||
"title": "Type of console connection for the administration of the appliance"
|
||||
},
|
||||
"boot_priority": {
|
||||
|
||||
@@ -60,6 +60,16 @@ class ConsoleThread(QtCore.QThread):
|
||||
except ValueError:
|
||||
self.consoleError.emit("Syntax error in command: {}".format(command))
|
||||
return
|
||||
if sys.platform.startswith("darwin") and hasattr(sys, "frozen"):
|
||||
# Add to the path where the OS search executables, this is to force using the embedded telnet
|
||||
# in the DMG on Mac OS
|
||||
frozen_dir = os.path.dirname(os.path.abspath(sys.executable))
|
||||
if sys.platform.startswith("darwin"):
|
||||
frozen_dirs = [
|
||||
frozen_dir,
|
||||
os.path.normpath(os.path.join(frozen_dir, '..', 'Resources'))
|
||||
]
|
||||
os.environ["PATH"] = os.pathsep.join(frozen_dirs) + os.pathsep + os.environ.get("PATH", "")
|
||||
subprocess.call(args, env=os.environ)
|
||||
|
||||
def run(self):
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1357</width>
|
||||
<width>799</width>
|
||||
<height>255</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/filter_dialog.ui'
|
||||
# Form implementation generated from reading ui file '/home/dominik/projects/gns3-gui/gns3/ui/filter_dialog.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.8.2
|
||||
#
|
||||
@@ -12,7 +12,7 @@ class Ui_FilterDialog(object):
|
||||
def setupUi(self, FilterDialog):
|
||||
FilterDialog.setObjectName("FilterDialog")
|
||||
FilterDialog.setWindowModality(QtCore.Qt.ApplicationModal)
|
||||
FilterDialog.resize(1357, 255)
|
||||
FilterDialog.resize(799, 255)
|
||||
self.verticalLayout_3 = QtWidgets.QVBoxLayout(FilterDialog)
|
||||
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||
self.uiVerticalLayout = QtWidgets.QVBoxLayout()
|
||||
|
||||
176063
gns3/ui/resources_rc.py
176063
gns3/ui/resources_rc.py
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
__version__ = "2.1.0dev4"
|
||||
__version__ = "2.1.0dev8"
|
||||
__version_info__ = (2, 1, 0, -99)
|
||||
|
||||
# If it's a git checkout try to add the commit
|
||||
|
||||
36
resources/icons/dialog-warning.svg
Normal file
36
resources/icons/dialog-warning.svg
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<linearGradient id="a" y2="50" gradientUnits="userSpaceOnUse" x2="42" y1="18" x1="12">
|
||||
<stop stop-color="#ddd" offset="0"/>
|
||||
<stop stop-color="#fff" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="e" x2="0" gradientUnits="userSpaceOnUse" y2="46.2" y1="41.2">
|
||||
<stop offset="0"/>
|
||||
<stop stop-opacity="0" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="b" y2="51" gradientUnits="userSpaceOnUse" y1="24" x2="38" x1="6">
|
||||
<stop stop-color="#e88" offset="0"/>
|
||||
<stop stop-color="#d33" offset="1"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="f" gradientUnits="userSpaceOnUse" cy="41.2" cx="39.1" gradientTransform="matrix(2 0 0 1.28 -39.1 -11.6)" r="3.9">
|
||||
<stop offset="0"/>
|
||||
<stop stop-opacity="0" offset="1"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<g opacity=".4">
|
||||
<path id="d" fill="url(#f)" d="m39.1 46.1c3.23 0 7.9-2.24 7.9-5s-3.7-5-7.9-5z"/>
|
||||
<use x="-48" xlink:href="#d" transform="scale(-1,1)"/>
|
||||
<path fill="url(#e)" d="m8.9 36.1h30.2v10h-30.2z"/>
|
||||
</g>
|
||||
<g stroke-linejoin="round">
|
||||
<g stroke="#900" stroke-width="6">
|
||||
<path id="c" d="m7 40h34l-17-32z"/>
|
||||
</g>
|
||||
<use stroke-width="4" stroke="url(#b)" xlink:href="#c"/>
|
||||
<use stroke-width="2" stroke="#c00" xlink:href="#c" fill="#c00"/>
|
||||
<path stroke="url(#a)" d="m9.8 38.3h28.4l-14.2-26.7z" fill="url(#a)"/>
|
||||
</g>
|
||||
<path d="m22.75 30.4l-0.5-10h3.5l-0.6 10z"/>
|
||||
<circle cy="33.58" cx="24" r="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -107,6 +107,7 @@
|
||||
<file>icons/camera-photo.svg</file>
|
||||
<file>icons/camera-photo-hover.svg</file>
|
||||
<file>icons/front.svg</file>
|
||||
<file>icons/dialog-warning.svg</file>
|
||||
<file>images/gns3_logo.png</file>
|
||||
<file>images/gns3_icon_128x128.png</file>
|
||||
<file>images/gns3_icon_256x256.png</file>
|
||||
|
||||
@@ -189,7 +189,7 @@ def test_create_new_version():
|
||||
# tests what happens without versions in file
|
||||
wrong_appliance_fp, wrong_appliance_file = tempfile.mkstemp()
|
||||
|
||||
with open(appliance_path) as f:
|
||||
with open(appliance_path, encoding='utf-8') as f:
|
||||
appliance = json.loads(f.read())
|
||||
del appliance['versions']
|
||||
os.write(wrong_appliance_fp, json.dumps(appliance).encode())
|
||||
|
||||
@@ -60,6 +60,7 @@ def link(devices, controller, project):
|
||||
link = Link(devices[0], devices[0].ports()[0], devices[1], devices[1].ports()[0])
|
||||
|
||||
data = {
|
||||
"suspend": False,
|
||||
"nodes": [
|
||||
{"node_id": devices[0].node_id(), "adapter_number": 0, "port_number": 0},
|
||||
{"node_id": devices[1].node_id(), "adapter_number": 0, "port_number": 0}
|
||||
@@ -83,6 +84,7 @@ def test_create_link(devices, project, controller):
|
||||
link = Link(devices[0], devices[0].ports()[0], devices[1], devices[1].ports()[0])
|
||||
|
||||
data = {
|
||||
"suspend": False,
|
||||
"nodes": [
|
||||
{"node_id": devices[0].node_id(), "adapter_number": 0, "port_number": 0},
|
||||
{"node_id": devices[1].node_id(), "adapter_number": 0, "port_number": 0},
|
||||
|
||||
Reference in New Issue
Block a user