Compare commits

...

29 Commits

Author SHA1 Message Date
grossmj
3527e5551c Release v2.2.42 2023-08-09 21:11:57 +10:00
grossmj
72960f8f2b Enable system certificate store later in the code and bump version to 2.2.42.dev4 2023-08-08 17:22:27 +10:00
grossmj
8abb502c72 Use the system's certificate store for SSL connections 2023-08-07 21:33:25 +10:00
grossmj
08c729e83a Upgrade dependencies 2023-08-06 20:39:27 +10:00
grossmj
aac004bd2f Use certifi to get SSL root certificates 2023-08-06 20:37:10 +10:00
grossmj
70677d8f18 Bump version to 2.2.42.dev3 2023-08-06 18:14:22 +10:00
Jeremy Grossmann
fba1ff4208 Merge pull request #3502 from GNS3/use-bundled-cacert
Use bundled cacert file for frozen app
2023-08-05 22:37:08 +10:00
grossmj
e4edbefc23 Use bundled cacert file on Windows and macOS 2023-08-05 22:21:08 +10:00
grossmj
d93f9afe74 Bump version to 2.2.42.dev2 2023-08-05 20:16:30 +10:00
grossmj
162d197e36 Give a node some time to start before opening the console (for console auto start). Fixes #3474 2023-08-02 11:08:58 +10:00
grossmj
5c21dd8a2f Merge branch 'master' into 2.2 2023-08-01 15:50:51 +10:00
Jeremy Grossmann
aa9b9d3b0b Merge pull request #3364 from AbdelbakiBoukerche/feature_rounded_rectangle
Rounded Rectangle
2023-08-01 15:46:32 +10:00
grossmj
eae9eec15b Support for horizontal and vertical corner radius 2023-08-01 15:34:30 +10:00
Jeremy Grossmann
a3bf832721 Merge branch 'master' into feature_rounded_rectangle 2023-07-31 18:34:50 +10:00
Jeremy Grossmann
67890d74d9 Merge pull request #3500 from GNS3/fix/3449
Support for gnome-terminal tabs to be opened in the same window
2023-07-31 18:30:22 +10:00
grossmj
ab4325f951 Remove warning to set open new terminals in tabs for gnome-terminal 2023-07-31 12:32:49 +10:00
grossmj
2a947b9cc5 Add comments for gnome-terminal special case 2023-07-31 01:44:39 +10:00
grossmj
601c082288 Use Mate Terminal by default if installed on Debian, Ubuntu and Linux Mint. 2023-07-31 01:40:20 +10:00
grossmj
7701d57bd0 Check that gnome-terminal is configured to open new terminals in tabs. 2023-07-31 01:34:59 +10:00
grossmj
f0b4148a20 Support for gnome-terminal tabs to be opened in the same window. 2023-07-30 22:15:38 +10:00
grossmj
2fdcbafbc1 Revert "Support for Python 3.12"
This reverts commit 5d82cea935.
2023-07-30 17:50:21 +10:00
grossmj
5d82cea935 Support for Python 3.12 2023-07-30 17:48:30 +10:00
grossmj
b0e3e93c41 Remove import urllib3 and let sentry_sdk import and patch it. Fixes https://github.com/GNS3/gns3-gui/issues/3498 2023-07-30 17:42:52 +10:00
grossmj
535f53737d Merge remote-tracking branch 'origin/master' into 2.2 2023-07-23 12:35:21 +10:00
Jeremy Grossmann
354f3eecec Merge pull request #3497 from kevinchevreuil/master
Add import sys in sudo.py
2023-07-23 12:04:29 +10:00
Kevin Chevreuil - Kaisen
35a6a5c8c7 Add import sys in sudo.py 2023-07-22 23:12:34 +02:00
grossmj
23cba0a28d Development on 2.2.42.dev1 2023-07-12 18:26:26 +10:00
Jeremy Grossmann
9c3d7bc95a Merge pull request #3495 from GNS3/release-v2.2.41
Release v2.2.41
2023-07-12 18:24:05 +10:00
Abdelbaki Boukerche
181bf3f360 Rounded Rectangle 2022-08-04 18:20:54 +01:00
17 changed files with 183 additions and 44 deletions

View File

