mirror of
https://github.com/GNS3/gns3-gui.git
synced 2026-05-17 00:46:01 +03:00
Merge remote-tracking branch 'origin/2.2' into 3.0
# Conflicts: # CHANGELOG # dev-requirements.txt # gns3/crash_report.py # gns3/version.py # tests/test_http_client.py
This commit is contained in:
10
CHANGELOG
10
CHANGELOG
@@ -1,5 +1,15 @@
|
||||
# Change Log
|
||||
|
||||
## 2.2.56.1 28/01/2026
|
||||
|
||||
* Fix line style support for links
|
||||
* Fix cannot add IOS in preferences
|
||||
* Fix cannot add IOU in preferences
|
||||
* Upgrade dependencies
|
||||
* Drop Python 3.8 support
|
||||
* Display a warning if a SVG image format isn't supported
|
||||
* Fix error in profile selection window after PyQt6 migration
|
||||
|
||||
## 3.0.6 28/01/2026
|
||||
|
||||
* Fixing tab name in MobaXterm
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
pytest==8.4.2 # version 8.4.2 is the last one supporting Python 3.9
|
||||
pytest==8.4.2; python_version == '3.9' # version 8.4.2 is the last one supporting Python 3.9
|
||||
pytest==9.0.2; python_version >= '3.10'
|
||||
pytest-timeout==2.4.0
|
||||
|
||||
@@ -65,10 +65,13 @@ class StyleEditorDialogLink(QtWidgets.QDialog, Ui_StyleEditorDialog):
|
||||
link.setHovered(True)
|
||||
|
||||
self._border_color = pen.color()
|
||||
self.uiBorderColorPushButton.setStyleSheet("background-color: rgba({}, {}, {}, {});".format(self._border_color.red(),
|
||||
self._border_color.green(),
|
||||
self._border_color.blue(),
|
||||
self._border_color.alpha()))
|
||||
self.uiBorderColorPushButton.setStyleSheet("background-color: rgba({}, {}, {}, {});".format(
|
||||
self._border_color.red(),
|
||||
self._border_color.green(),
|
||||
self._border_color.blue(),
|
||||
self._border_color.alpha())
|
||||
)
|
||||
|
||||
self.uiBorderWidthSpinBox.setValue(pen.width())
|
||||
index = self.uiBorderStyleComboBox.findData(pen.style())
|
||||
if index != -1:
|
||||
@@ -102,8 +105,8 @@ class StyleEditorDialogLink(QtWidgets.QDialog, Ui_StyleEditorDialog):
|
||||
new_link_style = {}
|
||||
new_link_style["color"] = self._border_color.name()
|
||||
new_link_style["width"] = self.uiBorderWidthSpinBox.value()
|
||||
new_link_style["type"] = border_style
|
||||
|
||||
new_link_style["type"] = border_style.value
|
||||
|
||||
# Store values
|
||||
self._link.setLinkStyle(new_link_style)
|
||||
self._link.setHovered(False) # allow to see the new style
|
||||
|
||||
@@ -56,7 +56,7 @@ class EthernetLinkItem(LinkItem):
|
||||
if self._hovered:
|
||||
self.setPen(QtGui.QPen(QtCore.Qt.GlobalColor.red, self._link._link_style["width"] + 1, QtCore.Qt.PenStyle.SolidLine, QtCore.Qt.PenCapStyle.RoundCap, QtCore.Qt.PenJoinStyle.RoundJoin))
|
||||
else:
|
||||
self.setPen(QtGui.QPen(QtGui.QColor(self._link._link_style["color"]), self._link._link_style["width"], self._link._link_style["type"], QtCore.Qt.PenCapStyle.RoundCap, QtCore.Qt.PenJoinStyle.RoundJoin))
|
||||
self.setPen(QtGui.QPen(QtGui.QColor(self._link._link_style["color"]), self._link._link_style["width"], QtCore.Qt.PenStyle(self._link._link_style["type"]), QtCore.Qt.PenCapStyle.RoundCap, QtCore.Qt.PenJoinStyle.RoundJoin))
|
||||
except:
|
||||
if self._hovered:
|
||||
self.setPen(QtGui.QPen(QtCore.Qt.GlobalColor.red, self._pen_width + 1, QtCore.Qt.PenStyle.SolidLine, QtCore.Qt.PenCapStyle.RoundCap, QtCore.Qt.PenJoinStyle.RoundJoin))
|
||||
|
||||
@@ -54,7 +54,7 @@ class SerialLinkItem(LinkItem):
|
||||
if self._hovered:
|
||||
self.setPen(QtGui.QPen(QtCore.Qt.GlobalColor.red, self._link._link_style["width"] + 1, QtCore.Qt.PenStyle.SolidLine, QtCore.Qt.PenCapStyle.RoundCap, QtCore.Qt.PenJoinStyle.RoundJoin))
|
||||
else:
|
||||
self.setPen(QtGui.QPen(QtGui.QColor(self._link._link_style["color"]), self._link._link_style["width"], self._link._link_style["type"], QtCore.Qt.PenCapStyle.RoundCap, QtCore.Qt.PenJoinStyle.RoundJoin))
|
||||
self.setPen(QtGui.QPen(QtGui.QColor(self._link._link_style["color"]), self._link._link_style["width"], QtCore.Qt.PenStyle(self._link._link_style["type"]), QtCore.Qt.PenCapStyle.RoundCap, QtCore.Qt.PenJoinStyle.RoundJoin))
|
||||
except:
|
||||
if self._hovered:
|
||||
self.setPen(QtGui.QPen(QtCore.Qt.GlobalColor.red, self._pen_width + 1, QtCore.Qt.PenStyle.SolidLine, QtCore.Qt.PenCapStyle.RoundCap, QtCore.Qt.PenJoinStyle.RoundJoin))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
jsonschema>=4.25.1,<4.26 # version 4.25.1 is the last to support Python 3.9
|
||||
sentry-sdk>=2.50.0,<3 # optional dependency
|
||||
psutil>=7.2.1
|
||||
jsonschema==4.25.1; python_version == '3.9' # version 4.25.1 is the last to support Python 3.9
|
||||
jsonschema>=4.26.0,<4.27; python_version >= '3.10'
|
||||
sentry-sdk>=2.52.0,<3 # optional dependency
|
||||
psutil>=7.2.2
|
||||
distro>=1.9.0
|
||||
truststore>=0.10.4; python_version >= '3.10'
|
||||
|
||||
@@ -23,8 +23,8 @@ from gns3.qt import QtGui, QtCore
|
||||
|
||||
def test_toSvg(project, controller):
|
||||
ellipse = EllipseItem(width=400, height=100, project=project)
|
||||
pen = QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
|
||||
pen.setStyle(QtCore.Qt.DashLine)
|
||||
pen = QtGui.QPen(QtCore.Qt.GlobalColor.black, 2, QtCore.Qt.PenStyle.SolidLine, QtCore.Qt.PenCapStyle.RoundCap, QtCore.Qt.PenJoinStyle.RoundJoin)
|
||||
pen.setStyle(QtCore.Qt.PenStyle.DashLine)
|
||||
ellipse.setPen(pen)
|
||||
svg = ET.fromstring(ellipse.toSvg())
|
||||
assert float(svg.get("width")) == 400.0
|
||||
|
||||
@@ -32,7 +32,7 @@ def test_dump():
|
||||
font.setUnderline(True)
|
||||
font.setStrikeOut(True)
|
||||
label.setFont(font)
|
||||
label.setDefaultTextColor(QtCore.Qt.red)
|
||||
label.setDefaultTextColor(QtCore.Qt.GlobalColor.red)
|
||||
|
||||
assert label.dump() == {
|
||||
"text": "Test",
|
||||
@@ -54,7 +54,7 @@ def test_setStyle():
|
||||
font.setUnderline(True)
|
||||
font.setStrikeOut(False)
|
||||
label.setFont(font)
|
||||
label.setDefaultTextColor(QtCore.Qt.red)
|
||||
label.setDefaultTextColor(QtCore.Qt.GlobalColor.red)
|
||||
|
||||
style = label.dump()["style"]
|
||||
label2 = LabelItem()
|
||||
@@ -65,4 +65,4 @@ def test_setStyle():
|
||||
assert label2.font().bold()
|
||||
assert label2.font().strikeOut() is False
|
||||
assert label2.font().underline()
|
||||
assert label2.defaultTextColor() == QtCore.Qt.red
|
||||
assert label2.defaultTextColor() == QtCore.Qt.GlobalColor.red
|
||||
|
||||
@@ -23,8 +23,8 @@ from gns3.qt import QtGui, QtCore
|
||||
|
||||
def test_toSvg(project, controller):
|
||||
line = LineItem(dst=QtCore.QPointF(400, 280), project=project)
|
||||
pen = QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
|
||||
pen.setStyle(QtCore.Qt.DashLine)
|
||||
pen = QtGui.QPen(QtCore.Qt.GlobalColor.black, 2, QtCore.Qt.PenStyle.SolidLine, QtCore.Qt.PenCapStyle.RoundCap, QtCore.Qt.PenJoinStyle.RoundJoin)
|
||||
pen.setStyle(QtCore.Qt.PenStyle.DashLine)
|
||||
line.setPen(pen)
|
||||
svg = ET.fromstring(line.toSvg())
|
||||
assert float(svg.get("width")) == 400.0
|
||||
@@ -42,8 +42,8 @@ def test_toSvg(project, controller):
|
||||
|
||||
def test_toSvg_negative_y(project, controller):
|
||||
line = LineItem(dst=QtCore.QPointF(400, -280), project=project)
|
||||
pen = QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
|
||||
pen.setStyle(QtCore.Qt.DashLine)
|
||||
pen = QtGui.QPen(QtCore.Qt.GlobalColor.black, 2, QtCore.Qt.PenStyle.SolidLine, QtCore.Qt.PenCapStyle.RoundCap, QtCore.Qt.PenJoinStyle.RoundJoin)
|
||||
pen.setStyle(QtCore.Qt.PenStyle.DashLine)
|
||||
line.setPen(pen)
|
||||
svg = ET.fromstring(line.toSvg())
|
||||
assert float(svg.get("width")) == 400.0
|
||||
@@ -69,7 +69,7 @@ def test_fromSvg(project, controller):
|
||||
assert line.line().x2() == 250
|
||||
assert line.line().y2() == 150
|
||||
assert hex(line.pen().color().rgba()) == "0xff0000ff"
|
||||
assert line.pen().style() == QtCore.Qt.DashDotLine
|
||||
assert line.pen().style() == QtCore.Qt.PenStyle.DashDotLine
|
||||
assert line.pos().x() == 50
|
||||
assert line.pos().y() == 84
|
||||
|
||||
@@ -84,7 +84,7 @@ def test_fromSvg_top_direction(project, controller):
|
||||
assert line.line().x2() == 250
|
||||
assert line.line().y2() == 0
|
||||
assert hex(line.pen().color().rgba()) == "0xff0000ff"
|
||||
assert line.pen().style() == QtCore.Qt.DashDotLine
|
||||
assert line.pen().style() == QtCore.Qt.PenStyle.DashDotLine
|
||||
assert line.pos().x() == 50
|
||||
assert line.pos().y() == 84
|
||||
|
||||
@@ -92,7 +92,7 @@ def test_fromSvg_top_direction(project, controller):
|
||||
def test_fromSvg_solid_stroke(project, controller):
|
||||
line = LineItem(project=project)
|
||||
line.fromSvg('<svg height="150" width="250"><line x1="0" y1="0" x2="250" y2="150" stroke-width="5" stroke="#0000ff" /></svg>')
|
||||
assert line.pen().style() == QtCore.Qt.SolidLine
|
||||
assert line.pen().style() == QtCore.Qt.PenStyle.SolidLine
|
||||
|
||||
|
||||
def test_fromEmptySvg(project, controller):
|
||||
|
||||
@@ -23,8 +23,8 @@ from gns3.qt import QtGui, QtCore
|
||||
|
||||
def test_toSvg(project, controller):
|
||||
rect = RectangleItem(width=400, height=280, project=project)
|
||||
pen = QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
|
||||
pen.setStyle(QtCore.Qt.DashLine)
|
||||
pen = QtGui.QPen(QtCore.Qt.GlobalColor.black, 2, QtCore.Qt.PenStyle.SolidLine, QtCore.Qt.PenCapStyle.RoundCap, QtCore.Qt.PenJoinStyle.RoundJoin)
|
||||
pen.setStyle(QtCore.Qt.PenStyle.DashLine)
|
||||
rect.setPen(pen)
|
||||
svg = ET.fromstring(rect.toSvg())
|
||||
assert float(svg.get("width")) == 400.0
|
||||
@@ -49,13 +49,13 @@ def test_fromSvg(project, controller):
|
||||
assert rect.pen().width() == 5
|
||||
assert hex(rect.pen().color().rgba()) == "0xff0000ff"
|
||||
assert hex(rect.brush().color().rgba()) == "0x80ff00ff"
|
||||
assert rect.pen().style() == QtCore.Qt.DashDotLine
|
||||
assert rect.pen().style() == QtCore.Qt.PenStyle.DashDotLine
|
||||
|
||||
|
||||
def test_fromSvg_solid_stroke(project, controller):
|
||||
rect = RectangleItem(project=project)
|
||||
rect.fromSvg('<svg height="150" width="250"><rect height="150" stroke-width="5" stroke="#0000ff" fill="#ff00ff" width="150" /></svg>')
|
||||
assert rect.pen().style() == QtCore.Qt.SolidLine
|
||||
assert rect.pen().style() == QtCore.Qt.PenStyle.SolidLine
|
||||
|
||||
|
||||
def test_fromEmptySvg(project, controller):
|
||||
|
||||
@@ -46,7 +46,7 @@ def test_fromSvg(project, controller):
|
||||
font.setItalic(True)
|
||||
font.setStrikeOut(True)
|
||||
text.setFont(font)
|
||||
text.setDefaultTextColor(QtCore.Qt.red)
|
||||
text.setDefaultTextColor(QtCore.Qt.GlobalColor.red)
|
||||
text.setPlainText("Hello")
|
||||
|
||||
text2 = TextItem(project=project)
|
||||
|
||||
@@ -36,7 +36,7 @@ def network_manager(response):
|
||||
def response():
|
||||
response = unittest.mock.MagicMock()
|
||||
type(response).finished = unittest.mock.PropertyMock(return_value=FakeQtSignal())
|
||||
response.error.return_value = QtNetwork.QNetworkReply.NoError
|
||||
response.error.return_value = QtNetwork.QNetworkReply.NetworkError.NoError
|
||||
response.attribute.return_value = 200
|
||||
response.header.return_value = "application/json"
|
||||
return response
|
||||
@@ -115,7 +115,7 @@ def test_dataReadySlot(http_client):
|
||||
callback = unittest.mock.MagicMock()
|
||||
response = unittest.mock.MagicMock()
|
||||
response.header.return_value = "application/json"
|
||||
response.error.return_value = QtNetwork.QNetworkReply.NoError
|
||||
response.error.return_value = QtNetwork.QNetworkReply.NetworkError.NoError
|
||||
response.attribute.return_value = 200
|
||||
response.readAll.return_value = b'{"action": "ping"}'
|
||||
http_client._dataReadySlot(response, callback, {"query_id": "bla"})
|
||||
@@ -130,7 +130,7 @@ def test_dataReadySlotHTTPError(http_client):
|
||||
callback = unittest.mock.MagicMock()
|
||||
response = unittest.mock.MagicMock()
|
||||
response.header.return_value = "application/json"
|
||||
response.error.return_value = QtNetwork.QNetworkReply.NoError
|
||||
response.error.return_value = QtNetwork.QNetworkReply.NetworkError.NoError
|
||||
response.attribute.return_value = 404
|
||||
http_client._dataReadySlot(response, callback, {"query_id": "bla"})
|
||||
assert not callback.called
|
||||
@@ -141,7 +141,7 @@ def test_dataReadySlotConnectionRefusedError(http_client):
|
||||
callback = unittest.mock.MagicMock()
|
||||
response = unittest.mock.MagicMock()
|
||||
response.header.return_value = "application/json"
|
||||
response.error.return_value = QtNetwork.QNetworkReply.ConnectionRefusedError
|
||||
response.error.return_value = QtNetwork.QNetworkReply.NetworkError.ConnectionRefusedError
|
||||
response.attribute.return_value = 200
|
||||
http_client._dataReadySlot(response, callback, {"query_id": "bla"})
|
||||
assert not callback.called
|
||||
@@ -155,7 +155,7 @@ def test_dataReadySlotPartialJSON(http_client):
|
||||
response = unittest.mock.MagicMock()
|
||||
response.header.return_value = "application/json"
|
||||
response.readAll.return_value = b'{"action": "ping"'
|
||||
response.error.return_value = QtNetwork.QNetworkReply.NoError
|
||||
response.error.return_value = QtNetwork.QNetworkReply.NetworkError.NoError
|
||||
response.attribute.return_value = 200
|
||||
http_client._dataReadySlot(response, callback, {"query_id": "bla"})
|
||||
assert not callback.called
|
||||
@@ -172,7 +172,7 @@ def test_dataReadySlotPartialBytes(http_client):
|
||||
response = unittest.mock.MagicMock()
|
||||
response.header.return_value = "application/octet-stream"
|
||||
response.readAll.return_value = b'hello'
|
||||
response.error.return_value = QtNetwork.QNetworkReply.NoError
|
||||
response.error.return_value = QtNetwork.QNetworkReply.NetworkError.NoError
|
||||
response.attribute.return_value = 200
|
||||
|
||||
http_client._dataReadySlot(response, callback, {"query_id": "bla"})
|
||||
|
||||
Reference in New Issue
Block a user