2014-01-31 16:22:31 -07:00
|
|
|
# -*- 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/>.
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
Dialog to load module and built-in preference pages.
|
|
|
|
|
"""
|
|
|
|
|
|
2025-12-15 19:27:55 +08:00
|
|
|
from ..qt import QtGui, QtCore, QtWidgets
|
2014-06-20 14:30:52 -06:00
|
|
|
from ..ui.preferences_dialog_ui import Ui_PreferencesDialog
|
|
|
|
|
from ..pages.server_preferences_page import ServerPreferencesPage
|
|
|
|
|
from ..pages.general_preferences_page import GeneralPreferencesPage
|
2014-06-26 03:06:59 -06:00
|
|
|
from ..pages.packet_capture_preferences_page import PacketCapturePreferencesPage
|
2016-08-25 09:34:05 +02:00
|
|
|
from ..pages.gns3_vm_preferences_page import GNS3VMPreferencesPage
|
2014-06-20 14:30:52 -06:00
|
|
|
from ..modules import MODULES
|
2014-01-31 16:22:31 -07:00
|
|
|
|
2017-01-05 15:50:41 +01:00
|
|
|
import logging
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
2014-01-31 16:22:31 -07:00
|
|
|
|
2015-04-17 12:14:21 +02:00
|
|
|
class PreferencesDialog(QtWidgets.QDialog, Ui_PreferencesDialog):
|
2015-01-28 11:13:10 +01:00
|
|
|
|
2014-01-31 16:22:31 -07:00
|
|
|
"""
|
|
|
|
|
Preferences dialog implementation.
|
|
|
|
|
|
|
|
|
|
:param parent: parent widget
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, parent):
|
|
|
|
|
|
2015-04-17 12:14:21 +02:00
|
|
|
super().__init__(parent)
|
2015-12-02 12:18:07 +01:00
|
|
|
|
2014-01-31 16:22:31 -07:00
|
|
|
self.setupUi(self)
|
2017-04-10 11:42:13 +02:00
|
|
|
self._modified_pages = set()
|
2014-01-31 16:22:31 -07:00
|
|
|
|
2015-12-02 12:18:07 +01:00
|
|
|
# We adapt the max size to the screen resolution
|
2016-02-16 09:56:33 +01:00
|
|
|
# We need to manually do that otherwise on small screen the windows
|
2016-05-18 11:27:38 +02:00
|
|
|
# could be bigger than the screen instead of displaying scrollbars
|
2025-12-15 19:27:55 +08:00
|
|
|
geometry = QtGui.QGuiApplication.primaryScreen().geometry()
|
|
|
|
|
height = geometry.height() - 100
|
|
|
|
|
width = geometry.width() - 100
|
2016-02-16 09:56:33 +01:00
|
|
|
|
2016-05-05 18:56:54 -06:00
|
|
|
# 980 is the default width
|
|
|
|
|
if self.width() > width:
|
|
|
|
|
self.resize(width, self.height())
|
|
|
|
|
# 680 is the default height
|
|
|
|
|
if self.height() > height:
|
|
|
|
|
self.resize(self.width(), height)
|
2015-12-02 12:18:07 +01:00
|
|
|
|
2014-09-30 19:59:15 -06:00
|
|
|
self.uiTreeWidget.currentItemChanged.connect(self._showPreferencesPageSlot)
|
2025-12-14 18:19:47 +08:00
|
|
|
self._applyButton = self.uiButtonBox.button(QtWidgets.QDialogButtonBox.StandardButton.Apply)
|
2015-07-24 16:30:18 +02:00
|
|
|
self._applyButton.clicked.connect(self._applyPreferences)
|
|
|
|
|
self._applyButton.setEnabled(False)
|
|
|
|
|
self._applyButton.setStyleSheet("QPushButton:disabled {color: gray}")
|
2014-01-31 16:22:31 -07:00
|
|
|
self._items = []
|
|
|
|
|
self._loadPreferencePages()
|
|
|
|
|
|
|
|
|
|
# select the first available page
|
2014-09-30 19:59:15 -06:00
|
|
|
self.uiTreeWidget.setCurrentItem(self._items[0])
|
2014-01-31 16:22:31 -07:00
|
|
|
|
2016-03-27 12:16:05 -06:00
|
|
|
# set the maximum width based on the content of column 0
|
2016-04-29 18:56:16 -06:00
|
|
|
self.uiTreeWidget.setMaximumWidth(self.uiTreeWidget.sizeHintForColumn(0) + 10)
|
2016-03-27 12:16:05 -06:00
|
|
|
|
2025-12-15 19:27:55 +08:00
|
|
|
# Something has changed?
|
2016-08-26 14:34:25 +02:00
|
|
|
self._modified_pages = set()
|
2015-07-24 16:30:18 +02:00
|
|
|
|
2014-01-31 16:22:31 -07:00
|
|
|
def _loadPreferencePages(self):
|
|
|
|
|
"""
|
|
|
|
|
Loads all preference pages (built-ins and from modules).
|
|
|
|
|
"""
|
|
|
|
|
|
2014-06-26 03:06:59 -06:00
|
|
|
# load built-in preference pages
|
|
|
|
|
pages = [
|
|
|
|
|
GeneralPreferencesPage,
|
|
|
|
|
ServerPreferencesPage,
|
2016-08-25 09:34:05 +02:00
|
|
|
GNS3VMPreferencesPage,
|
2014-06-26 03:06:59 -06:00
|
|
|
PacketCapturePreferencesPage,
|
|
|
|
|
]
|
2014-02-27 21:45:56 -07:00
|
|
|
|
2014-06-26 03:06:59 -06:00
|
|
|
for page in pages:
|
2015-03-06 13:43:49 -07:00
|
|
|
preferences_page = page(self)
|
2014-06-26 03:06:59 -06:00
|
|
|
preferences_page.loadPreferences()
|
|
|
|
|
name = preferences_page.windowTitle()
|
2015-04-17 12:14:21 +02:00
|
|
|
item = QtWidgets.QTreeWidgetItem(self.uiTreeWidget)
|
2014-09-30 19:59:15 -06:00
|
|
|
item.setText(0, name)
|
2025-12-14 18:19:47 +08:00
|
|
|
item.setData(0, QtCore.Qt.ItemDataRole.UserRole, preferences_page)
|
2014-06-26 03:06:59 -06:00
|
|
|
self.uiStackedWidget.addWidget(preferences_page)
|
|
|
|
|
self._items.append(item)
|
2015-07-24 16:30:18 +02:00
|
|
|
self._watchForChanges(preferences_page)
|
2014-01-31 16:22:31 -07:00
|
|
|
|
2014-03-11 16:44:37 -06:00
|
|
|
# load module preference pages
|
|
|
|
|
for module in MODULES:
|
2014-09-30 19:59:15 -06:00
|
|
|
preference_pages = module.preferencePages()
|
|
|
|
|
parent = self.uiTreeWidget
|
|
|
|
|
for cls in preference_pages:
|
2014-03-11 16:44:37 -06:00
|
|
|
preferences_page = cls()
|
2017-04-07 11:06:51 +02:00
|
|
|
preferences_page.setParent(self)
|
2014-03-11 16:44:37 -06:00
|
|
|
preferences_page.loadPreferences()
|
|
|
|
|
name = preferences_page.windowTitle()
|
2015-04-17 12:14:21 +02:00
|
|
|
item = QtWidgets.QTreeWidgetItem(parent)
|
2014-09-30 19:59:15 -06:00
|
|
|
item.setText(0, name)
|
2025-12-14 18:19:47 +08:00
|
|
|
item.setData(0, QtCore.Qt.ItemDataRole.UserRole, preferences_page)
|
2014-03-11 16:44:37 -06:00
|
|
|
self.uiStackedWidget.addWidget(preferences_page)
|
|
|
|
|
self._items.append(item)
|
2014-09-30 19:59:15 -06:00
|
|
|
if cls is preference_pages[0]:
|
|
|
|
|
parent = item
|
2015-07-24 16:30:18 +02:00
|
|
|
self._watchForChanges(preferences_page)
|
2014-01-31 16:22:31 -07:00
|
|
|
|
2014-11-02 10:10:13 -07:00
|
|
|
# expand all items by default
|
|
|
|
|
self.uiTreeWidget.expandAll()
|
|
|
|
|
|
2015-07-24 16:30:18 +02:00
|
|
|
def _watchForChanges(self, preferences_page):
|
|
|
|
|
"""
|
|
|
|
|
Connect all the widget of a page to check if something has change
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
# Class name, changed signal
|
|
|
|
|
widget_to_watch = {
|
2019-08-02 17:23:31 -02:30
|
|
|
QtWidgets.QLineEdit: "textChanged",
|
2016-11-21 18:16:02 +01:00
|
|
|
QtWidgets.QPlainTextEdit: "textChanged",
|
2016-09-07 10:22:45 +02:00
|
|
|
# QtWidgets.QTreeWidget: "itemChanged",
|
2022-04-20 16:49:22 +07:00
|
|
|
QtWidgets.QTreeWidget: "itemDoubleClicked",
|
2015-07-24 16:30:18 +02:00
|
|
|
QtWidgets.QComboBox: "currentIndexChanged",
|
|
|
|
|
QtWidgets.QSpinBox: "valueChanged",
|
2015-08-07 11:42:48 +02:00
|
|
|
QtWidgets.QAbstractButton: "pressed"
|
2015-07-24 16:30:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for widget, signal in widget_to_watch.items():
|
|
|
|
|
for children in preferences_page.findChildren(widget):
|
|
|
|
|
getattr(children, signal).connect(self._preferenceChangeSlot)
|
|
|
|
|
|
|
|
|
|
def _preferenceChangeSlot(self, *args):
|
|
|
|
|
"""
|
2016-08-26 14:34:25 +02:00
|
|
|
Called when something change in the preference dialog
|
2015-07-24 16:30:18 +02:00
|
|
|
"""
|
2016-08-26 14:34:25 +02:00
|
|
|
|
|
|
|
|
# Found the page with the change
|
2017-01-05 15:50:41 +01:00
|
|
|
widget = sender = self.sender()
|
2016-08-26 14:34:25 +02:00
|
|
|
while widget.parent() != self.uiStackedWidget:
|
|
|
|
|
widget = widget.parent()
|
|
|
|
|
|
2017-01-05 15:50:41 +01:00
|
|
|
if self.addModifiedPage(widget):
|
|
|
|
|
log.debug("%s value has changed", sender.objectName())
|
2016-09-07 10:22:45 +02:00
|
|
|
|
|
|
|
|
def addModifiedPage(self, widget):
|
2017-01-05 15:50:41 +01:00
|
|
|
"""
|
|
|
|
|
:returns: True is the page is initialized and element added
|
|
|
|
|
"""
|
2016-08-26 15:02:36 +02:00
|
|
|
# The widget can trigger signal before the end of init due to async api call
|
|
|
|
|
if not hasattr(widget, 'pageInitialized') or widget.pageInitialized():
|
|
|
|
|
self._applyButton.setEnabled(True)
|
|
|
|
|
self._modified_pages.add(widget)
|
2017-01-05 15:50:41 +01:00
|
|
|
return True
|
|
|
|
|
return False
|
2015-07-24 16:30:18 +02:00
|
|
|
|
2014-01-31 16:22:31 -07:00
|
|
|
def _showPreferencesPageSlot(self, current, previous):
|
|
|
|
|
"""
|
|
|
|
|
Shows a preference page in the current dialog.
|
|
|
|
|
|
|
|
|
|
:param current: current preference page widget
|
|
|
|
|
:param previous: ignored
|
|
|
|
|
"""
|
|
|
|
|
|
2014-09-30 19:59:15 -06:00
|
|
|
if current is None:
|
2014-01-31 16:22:31 -07:00
|
|
|
current = previous
|
|
|
|
|
|
2025-12-14 18:19:47 +08:00
|
|
|
preferences_page = current.data(0, QtCore.Qt.ItemDataRole.UserRole)
|
2015-03-11 22:08:31 -06:00
|
|
|
accessible_name = preferences_page.accessibleName()
|
|
|
|
|
if accessible_name:
|
|
|
|
|
self.uiTitleLabel.setText(accessible_name)
|
|
|
|
|
else:
|
|
|
|
|
name = preferences_page.windowTitle()
|
|
|
|
|
self.uiTitleLabel.setText("{} preferences".format(name))
|
2014-01-31 16:22:31 -07:00
|
|
|
index = self.uiStackedWidget.indexOf(preferences_page)
|
|
|
|
|
widget = self.uiStackedWidget.widget(index)
|
2019-03-13 15:46:41 +07:00
|
|
|
#self.uiStackedWidget.setMinimumSize(widget.size()) # FIXME: this seems to not work on Windows and OSX
|
|
|
|
|
#self.uiStackedWidget.resize(widget.size())
|
2014-01-31 16:22:31 -07:00
|
|
|
self.uiStackedWidget.setCurrentIndex(index)
|
|
|
|
|
|
2019-03-13 15:46:41 +07:00
|
|
|
for index in range(0, self.uiStackedWidget.count()):
|
|
|
|
|
page = self.uiStackedWidget.widget(index)
|
|
|
|
|
if self.uiStackedWidget.currentIndex() == index:
|
2025-12-14 18:19:47 +08:00
|
|
|
page.setSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
|
2019-03-13 15:46:41 +07:00
|
|
|
else:
|
2025-12-14 18:19:47 +08:00
|
|
|
page.setSizePolicy(QtWidgets.QSizePolicy.Policy.Ignored, QtWidgets.QSizePolicy.Policy.Ignored)
|
2019-03-13 15:46:41 +07:00
|
|
|
|
2014-01-31 16:22:31 -07:00
|
|
|
def _applyPreferences(self):
|
|
|
|
|
"""
|
|
|
|
|
Saves all the preferences.
|
|
|
|
|
"""
|
|
|
|
|
|
2014-05-15 19:39:01 +02:00
|
|
|
success = True
|
2017-03-21 15:13:49 +01:00
|
|
|
for preferences_page in list(self._modified_pages):
|
2014-05-15 19:39:01 +02:00
|
|
|
ok = preferences_page.savePreferences()
|
|
|
|
|
# if page.savePreferences() returns None, assume success
|
|
|
|
|
if ok is not None and not ok:
|
|
|
|
|
success = False
|
2015-07-24 16:30:18 +02:00
|
|
|
if success:
|
|
|
|
|
self._applyButton.setEnabled(False)
|
2016-08-26 14:34:25 +02:00
|
|
|
self._modified_pages = set()
|
2014-05-15 19:39:01 +02:00
|
|
|
return success
|
2014-01-31 16:22:31 -07:00
|
|
|
|
|
|
|
|
def reject(self):
|
|
|
|
|
"""
|
|
|
|
|
Closes this dialog.
|
|
|
|
|
"""
|
|
|
|
|
|
2016-08-26 14:34:25 +02:00
|
|
|
if len(self._modified_pages) > 0:
|
|
|
|
|
# Get the title of pages with modifications
|
2016-09-07 10:22:45 +02:00
|
|
|
pages_title = ', '.join([page.windowTitle() for page in self._modified_pages])
|
2015-07-24 16:30:18 +02:00
|
|
|
reply = QtWidgets.QMessageBox.warning(self,
|
2015-11-09 12:39:14 +01:00
|
|
|
"Preferences",
|
2016-08-26 14:34:25 +02:00
|
|
|
"You have unsaved preferences in {}.\n\nContinue without saving?".format(pages_title),
|
2025-12-14 18:19:47 +08:00
|
|
|
QtWidgets.QMessageBox.StandardButton.Yes,
|
|
|
|
|
QtWidgets.QMessageBox.StandardButton.No)
|
|
|
|
|
if reply == QtWidgets.QMessageBox.StandardButton.No:
|
2015-07-24 16:30:18 +02:00
|
|
|
return
|
2015-04-17 12:14:21 +02:00
|
|
|
QtWidgets.QDialog.reject(self)
|
2014-01-31 16:22:31 -07:00
|
|
|
|
|
|
|
|
def accept(self):
|
|
|
|
|
"""
|
|
|
|
|
Saves the preferences and closes this dialog.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
if self._applyPreferences():
|
2015-04-17 12:14:21 +02:00
|
|
|
QtWidgets.QDialog.accept(self)
|