@@ -1,5 +1,15 @@
# Change Log
## 2.2.42 09/08/2023
* Use the system's certificate store for SSL connections
* Give a node some time to start before opening the console (for console auto start). Fixes #3474
* Use Mate Terminal by default if installed on Debian, Ubuntu and Linux Mint.
* Support for gnome-terminal tabs to be opened in the same window.
* Remove import urllib3 and let sentry_sdk import and patch it. Fixes https://github.com/GNS3/gns3-gui/issues/3498
* Add import sys in sudo.py
* Rounded Rectangle support
## 2.2.41 12/07/2023
* Use alternative method to set the correct permissions for uBridge on macOS

View File

@@ -15,13 +15,6 @@
# 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 sys
import os
import platform
import struct
import distro
import urllib3
try:
import sentry_sdk
from sentry_sdk.integrations.logging import LoggingIntegration
@@ -30,7 +23,12 @@ except ImportError:
# Sentry SDK is not installed with deb package in order to simplify packaging
SENTRY_SDK_AVAILABLE = False
from .utils.get_resource import get_resource
import sys
import os
import platform
import struct
import distro
from .version import __version__, __version_info__
import logging
@@ -52,7 +50,7 @@ class CrashReport:
Report crash to a third party service
"""
DSN = "https://8e73913aea164a31a72e3a07fc455e26@o19455.ingest.sentry.io/38506"
DSN = "https://bae0411a1718612ee8c25cdb12ec7f02@o19455.ingest.sentry.io/38506"
_instance = None
def __init__(self):
@@ -65,24 +63,14 @@ class CrashReport:
self._sentry_initialized = False
if SENTRY_SDK_AVAILABLE:
cacert = None
if hasattr(sys, "frozen"):
cacert_resource = get_resource("cacert.pem")
if cacert_resource is not None and os.path.isfile(cacert_resource):
cacert = cacert_resource
else:
log.error("The SSL certificate bundle file '{}' could not be found".format(cacert_resource))
# Don't send log records as events.
sentry_logging = LoggingIntegration(level=logging.INFO, event_level=None)
try:
sentry_sdk.init(dsn=CrashReport.DSN,
release=__version__,
ca_certs=cacert,
default_integrations=False,
integrations=[sentry_logging])
except urllib3.exceptions.HTTPError as e:
except Exception as e:
log.error("Crash report could not be sent: {}".format(e))
return

View File

@@ -22,6 +22,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
from ..items.rectangle_item import RectangleItem
class StyleEditorDialog(QtWidgets.QDialog, Ui_StyleEditorDialog):
@@ -70,6 +71,13 @@ class StyleEditorDialog(QtWidgets.QDialog, Ui_StyleEditorDialog):
self._border_color.green(),
self._border_color.blue(),
self._border_color.alpha()))
if isinstance(first_item, RectangleItem):
# use the horizontal corner radius first and then the vertical one if it's not set
# maybe we allow configuring them separately in the future
corner_radius = first_item.horizontalCornerRadius()
if not corner_radius:
corner_radius = first_item.verticalCornerRadius()
self.uiCornerRadiusSpinBox.setValue(corner_radius)
self.uiRotationSpinBox.setValue(int(first_item.rotation()))
self.uiBorderWidthSpinBox.setValue(pen.width())
index = self.uiBorderStyleComboBox.findData(pen.style())
@@ -116,10 +124,16 @@ class StyleEditorDialog(QtWidgets.QDialog, Ui_StyleEditorDialog):
for item in self._items:
item.setPen(pen)
# on multiselection it's possible to select many type of items
# on multi-selection 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)
if isinstance(item, RectangleItem):
corner_radius = self.uiCornerRadiusSpinBox.value()
# use the corner radius for both horizontal (rx) and vertical (ry)
# maybe we support setting them separately in the future
item.setHorizontalCornerRadius(corner_radius)
item.setVerticalCornerRadius(corner_radius)
item.setRotation(self.uiRotationSpinBox.value())
def done(self, result):

View File

@@ -54,7 +54,9 @@ class StyleEditorDialogLink(QtWidgets.QDialog, Ui_StyleEditorDialog):
self.uiColorLabel.hide()
self.uiColorPushButton.hide()
self._color = None
self.uiCornerRadiusLabel.hide()
self.uiCornerRadiusSpinBox.hide()
self.uiRotationLabel.hide()
self.uiRotationSpinBox.hide()

View File

@@ -32,8 +32,22 @@ class RectangleItem(QtWidgets.QGraphicsRectItem, ShapeItem):
"""
def __init__(self, width=200, height=100, **kws):
self._rx = 0
self._ry = 0
super().__init__(width=width, height=height, **kws)
def setHorizontalCornerRadius(self, radius: int):
self._rx = radius
def horizontalCornerRadius(self):
return self._rx
def setVerticalCornerRadius(self, radius: int):
self._ry = radius
def verticalCornerRadius(self):
return self._ry
def paint(self, painter, option, widget=None):
"""
Paints the contents of an item in local coordinates.
@@ -43,7 +57,9 @@ class RectangleItem(QtWidgets.QGraphicsRectItem, ShapeItem):
:param widget: QWidget instance
"""
super().paint(painter, option, widget)
painter.setPen(self.pen())
painter.setBrush(self.brush())
painter.drawRoundedRect(self.rect(), self._rx, self._ry)
self.drawLayerInfo(painter)
def toSvg(self):
@@ -57,7 +73,27 @@ class RectangleItem(QtWidgets.QGraphicsRectItem, ShapeItem):
rect = ET.SubElement(svg, "rect")
rect.set("width", str(int(self.rect().width())))
rect.set("height", str(int(self.rect().height())))
if self._rx:
rect.set("rx", str(self._rx))
if self._ry:
rect.set("ry", str(self._ry))
rect = self._styleSvg(rect)
return ET.tostring(svg, encoding="utf-8").decode("utf-8")
def fromSvg(self, svg):
svg_elem = ET.fromstring(svg)
if len(svg_elem):
# handle horizontal corner radius and vertical corner radius (specific to rectangles)
rx = svg_elem[0].get("rx")
ry = svg_elem[0].get("ry")
if rx:
self._rx = int(rx)
elif ry:
self._rx = int(ry) # defaults to ry if it is specified
if ry:
self._ry = int(ry)
elif rx:
self._ry = int(rx) # defaults to rx if it is specified
super().fromSvg(svg)

