Source code for spinetoolbox.widgets.settings_widget

######################################################################################################################
# Copyright (C) 2017-2020 Spine project consortium
# This file is part of Spine Toolbox.
# Spine Toolbox is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser 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 Lesser General
# Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
######################################################################################################################

"""
Widget for controlling user settings.

:author: P. Savolainen (VTT)
:date:   17.1.2018
"""

import os
from PySide2.QtWidgets import QWidget, QFileDialog, QMessageBox, QColorDialog
from PySide2.QtCore import Slot, Qt, QSize
from PySide2.QtGui import QPixmap
from ..config import DEFAULT_WORK_DIR, SETTINGS_SS
from ..graphics_items import Link
from ..widgets.kernel_editor import KernelEditor, find_python_kernels, find_julia_kernels
from spinetoolbox.widgets.notification import Notification
from spinetoolbox.helpers import select_python_interpreter, select_julia_executable, select_julia_project, \
    file_is_valid, dir_is_valid


[docs]class SettingsWidgetBase(QWidget): def __init__(self, qsettings): """Initialize class.""" # FIXME: setting the parent to toolbox causes the checkboxes in the # groupBox_general to not layout correctly, this might be caused elsewhere? from ..ui.settings import Ui_SettingsForm # pylint: disable=import-outside-toplevel super().__init__(parent=None) # Do not set parent. Uses own stylesheet. # Set up the ui from Qt Designer files self._qsettings = qsettings self.ui = Ui_SettingsForm() self.ui.setupUi(self) self.setWindowFlags(Qt.Window | Qt.CustomizeWindowHint) self.setStyleSheet(SETTINGS_SS) self.ui.pushButton_ok.setDefault(True) self._mouse_press_pos = None self._mouse_release_pos = None self._mouse_move_pos = None
[docs] def connect_signals(self): """Connect signals.""" self.ui.pushButton_ok.clicked.connect(self.save_and_close) self.ui.pushButton_cancel.clicked.connect(self.update_ui_and_close)
[docs] def keyPressEvent(self, e): """Close settings form when escape key is pressed. Args: e (QKeyEvent): Received key press event. """ if e.key() == Qt.Key_Escape: self.update_ui_and_close()
[docs] def mousePressEvent(self, e): """Save mouse position at the start of dragging. Args: e (QMouseEvent): Mouse event """ self._mouse_press_pos = e.globalPos() self._mouse_move_pos = e.globalPos() super().mousePressEvent(e)
[docs] def mouseReleaseEvent(self, e): """Save mouse position at the end of dragging. Args: e (QMouseEvent): Mouse event """ if self._mouse_press_pos is not None: self._mouse_release_pos = e.globalPos() moved = self._mouse_release_pos - self._mouse_press_pos if moved.manhattanLength() > 3: e.ignore() return
[docs] def mouseMoveEvent(self, e): """Moves the window when mouse button is pressed and mouse cursor is moved. Args: e (QMouseEvent): Mouse event """ currentpos = self.pos() globalpos = e.globalPos() if not self._mouse_move_pos: e.ignore() return diff = globalpos - self._mouse_move_pos newpos = currentpos + diff self.move(newpos) self._mouse_move_pos = globalpos
[docs] def update_ui(self):
"""Updates UI to reflect current settings. Called when the user choses to cancel their changes. Undoes all temporary UI changes that resulted from the user playing with certain settings."""
[docs] def save_settings(self):
"""Gets selections and saves them to persistent memory.""" @Slot(bool)
[docs] def update_ui_and_close(self, checked=False): """Updates UI to reflect current settings and close.""" self.update_ui() self.close()
@Slot(bool)
[docs] def save_and_close(self, checked=False): """Saves settings and close.""" self.save_settings() self.close()
[docs]class SpineDBEditorSettingsMixin:
[docs] def connect_signals(self): """Connect signals.""" super().connect_signals() self.ui.checkBox_show_cascading_relationships.clicked.connect(self.set_show_cascading_relationships)
@Slot(bool)
[docs] def set_show_cascading_relationships(self, checked=False): if not self._db_mngr: return for db_editor in self._db_mngr.db_editors: db_editor.set_show_cascading_relationships(checked)
[docs] def read_settings(self): """Read saved settings from app QSettings instance and update UI to display them.""" commit_at_exit = int(self._qsettings.value("appSettings/commitAtExit", defaultValue="1")) # tri-state sticky_selection = self._qsettings.value("appSettings/stickySelection", defaultValue="false") smooth_zoom = self._qsettings.value("appSettings/smoothEntityGraphZoom", defaultValue="false") smooth_rotation = self._qsettings.value("appSettings/smoothEntityGraphRotation", defaultValue="false") relationship_items_follow = self._qsettings.value("appSettings/relationshipItemsFollow", defaultValue="true") show_cascading_relationships = self._qsettings.value( "appSettings/showCascadingRelationships", defaultValue="true" ) if commit_at_exit == 0: # Not needed but makes the code more readable. self.ui.checkBox_commit_at_exit.setCheckState(Qt.Unchecked) elif commit_at_exit == 1: self.ui.checkBox_commit_at_exit.setCheckState(Qt.PartiallyChecked) else: # commit_at_exit == "2": self.ui.checkBox_commit_at_exit.setCheckState(Qt.Checked) self.ui.checkBox_object_tree_sticky_selection.setChecked(sticky_selection == "true") self.ui.checkBox_smooth_entity_graph_zoom.setChecked(smooth_zoom == "true") self.ui.checkBox_smooth_entity_graph_rotation.setChecked(smooth_rotation == "true") self.ui.checkBox_relationship_items_follow.setChecked(relationship_items_follow == "true") self.ui.checkBox_show_cascading_relationships.setChecked(show_cascading_relationships == "true")
[docs] def save_settings(self): """Get selections and save them to persistent memory.""" super().save_settings() commit_at_exit = str(int(self.ui.checkBox_commit_at_exit.checkState())) self._qsettings.setValue("appSettings/commitAtExit", commit_at_exit) sticky_selection = "true" if int(self.ui.checkBox_object_tree_sticky_selection.checkState()) else "false" self._qsettings.setValue("appSettings/stickySelection", sticky_selection) smooth_zoom = "true" if int(self.ui.checkBox_smooth_entity_graph_zoom.checkState()) else "false" self._qsettings.setValue("appSettings/smoothEntityGraphZoom", smooth_zoom) smooth_rotation = "true" if int(self.ui.checkBox_smooth_entity_graph_rotation.checkState()) else "false" self._qsettings.setValue("appSettings/smoothEntityGraphRotation", smooth_rotation) relationship_items_follow = "true" if int(self.ui.checkBox_relationship_items_follow.checkState()) else "false" self._qsettings.setValue("appSettings/relationshipItemsFollow", relationship_items_follow) show_cascading_relationships = ( "true" if int(self.ui.checkBox_show_cascading_relationships.checkState()) else "false" ) self._qsettings.setValue("appSettings/showCascadingRelationships", show_cascading_relationships)
[docs] def update_ui(self): super().update_ui() show_cascading_relationships = ( self._qsettings.value("appSettings/showCascadingRelationships", defaultValue="true") == "true" ) self.set_show_cascading_relationships(show_cascading_relationships)
[docs]class SpineDBEditorSettingsWidget(SpineDBEditorSettingsMixin, SettingsWidgetBase): """A widget to change user's preferred settings, but only for the Spine db editor. """ def __init__(self, db_mngr): """Initialize class.""" super().__init__(db_mngr.qsettings) self._db_mngr = db_mngr self.ui.stackedWidget.setCurrentWidget(self.ui.SpineDBEditor) self.ui.listWidget.hide() self.connect_signals()
[docs] def show(self): super().show() self.read_settings()
[docs]class SettingsWidget(SpineDBEditorSettingsMixin, SettingsWidgetBase): """A widget to change user's preferred settings.""" def __init__(self, toolbox): """ Args: toolbox (ToolboxUI): Parent widget. """ super().__init__(toolbox.qsettings()) self._toolbox = toolbox # QWidget parent self._project = self._toolbox.project() self._db_mngr = self._project.db_mngr if self._project else None self.orig_work_dir = "" # Work dir when this widget was opened self._kernel_editor = None # Initial scene bg color. Is overridden immediately in read_settings() if it exists in qSettings self.bg_color = self._toolbox.ui.graphicsView.scene().bg_color for item in self.ui.listWidget.findItems("*", Qt.MatchWildcard): item.setSizeHint(QSize(128, 44)) # Ensure this window gets garbage-collected when closed self.setAttribute(Qt.WA_DeleteOnClose) self.connect_signals() self.read_settings() self.read_project_settings()
[docs] def connect_signals(self): """Connect signals.""" super().connect_signals() self.ui.toolButton_browse_gams.clicked.connect(self.browse_gams_path) self.ui.toolButton_browse_julia.clicked.connect(self.browse_julia_button_clicked) self.ui.toolButton_browse_julia_project.clicked.connect(self.browse_julia_project_button_clicked) self.ui.toolButton_browse_python.clicked.connect(self.browse_python_button_clicked) self.ui.pushButton_open_kernel_editor_python.clicked.connect(self.show_python_kernel_editor) self.ui.pushButton_open_kernel_editor_julia.clicked.connect(self.show_julia_kernel_editor) self.ui.toolButton_browse_work.clicked.connect(self.browse_work_path) self.ui.toolButton_bg_color.clicked.connect(self.show_color_dialog) self.ui.radioButton_bg_grid.clicked.connect(self.update_scene_bg) self.ui.radioButton_bg_tree.clicked.connect(self.update_scene_bg) self.ui.radioButton_bg_solid.clicked.connect(self.update_scene_bg) self.ui.checkBox_use_curved_links.clicked.connect(self.update_links_geometry) self.ui.radioButton_use_julia_executable.clicked.connect(self.toggle_julia_execution_mode) self.ui.radioButton_use_julia_console.clicked.connect(self.toggle_julia_execution_mode) self.ui.radioButton_use_python_interpreter.clicked.connect(self.toggle_python_execution_mode) self.ui.radioButton_use_python_console.clicked.connect(self.toggle_python_execution_mode)
@Slot(bool)
[docs] def browse_gams_path(self, checked=False): """Open file browser where user can select a GAMS program.""" # noinspection PyCallByClass, PyArgumentList answer = QFileDialog.getOpenFileName( self, "Select GAMS Program (e.g. gams.exe on Windows)", os.path.abspath("C:\\") ) if answer[0] == "": # Canceled (american-english), cancelled (british-english) return # Check that it's not a directory if os.path.isdir(answer[0]): msg = "Please select a valid GAMS program (file) and not a directory" # noinspection PyCallByClass, PyArgumentList QMessageBox.warning(self, "Invalid GAMS Program", msg) return # Check that it's a file that actually exists if not os.path.exists(answer[0]): msg = "File {0} does not exist".format(answer[0]) # noinspection PyCallByClass, PyArgumentList QMessageBox.warning(self, "Invalid GAMS Program", msg) return # Check that selected file at least starts with string 'gams' _, selected_file = os.path.split(answer[0]) if not selected_file.lower().startswith("gams"): msg = "Selected file <b>{0}</b> may not be a valid GAMS program".format(selected_file) # noinspection PyCallByClass, PyArgumentList QMessageBox.warning(self, "Invalid GAMS Program", msg) return self.ui.lineEdit_gams_path.setText(answer[0]) return
@Slot(bool)
[docs] def browse_julia_button_clicked(self, checked=False): """Calls static method that shows a file browser for selecting the Julia path.""" select_julia_executable(self, self.ui.lineEdit_julia_path)
@Slot(bool)
[docs] def browse_julia_project_button_clicked(self, checked=False): """Calls static method that shows a file browser for selecting a Julia project.""" select_julia_project(self, self.ui.lineEdit_julia_project_path)
@Slot(bool)
[docs] def browse_python_button_clicked(self, checked=False): """Calls static method that shows a file browser for selecting Python interpreter.""" select_python_interpreter(self, self.ui.lineEdit_python_path)
@Slot(bool)
[docs] def show_python_kernel_editor(self, checked=False): """Opens kernel editor, where user can make a kernel for the Python Console.""" p = self.ui.lineEdit_python_path.text() # This may be an empty string j = self.ui.lineEdit_julia_path.text() current_kernel = self.ui.comboBox_python_kernel.currentText() self._kernel_editor = KernelEditor(self, p, j, "python", current_kernel) self._kernel_editor.finished.connect(self.python_kernel_editor_closed) self._kernel_editor.open()
@Slot(int)
[docs] def python_kernel_editor_closed(self, ret_code): """Catches the selected Python kernel name when the editor is closed.""" previous_python_kernel = self.ui.comboBox_python_kernel.currentText() self.ui.comboBox_python_kernel.clear() python_kernel_cb_items = ["Select Python kernel..."] + [*find_python_kernels().keys()] self.ui.comboBox_python_kernel.addItems(python_kernel_cb_items) if ret_code != 1: # Editor closed with something else than clicking Ok. # Set previous kernel selected in Python kernel combobox if it still exists python_kernel_index = self.ui.comboBox_python_kernel.findText(previous_python_kernel) if python_kernel_index == -1: self.ui.comboBox_python_kernel.setCurrentIndex(0) # Previous not found else: self.ui.comboBox_python_kernel.setCurrentIndex(python_kernel_index) return new_kernel = self._kernel_editor.selected_kernel index = self.ui.comboBox_python_kernel.findText(new_kernel) if index == -1: # New kernel not found, should be quite exceptional notification = Notification(self, f"Python kernel {new_kernel} not found") notification.show() self.ui.comboBox_python_kernel.setCurrentIndex(0) else: self.ui.comboBox_python_kernel.setCurrentIndex(index)
@Slot(bool)
[docs] def show_julia_kernel_editor(self, checked=False): """Opens kernel editor, where user can make a kernel the Julia Console.""" p = self.ui.lineEdit_python_path.text() # This may be an empty string j = self.ui.lineEdit_julia_path.text() current_kernel = self.ui.comboBox_julia_kernel.currentText() self._kernel_editor = KernelEditor(self, p, j, "julia", current_kernel) self._kernel_editor.finished.connect(self.julia_kernel_editor_closed) self._kernel_editor.open()
@Slot(int)
[docs] def julia_kernel_editor_closed(self, ret_code): """Catches the selected Julia kernel name when the editor is closed.""" previous_julia_kernel = self.ui.comboBox_julia_kernel.currentText() self.ui.comboBox_julia_kernel.clear() julia_kernel_cb_items = ["Select Julia kernel..."] + [*find_julia_kernels().keys()] self.ui.comboBox_julia_kernel.addItems(julia_kernel_cb_items) if ret_code != 1: # Editor closed with something else than clicking Ok. # Set previous kernel selected in combobox if it still exists previous_kernel_index = self.ui.comboBox_julia_kernel.findText(previous_julia_kernel) if previous_kernel_index == -1: self.ui.comboBox_julia_kernel.setCurrentIndex(0) else: self.ui.comboBox_julia_kernel.setCurrentIndex(previous_kernel_index) return new_kernel = self._kernel_editor.selected_kernel index = self.ui.comboBox_julia_kernel.findText(new_kernel) if index == -1: notification = Notification(self, f"Julia kernel {new_kernel} not found") notification.show() self.ui.comboBox_julia_kernel.setCurrentIndex(0) else: self.ui.comboBox_julia_kernel.setCurrentIndex(index)
@Slot(bool)
[docs] def browse_work_path(self, checked=False): """Open file browser where user can select the path to wanted work directory.""" # noinspection PyCallByClass, PyTypeChecker, PyArgumentList answer = QFileDialog.getExistingDirectory(self, "Select Work Directory", os.path.abspath("C:\\")) if answer == '': # Cancel button clicked return selected_path = os.path.abspath(answer) self.ui.lineEdit_work_dir.setText(selected_path)
@Slot(bool)
[docs] def show_color_dialog(self, checked=False): """Let user pick the bg color. Args: checked (boolean): Value emitted with clicked signal """ # noinspection PyArgumentList color = QColorDialog.getColor(initial=self.bg_color) if not color.isValid(): return # Canceled self.bg_color = color self.update_bg_color()
[docs] def update_bg_color(self): """Set tool button icon as the selected color and update Design View scene background color.""" pixmap = QPixmap(16, 16) pixmap.fill(self.bg_color) self.ui.toolButton_bg_color.setIcon(pixmap) self._toolbox.ui.graphicsView.scene().set_bg_color(self.bg_color) self._toolbox.ui.graphicsView.scene().update()
@Slot(bool)
[docs] def update_scene_bg(self, checked=False): """Draw background on scene depending on radiobutton states. Args: checked (boolean): Toggle state """ if self.ui.radioButton_bg_grid.isChecked(): self._toolbox.ui.graphicsView.scene().set_bg_choice("grid") elif self.ui.radioButton_bg_tree.isChecked(): self._toolbox.ui.graphicsView.scene().set_bg_choice("tree") elif self.ui.radioButton_bg_solid.isChecked(): self._toolbox.ui.graphicsView.scene().set_bg_choice("solid") self._toolbox.ui.graphicsView.scene().update()
@Slot(bool) @Slot(bool)
[docs] def toggle_julia_execution_mode(self, checked=False): """Toggles between console and non-console Julia execution modes depending on radiobutton states. Args: checked (boolean): Toggle state """ console_enabled = True if self.ui.radioButton_use_julia_executable.isChecked(): console_enabled = False elif self.ui.radioButton_use_julia_console.isChecked(): console_enabled = True self.ui.comboBox_julia_kernel.setEnabled(console_enabled) self.ui.lineEdit_julia_path.setEnabled(not console_enabled) self.ui.lineEdit_julia_project_path.setEnabled(not console_enabled) self.ui.toolButton_browse_julia.setEnabled(not console_enabled) self.ui.toolButton_browse_julia_project.setEnabled(not console_enabled)
@Slot(bool)
[docs] def toggle_python_execution_mode(self, checked=False): """Toggles between console and non-console Python execution modes depending on radiobutton states. Args: checked (boolean): Toggle state """ console_enabled = True if self.ui.radioButton_use_python_interpreter.isChecked(): console_enabled = False elif self.ui.radioButton_use_python_console.isChecked(): console_enabled = True self.ui.comboBox_python_kernel.setEnabled(console_enabled) self.ui.lineEdit_python_path.setEnabled(not console_enabled) self.ui.toolButton_browse_python.setEnabled(not console_enabled)
[docs] def read_settings(self): """Read saved settings from app QSettings instance and update UI to display them.""" # checkBox check state 0: unchecked, 1: partially checked, 2: checked # QSettings value() method returns a str even if a boolean was stored super().read_settings() open_previous_project = int(self._qsettings.value("appSettings/openPreviousProject", defaultValue="0")) show_exit_prompt = int(self._qsettings.value("appSettings/showExitPrompt", defaultValue="2")) save_at_exit = int(self._qsettings.value("appSettings/saveAtExit", defaultValue="1")) # tri-state datetime = int(self._qsettings.value("appSettings/dateTime", defaultValue="2")) delete_data = int(self._qsettings.value("appSettings/deleteData", defaultValue="0")) smooth_zoom = self._qsettings.value("appSettings/smoothZoom", defaultValue="false") curved_links = self._qsettings.value("appSettings/curvedLinks", defaultValue="false") data_flow_anim_dur = int(self._qsettings.value("appSettings/dataFlowAnimationDuration", defaultValue="100")) bg_choice = self._qsettings.value("appSettings/bgChoice", defaultValue="solid") bg_color = self._qsettings.value("appSettings/bgColor", defaultValue="false") gams_path = self._qsettings.value("appSettings/gamsPath", defaultValue="") use_embedded_julia = int(self._qsettings.value("appSettings/useEmbeddedJulia", defaultValue="2")) julia_path = self._qsettings.value("appSettings/juliaPath", defaultValue="") julia_project_path = self._qsettings.value("appSettings/juliaProjectPath", defaultValue="") julia_kernel = self._qsettings.value("appSettings/juliaKernel", defaultValue="") use_embedded_python = int(self._qsettings.value("appSettings/useEmbeddedPython", defaultValue="2")) python_path = self._qsettings.value("appSettings/pythonPath", defaultValue="") python_kernel = self._qsettings.value("appSettings/pythonKernel", defaultValue="") work_dir = self._qsettings.value("appSettings/workDir", defaultValue="") if open_previous_project == 2: self.ui.checkBox_open_previous_project.setCheckState(Qt.Checked) if show_exit_prompt == 2: self.ui.checkBox_exit_prompt.setCheckState(Qt.Checked) if save_at_exit == 0: # Not needed but makes the code more readable. self.ui.checkBox_save_at_exit.setCheckState(Qt.Unchecked) elif save_at_exit == 1: self.ui.checkBox_save_at_exit.setCheckState(Qt.PartiallyChecked) else: # save_at_exit == 2: self.ui.checkBox_save_at_exit.setCheckState(Qt.Checked) if datetime == 2: self.ui.checkBox_datetime.setCheckState(Qt.Checked) if delete_data == 2: self.ui.checkBox_delete_data.setCheckState(Qt.Checked) if smooth_zoom == "true": self.ui.checkBox_use_smooth_zoom.setCheckState(Qt.Checked) if curved_links == "true": self.ui.checkBox_use_curved_links.setCheckState(Qt.Checked) self.ui.horizontalSlider_data_flow_animation_duration.setValue(data_flow_anim_dur) if bg_choice == "grid": self.ui.radioButton_bg_grid.setChecked(True) elif bg_choice == "tree": self.ui.radioButton_bg_tree.setChecked(True) else: self.ui.radioButton_bg_solid.setChecked(True) if bg_color == "false": pass else: self.bg_color = bg_color self.update_bg_color() self.ui.lineEdit_gams_path.setText(gams_path) # Add Python and Julia kernels to comboBoxes julia_kernel_cb_items = ["Select Julia kernel..."] + [*find_julia_kernels().keys()] # Unpack to list literal self.ui.comboBox_julia_kernel.addItems(julia_kernel_cb_items) python_kernel_cb_items = ["Select Python kernel..."] + [*find_python_kernels().keys()] self.ui.comboBox_python_kernel.addItems(python_kernel_cb_items) if use_embedded_julia == 2: self.ui.radioButton_use_julia_console.setChecked(True) else: self.ui.radioButton_use_python_interpreter.setChecked(True) self.toggle_julia_execution_mode() self.ui.lineEdit_julia_path.setText(julia_path) self.ui.lineEdit_julia_project_path.setText(julia_project_path) ind = self.ui.comboBox_julia_kernel.findText(julia_kernel) if ind == -1: self.ui.comboBox_julia_kernel.setCurrentIndex(0) else: self.ui.comboBox_julia_kernel.setCurrentIndex(ind) if use_embedded_python == 2: self.ui.radioButton_use_python_console.setChecked(True) else: self.ui.radioButton_use_python_interpreter.setChecked(True) self.toggle_python_execution_mode() self.ui.lineEdit_python_path.setText(python_path) ind = self.ui.comboBox_python_kernel.findText(python_kernel) if ind == -1: self.ui.comboBox_python_kernel.setCurrentIndex(0) else: self.ui.comboBox_python_kernel.setCurrentIndex(ind) self.ui.lineEdit_work_dir.setText(work_dir) self.orig_work_dir = work_dir
[docs] def read_project_settings(self): """Get project name and description and update widgets accordingly.""" if self._project: self.ui.lineEdit_project_name.setText(self._project.name) self.ui.textEdit_project_description.setText(self._project.description)
@Slot()
[docs] def save_settings(self): """Get selections and save them to persistent memory. Note: On Linux, True and False are saved as boolean values into QSettings. On Windows, booleans and integers are saved as strings. To make it consistent, we should use strings. """ # checkBox check state 0: unchecked, 1: partially checked, 2: checked # checkBox check states are casted from integers to string because of Linux super().save_settings() open_prev_proj = str(int(self.ui.checkBox_open_previous_project.checkState())) self._qsettings.setValue("appSettings/openPreviousProject", open_prev_proj) exit_prompt = str(int(self.ui.checkBox_exit_prompt.checkState())) self._qsettings.setValue("appSettings/showExitPrompt", exit_prompt) save_at_exit = str(int(self.ui.checkBox_save_at_exit.checkState())) self._qsettings.setValue("appSettings/saveAtExit", save_at_exit) datetime = str(int(self.ui.checkBox_datetime.checkState())) self._qsettings.setValue("appSettings/dateTime", datetime) delete_data = str(int(self.ui.checkBox_delete_data.checkState())) self._qsettings.setValue("appSettings/deleteData", delete_data) smooth_zoom = "true" if int(self.ui.checkBox_use_smooth_zoom.checkState()) else "false" self._qsettings.setValue("appSettings/smoothZoom", smooth_zoom) curved_links = "true" if int(self.ui.checkBox_use_curved_links.checkState()) else "false" self._qsettings.setValue("appSettings/curvedLinks", curved_links) data_flow_anim_dur = str(self.ui.horizontalSlider_data_flow_animation_duration.value()) self._qsettings.setValue("appSettings/dataFlowAnimationDuration", data_flow_anim_dur) if self.ui.radioButton_bg_grid.isChecked(): bg_choice = "grid" elif self.ui.radioButton_bg_tree.isChecked(): bg_choice = "tree" else: bg_choice = "solid" self._qsettings.setValue("appSettings/bgChoice", bg_choice) self._qsettings.setValue("appSettings/bgColor", self.bg_color) # GAMS gams_path = self.ui.lineEdit_gams_path.text().strip() # Check gams_path is a file, it exists, and file name starts with 'gams' if not file_is_valid(self, gams_path, "Invalid GAMS Program", extra_check="gams"): return self._qsettings.setValue("appSettings/gamsPath", gams_path) # Julia (str because Linux) use_emb_julia = "2" if self.ui.radioButton_use_julia_console.isChecked() else "0" self._qsettings.setValue("appSettings/useEmbeddedJulia", use_emb_julia) julia_path = self.ui.lineEdit_julia_path.text().strip() # Check julia_path is a file, it exists, and file name starts with 'julia' if not file_is_valid(self, julia_path, "Invalid Julia Executable", extra_check="julia"): return self._qsettings.setValue("appSettings/juliaPath", julia_path) julia_project_path = self.ui.lineEdit_julia_project_path.text().strip() if not dir_is_valid(self, julia_project_path, "Invalid Julia Project"): # Check it's a directory and it exists return self._qsettings.setValue("appSettings/juliaProjectPath", julia_project_path) if self.ui.comboBox_julia_kernel.currentIndex() == 0: julia_kernel = "" else: julia_kernel = self.ui.comboBox_julia_kernel.currentText() self._qsettings.setValue("appSettings/juliaKernel", julia_kernel) # Python use_emb_python = "2" if self.ui.radioButton_use_python_console.isChecked() else "0" self._qsettings.setValue("appSettings/useEmbeddedPython", use_emb_python) python_path = self.ui.lineEdit_python_path.text().strip() # Check python_path is a file, it exists, and file name starts with 'python' if not file_is_valid(self, python_path, "Invalid Python Interpreter", extra_check="python"): return self._qsettings.setValue("appSettings/pythonPath", python_path) if self.ui.comboBox_python_kernel.currentIndex() == 0: python_kernel = "" else: python_kernel = self.ui.comboBox_python_kernel.currentText() self._qsettings.setValue("appSettings/pythonKernel", python_kernel) # Work directory work_dir = self.ui.lineEdit_work_dir.text().strip() self._qsettings.setValue("appSettings/workDir", work_dir) # Check if something in the app needs to be updated self._toolbox.show_datetime = self._toolbox.update_datetime() # Project self.update_project_settings()
[docs] def update_project_settings(self): """Update project name and description if these have been changed.""" if not self._project: return new_name = self.ui.lineEdit_project_name.text().strip() if self._project.name != new_name: # Change project name if new_name != "": self._project.call_set_name(new_name) if not self._project.description == self.ui.textEdit_project_description.toPlainText(): # Set new project description self._project.call_set_description(self.ui.textEdit_project_description.toPlainText())
[docs] def check_if_work_dir_changed(self, new_work_dir): """Checks if work directory was changed. Args: new_work_dir (str): Possibly a new work directory """ if self.orig_work_dir != new_work_dir: if not new_work_dir: # Happens when clearing the work dir line edit # This is here because I don't want to see this message every time app is started self._toolbox.msg.emit("Work directory is now <b>{0}</b>".format(DEFAULT_WORK_DIR)) self._toolbox.set_work_directory(new_work_dir)
[docs] def update_ui(self): super().update_ui() curved_links = self._qsettings.value("appSettings/curvedLinks", defaultValue="false") bg_choice = self._qsettings.value("appSettings/bgChoice", defaultValue="solid") bg_color = self._qsettings.value("appSettings/bgColor", defaultValue="false") self.update_links_geometry(curved_links == "true") if bg_choice == "grid": self.ui.radioButton_bg_grid.setChecked(True) elif bg_choice == "tree": self.ui.radioButton_bg_tree.setChecked(True) else: self.ui.radioButton_bg_solid.setChecked(True) self.update_scene_bg() if bg_color == "false": pass else: self.bg_color = bg_color self.update_bg_color()