View File

@@ -173,7 +173,7 @@ class ShapeItem(DrawingItem):
def fromSvg(self, svg):
"""
Import element informations from an SVG
Import element information from SVG
"""
svg = ET.fromstring(svg)
width = float(svg.get("width", self.rect().width()))

View File

@@ -60,12 +60,12 @@ from gns3.local_config import LocalConfig
from gns3.application import Application
from gns3.utils import parse_version
from gns3.dialogs.profile_select import ProfileSelectDialog
from gns3.version import __version__
import logging
log = logging.getLogger(__name__)
from gns3.version import __version__
def locale_check():
"""
@@ -135,6 +135,13 @@ def main():
if options.project:
options.project = os.path.abspath(options.project)
try:
import truststore
truststore.inject_into_ssl()
log.info("Using system certificate store for SSL connections")
except ImportError:
pass
if hasattr(sys, "frozen"):
# We add to the path where the OS search executable our binary location starting by GNS3
# packaged binary

View File

@@ -689,7 +689,8 @@ class Node(BaseNode):
return
super().setStatus(status)
if status == self.started and "console_auto_start" in self.settings() and self.settings()["console_auto_start"]:
self.openConsole()
# give the node some time to start before opening the console
QtCore.QTimer.singleShot(1000, self.openConsole)
def openConsole(self, command=None, aux=False):
"""

View File

@@ -24,6 +24,7 @@ from ..qt import QtCore, QtWidgets, QtNetwork
from ..controller import Controller
from .config import Config, ConfigException
import logging
log = logging.getLogger(__name__)

View File

@@ -152,12 +152,12 @@ elif sys.platform.startswith("darwin"):
else:
PRECONFIGURED_TELNET_CONSOLE_COMMANDS = {'Xterm': 'xterm -T "%d" -e "telnet %h %p"',
'Putty': 'putty -telnet %h %p -title "%d" -sl 2500 -fg SALMON1 -bg BLACK',
'Gnome Terminal': 'gnome-terminal -t "%d" -e "telnet %h %p"',
'Gnome Terminal': 'gnome-terminal --tab -t "%d" -- telnet %h %p',
'Xfce4 Terminal': 'xfce4-terminal --tab -T "%d" -e "telnet %h %p"',
'ROXTerm': 'roxterm -n "%d" --tab -e "telnet %h %p"',
'KDE Konsole': 'konsole --new-tab -p tabtitle="%d" -e "telnet %h %p"',
'SecureCRT': 'SecureCRT /T /N "%d" /TELNET %h %p',
'Mate Terminal': 'mate-terminal --tab -e "telnet %h %p" -t "%d"',
'Mate Terminal': 'mate-terminal --tab -e "telnet %h %p" -t "%d"',
'terminator': 'terminator -e "telnet %h %p" -T "%d"',
'urxvt': 'urxvt -title %d -e telnet %h %p',
'kitty': 'kitty -T %d telnet %h %p'}
@@ -168,7 +168,10 @@ else:
if sys.platform.startswith("linux"):
distro_name = distro.name()
if distro_name == "Debian" or distro_name == "Ubuntu" or distro_name == "LinuxMint":
DEFAULT_TELNET_CONSOLE_COMMAND = PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Gnome Terminal"]
if shutil.which("mate-terminal"):
DEFAULT_TELNET_CONSOLE_COMMAND = PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Mate Terminal"]
else:
DEFAULT_TELNET_CONSOLE_COMMAND = PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Gnome Terminal"]
# Pre-configured VNC console commands on various OSes
if sys.platform.startswith("win"):

View File

@@ -25,6 +25,8 @@ import os
import sys
import shlex
import subprocess
import psutil
from .main_window import MainWindow
from .controller import Controller
@@ -34,6 +36,39 @@ log = logging.getLogger(__name__)
console_mutex = QtCore.QMutex()
def gnome_terminal_env():
uid = os.getuid()
# get list of processes of current user
procs = [p.info for p in psutil.process_iter(
attrs=['name', 'pid', 'ppid', 'create_time', 'uids']
) if p.info['uids'].real == uid]
# get pid of gnome-terminal-server process
gnome_terminal_server_pid = [p['pid'] for p in procs if p['name'] == "gnome-terminal-server"]
if not gnome_terminal_server_pid:
return {}
gnome_terminal_server_pid = gnome_terminal_server_pid[0]
# get subprocesses of gnome-terminal-server
gnome_terminal_server_children = [p for p in procs if p['ppid'] == gnome_terminal_server_pid]
gnome_terminal_server_children.sort(key=lambda p: p['create_time'], reverse=True)
# return the gnome-terminal environment variables of the first subprocess named telnet
for proc in gnome_terminal_server_children:
if proc['name'] == "telnet":
try:
env = psutil.Process(proc['pid']).environ()
if 'GNOME_TERMINAL_SERVICE' in env and \
'GNOME_TERMINAL_SCREEN' in env:
return {'GNOME_TERMINAL_SERVICE': env['GNOME_TERMINAL_SERVICE'],
'GNOME_TERMINAL_SCREEN': env['GNOME_TERMINAL_SCREEN']}
except psutil.Error:
pass
return {}
class ConsoleThread(QtCore.QThread):
consoleError = QtCore.pyqtSignal(str)
@@ -60,7 +95,14 @@ class ConsoleThread(QtCore.QThread):
except ValueError:
self.consoleError.emit("Syntax error in command: '{}'".format(command))
return
subprocess.call(args, env=os.environ)
env = os.environ.copy()
# special case to force gnome-terminal to correctly use tabs on Linux
if sys.platform.startswith("linux") and "gnome-terminal" in args[0] and "--tab" in command:
# inject gnome-terminal environment variables
if "GNOME_TERMINAL_SERVICE" not in env or "GNOME_TERMINAL_SCREEN" not in env:
env.update(gnome_terminal_env())
subprocess.call(args, env=env)
def run(self):

View File

@@ -2,6 +2,14 @@
<ui version="4.0">
<class>StyleEditorDialog</class>
<widget class="QDialog" name="StyleEditorDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>270</width>
<height>294</height>
</rect>
</property>
<property name="windowTitle">
<string>Style editor</string>
</property>
@@ -76,14 +84,14 @@
<item row="3" column="1">
<widget class="QComboBox" name="uiBorderStyleComboBox"/>
</item>
<item row="4" column="0">
<item row="5" column="0">
<widget class="QLabel" name="uiRotationLabel">
<property name="text">
<string>Rotation:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="5" column="1">
<widget class="QSpinBox" name="uiRotationSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@@ -106,6 +114,23 @@ editing (notes only) with ALT and '+' (or P) / ALT and '-' (or M)</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="uiCornerRadiusLabel">
<property name="text">
<string>Corner radius:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="uiCornerRadiusSpinBox">
<property name="suffix">
<string>°</string>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/style_editor_dialog.ui'
#
# Created by: PyQt5 UI code generator 5.15.2
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
@@ -14,6 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_StyleEditorDialog(object):
def setupUi(self, StyleEditorDialog):
StyleEditorDialog.setObjectName("StyleEditorDialog")
StyleEditorDialog.resize(270, 294)
StyleEditorDialog.setModal(True)
self.verticalLayout = QtWidgets.QVBoxLayout(StyleEditorDialog)
self.verticalLayout.setObjectName("verticalLayout")
@@ -52,7 +53,7 @@ class Ui_StyleEditorDialog(object):
self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.uiBorderStyleComboBox)
self.uiRotationLabel = QtWidgets.QLabel(self.uiStyleSettingsGroupBox)
self.uiRotationLabel.setObjectName("uiRotationLabel")
self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.uiRotationLabel)
self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.uiRotationLabel)
self.uiRotationSpinBox = QtWidgets.QSpinBox(self.uiStyleSettingsGroupBox)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
@@ -62,7 +63,14 @@ class Ui_StyleEditorDialog(object):
self.uiRotationSpinBox.setMinimum(-360)
self.uiRotationSpinBox.setMaximum(360)
self.uiRotationSpinBox.setObjectName("uiRotationSpinBox")
self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.uiRotationSpinBox)
self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.uiRotationSpinBox)
self.uiCornerRadiusLabel = QtWidgets.QLabel(self.uiStyleSettingsGroupBox)
self.uiCornerRadiusLabel.setObjectName("uiCornerRadiusLabel")
self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.uiCornerRadiusLabel)
self.uiCornerRadiusSpinBox = QtWidgets.QSpinBox(self.uiStyleSettingsGroupBox)
self.uiCornerRadiusSpinBox.setMaximum(100)
self.uiCornerRadiusSpinBox.setObjectName("uiCornerRadiusSpinBox")
self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.uiCornerRadiusSpinBox)
self.verticalLayout.addWidget(self.uiStyleSettingsGroupBox)
self.uiButtonBox = QtWidgets.QDialogButtonBox(StyleEditorDialog)
self.uiButtonBox.setOrientation(QtCore.Qt.Horizontal)
@@ -73,8 +81,8 @@ class Ui_StyleEditorDialog(object):
self.verticalLayout.addItem(spacerItem)
self.retranslateUi(StyleEditorDialog)
self.uiButtonBox.accepted.connect(StyleEditorDialog.accept)
self.uiButtonBox.rejected.connect(StyleEditorDialog.reject)
self.uiButtonBox.accepted.connect(StyleEditorDialog.accept) # type: ignore
self.uiButtonBox.rejected.connect(StyleEditorDialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(StyleEditorDialog)
def retranslateUi(self, StyleEditorDialog):
@@ -90,4 +98,6 @@ class Ui_StyleEditorDialog(object):
self.uiRotationSpinBox.setToolTip(_translate("StyleEditorDialog", "Rotation can be ajusted on the scene for a selected item while\n"
"editing (notes only) with ALT and \'+\' (or P) / ALT and \'-\' (or M)"))
self.uiRotationSpinBox.setSuffix(_translate("StyleEditorDialog", "°"))
self.uiCornerRadiusLabel.setText(_translate("StyleEditorDialog", "Corner radius:"))
self.uiCornerRadiusSpinBox.setSuffix(_translate("StyleEditorDialog", "°"))
from . import resources_rc

View File

@@ -24,7 +24,6 @@ import re
from gns3.utils import parse_version
from gns3 import version
from gns3.qt import QtNetwork, QtCore, QtWidgets, QtGui, qslot
from gns3.local_config import LocalConfig

View File

@@ -17,6 +17,7 @@
import shlex
import subprocess
import sys
from gns3.qt import QtWidgets
from gns3.utils.progress_dialog import ProgressDialog

View File

@@ -23,9 +23,8 @@
# or negative for a release candidate or beta (after the base version
# number has been incremented)
__version__ = "2.2.41"
__version_info__ = (2, 2, 41, 0)
__version__ = "2.2.42"
__version_info__ = (2, 2, 42, 0)
if "dev" in __version__:
try:
import os

View File

@@ -1,7 +1,8 @@
jsonschema>=4.17.3,<4.18; python_version >= '3.7'
jsonschema==3.2.0; python_version < '3.7' # v3.2.0 is the last version to support Python 3.6
sentry-sdk==1.17.0,<1.18
psutil==5.9.4
sentry-sdk==1.29.2,<1.30
psutil==5.9.5
distro>=1.8.0
truststore>=0.7.0; python_version >= '3.10'
setuptools>=60.8.1; python_version >= '3.7'
setuptools==59.6.0; python_version < '3.7' # v59.6.0 is the last version to support Python 3.6