2022-03-02 10:36:16 +13:00
|
|
|
from logging import getLogger
|
|
|
|
|
|
|
|
from PyQt5.QtCore import Qt, QFileSystemWatcher
|
2023-01-25 02:36:27 +13:00
|
|
|
from PyQt5.QtGui import QFont
|
|
|
|
from PyQt5.QtWidgets import QGroupBox, QTableWidgetItem, QMessageBox, QPushButton, QHeaderView, QFrame
|
2022-03-02 10:36:16 +13:00
|
|
|
|
|
|
|
from rare.shared import LegendaryCoreSingleton
|
2022-03-30 11:51:23 +13:00
|
|
|
from rare.ui.components.tabs.settings.widgets.env_vars import Ui_EnvVars
|
2022-03-02 10:36:16 +13:00
|
|
|
from rare.utils import config_helper
|
2022-07-27 02:58:17 +12:00
|
|
|
from rare.utils.misc import icon
|
2022-03-02 10:36:16 +13:00
|
|
|
|
|
|
|
logger = getLogger("EnvVars")
|
|
|
|
|
|
|
|
|
|
|
|
class EnvVars(QGroupBox, Ui_EnvVars):
|
|
|
|
def __init__(self, parent):
|
|
|
|
super(EnvVars, self).__init__(parent=parent)
|
|
|
|
self.setupUi(self)
|
|
|
|
self.app_name = None
|
|
|
|
self.core = LegendaryCoreSingleton()
|
|
|
|
self.latest_item = None
|
2023-01-25 02:36:27 +13:00
|
|
|
self.list_of_readonly = [
|
|
|
|
"STEAM_COMPAT_DATA_PATH",
|
|
|
|
"STEAM_COMPAT_CLIENT_INSTALL_PATH",
|
|
|
|
"WINEPREFIX",
|
|
|
|
"DXVK_HUD",
|
|
|
|
"MANGOHUD_CONFIG",
|
|
|
|
]
|
2022-03-02 10:36:16 +13:00
|
|
|
self.warn_msg = self.tr("Readonly, please edit this via the appropriate setting above.")
|
|
|
|
self.setup_file_watcher()
|
|
|
|
self.env_vars_table.cellChanged.connect(self.update_env_vars)
|
|
|
|
self.env_vars_table.verticalHeader().sectionClicked.connect(self.remove_row)
|
2022-06-23 06:06:38 +12:00
|
|
|
|
2022-03-02 10:36:16 +13:00
|
|
|
# We use this function to keep an eye on the config.
|
|
|
|
# When the user uses for example the wineprefix settings, we need to update the table.
|
|
|
|
# With this function, when the config file changes, we update the table.
|
|
|
|
def setup_file_watcher(self):
|
2022-03-20 11:23:36 +13:00
|
|
|
self.config_file_watcher = QFileSystemWatcher([str(self.core.lgd.config_path)], self)
|
2022-03-02 10:36:16 +13:00
|
|
|
self.config_file_watcher.fileChanged.connect(self.import_env_vars)
|
2022-06-23 06:06:38 +12:00
|
|
|
|
2022-03-20 11:23:36 +13:00
|
|
|
def append_row(self):
|
|
|
|
# If the last row is not None, we insert a new one and set the correct icon.
|
|
|
|
row_count = self.env_vars_table.rowCount()
|
2022-03-20 12:04:14 +13:00
|
|
|
|
|
|
|
if row_count == 0:
|
|
|
|
self.env_vars_table.insertRow(0)
|
|
|
|
trash_icon = QTableWidgetItem()
|
2022-06-23 06:06:38 +12:00
|
|
|
trash_icon.setIcon(icon("mdi.delete", "ei.minus"))
|
2022-03-20 12:04:14 +13:00
|
|
|
self.env_vars_table.setVerticalHeaderItem(row_count, trash_icon)
|
|
|
|
return
|
|
|
|
|
2022-03-20 11:23:36 +13:00
|
|
|
last_item = self.env_vars_table.item(self.env_vars_table.rowCount() - 1, 0)
|
2022-03-20 12:04:14 +13:00
|
|
|
|
2022-03-20 11:23:36 +13:00
|
|
|
if last_item is not None:
|
|
|
|
self.env_vars_table.insertRow(row_count)
|
|
|
|
trash_icon = QTableWidgetItem()
|
2022-06-23 06:06:38 +12:00
|
|
|
trash_icon.setIcon(icon("mdi.delete", "ei.minus"))
|
2022-03-20 11:23:36 +13:00
|
|
|
self.env_vars_table.setVerticalHeaderItem(row_count, trash_icon)
|
2022-03-02 10:36:16 +13:00
|
|
|
|
|
|
|
def import_env_vars(self):
|
|
|
|
self.env_vars_table.blockSignals(True)
|
|
|
|
self.env_vars_table.clearContents()
|
|
|
|
|
|
|
|
# If the config file doesnt have an env var section, we just set RowCount to 1 and return.
|
|
|
|
if not self.core.lgd.config.has_section(f"{self.app_name}.env"):
|
|
|
|
self.env_vars_table.setRowCount(1)
|
|
|
|
trash_icon = QTableWidgetItem()
|
2022-06-23 06:06:38 +12:00
|
|
|
trash_icon.setIcon(icon("mdi.delete", "ei.minus"))
|
2022-03-02 10:36:16 +13:00
|
|
|
self.env_vars_table.setVerticalHeaderItem(0, trash_icon)
|
|
|
|
self.env_vars_table.blockSignals(False)
|
|
|
|
return
|
|
|
|
|
|
|
|
# We count how many keys we have and insert new lines
|
|
|
|
# (as many as we need).
|
|
|
|
self.env_vars_table.setRowCount(len(self.core.lgd.config[f"{self.app_name}.env"]) + 1)
|
|
|
|
|
|
|
|
# Each iteration we have to create a new QTableWidgetItem object,
|
|
|
|
# else we segfault. (For using the same object in multiple references.)
|
|
|
|
for i, (key, value) in enumerate(self.core.lgd.config[f"{self.app_name}.env"].items()):
|
|
|
|
trash_icon = QTableWidgetItem()
|
2022-06-23 06:06:38 +12:00
|
|
|
trash_icon.setIcon(icon("mdi.delete", "ei.minus"))
|
2022-03-02 10:36:16 +13:00
|
|
|
self.env_vars_table.setVerticalHeaderItem(i, trash_icon)
|
|
|
|
|
2023-01-25 02:36:27 +13:00
|
|
|
font = QFont("Monospace")
|
|
|
|
font.setStyleHint(QFont.Monospace)
|
|
|
|
|
2022-03-02 10:36:16 +13:00
|
|
|
key_item = QTableWidgetItem()
|
|
|
|
key_item.setText(key)
|
2023-01-25 02:36:27 +13:00
|
|
|
key_item.setFont(font)
|
2022-03-02 10:36:16 +13:00
|
|
|
self.env_vars_table.setItem(i, 0, key_item)
|
|
|
|
|
|
|
|
value_item = QTableWidgetItem()
|
2023-01-25 02:36:27 +13:00
|
|
|
value_item.setFont(font)
|
2022-03-02 10:36:16 +13:00
|
|
|
value_item.setText(value)
|
|
|
|
self.env_vars_table.setItem(i, 1, value_item)
|
|
|
|
if key in self.list_of_readonly:
|
|
|
|
key_item.setFlags(key_item.flags() ^ Qt.ItemIsEnabled)
|
|
|
|
key_item.setToolTip(self.warn_msg)
|
|
|
|
|
|
|
|
value_item.setFlags(value_item.flags() ^ Qt.ItemIsEnabled)
|
|
|
|
value_item.setToolTip(self.warn_msg)
|
|
|
|
|
|
|
|
trash_icon = QTableWidgetItem()
|
2022-06-23 06:06:38 +12:00
|
|
|
trash_icon.setIcon(icon("mdi.delete", "ei.minus"))
|
2022-03-02 10:36:16 +13:00
|
|
|
self.env_vars_table.setVerticalHeaderItem(self.env_vars_table.rowCount() - 1, trash_icon)
|
2023-01-25 02:36:27 +13:00
|
|
|
self.env_vars_table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
|
2022-03-02 10:36:16 +13:00
|
|
|
|
|
|
|
self.env_vars_table.blockSignals(False)
|
|
|
|
|
|
|
|
def update_env_vars(self, row, column):
|
2022-03-20 11:23:36 +13:00
|
|
|
self.config_file_watcher.removePath(str(self.core.lgd.config_path))
|
2022-03-02 10:36:16 +13:00
|
|
|
row_count = self.env_vars_table.rowCount()
|
|
|
|
key_item = self.env_vars_table.item(row, 0)
|
|
|
|
value_item = self.env_vars_table.item(row, 1)
|
|
|
|
|
2022-03-20 12:46:07 +13:00
|
|
|
if key_item is not None and not key_item.text():
|
2022-03-22 10:40:02 +13:00
|
|
|
try:
|
|
|
|
list_of_config_keys = list(self.core.lgd.config[f"{self.app_name}.env"].keys())
|
|
|
|
except KeyError:
|
|
|
|
list_of_config_keys = []
|
2022-03-21 09:42:51 +13:00
|
|
|
try:
|
|
|
|
config_helper.remove_option(f"{self.app_name}.env", list_of_config_keys[row])
|
|
|
|
except IndexError:
|
|
|
|
# Item hasnt been saved to the config yet.
|
|
|
|
pass
|
2022-03-20 12:46:07 +13:00
|
|
|
self.env_vars_table.removeRow(key_item.row())
|
2022-03-21 10:28:47 +13:00
|
|
|
self.append_row()
|
2022-03-20 12:46:07 +13:00
|
|
|
return
|
|
|
|
|
2022-03-02 10:36:16 +13:00
|
|
|
# get all config keys
|
|
|
|
try:
|
|
|
|
list_of_config_keys = list(self.core.lgd.config[f"{self.app_name}.env"].keys())
|
|
|
|
except KeyError:
|
|
|
|
list_of_config_keys = []
|
|
|
|
|
|
|
|
# get all table keys
|
|
|
|
list_of_keys_in_table = []
|
|
|
|
for i in range(row_count):
|
|
|
|
item = self.env_vars_table.item(i, 0)
|
|
|
|
if item:
|
|
|
|
list_of_keys_in_table.append(item.text())
|
|
|
|
|
|
|
|
missing_item = list(set(list_of_config_keys) - set(list_of_keys_in_table))
|
|
|
|
if len(missing_item) != 0:
|
|
|
|
config_helper.remove_option(f"{self.app_name}.env", missing_item[0])
|
|
|
|
|
|
|
|
# A env var always needs to have a key.
|
|
|
|
# If it's none, we return.
|
|
|
|
if key_item is None:
|
|
|
|
return
|
|
|
|
|
|
|
|
if key_item.text() in self.list_of_readonly:
|
|
|
|
error_dialog = QMessageBox()
|
|
|
|
error_dialog.setText(
|
|
|
|
self.tr("Please don't manually add this environment variable. Use the appropriate game setting above."))
|
|
|
|
error_dialog.exec()
|
|
|
|
key_item.setText("")
|
|
|
|
if value_item is not None:
|
|
|
|
value_item.setText("")
|
|
|
|
config_helper.remove_option(f"{self.app_name}.env", key_item.text())
|
|
|
|
return
|
|
|
|
|
|
|
|
if key_item.text():
|
|
|
|
if "=" in key_item.text():
|
|
|
|
error_dialog = QMessageBox()
|
|
|
|
error_dialog.setText(
|
|
|
|
self.tr("Please don't use an equal sign in an env var."))
|
|
|
|
error_dialog.exec()
|
2022-03-20 11:23:36 +13:00
|
|
|
self.env_vars_table.removeRow(row)
|
|
|
|
self.append_row()
|
2022-03-02 10:36:16 +13:00
|
|
|
return
|
|
|
|
|
|
|
|
if key_item.text() in list_of_config_keys and column == 0:
|
|
|
|
ask_user = QMessageBox()
|
|
|
|
ask_user.setText(
|
|
|
|
self.tr("The config already contains this environment variable."))
|
|
|
|
ask_user.setInformativeText(
|
|
|
|
self.tr("Do you want to keep the newer one or the older one?"))
|
|
|
|
|
|
|
|
ask_user.addButton(QPushButton("Keep the newer one"), QMessageBox.YesRole)
|
|
|
|
ask_user.addButton(QPushButton("Keep the older one"), QMessageBox.NoRole)
|
|
|
|
|
|
|
|
response = ask_user.exec()
|
|
|
|
|
|
|
|
if response == 0:
|
|
|
|
if value_item is not None:
|
|
|
|
config_helper.add_option(f"{self.app_name}.env", key_item.text(), value_item.text())
|
|
|
|
else:
|
|
|
|
config_helper.add_option(f"{self.app_name}.env", key_item.text(), "")
|
|
|
|
|
|
|
|
item_to_safe = self.env_vars_table.findItems(key_item.text(), Qt.MatchExactly)
|
|
|
|
|
|
|
|
# aznd:
|
|
|
|
# This is to fix an issue where the user updates a env var, thats above the older one.
|
|
|
|
# so say if you have two env vars:
|
|
|
|
# something = newkey
|
|
|
|
# yes = oldkey
|
|
|
|
# if the user updates the something key to yes, it would delete the wrong row,
|
|
|
|
# since item_to_safe[0] is the first search result. but we dont want to delete that,
|
|
|
|
# we want to delete the second result.
|
|
|
|
# we use this simple if check to find out which case we have.
|
|
|
|
if key_item.row() < item_to_safe[0].row():
|
|
|
|
self.env_vars_table.removeRow(item_to_safe[0].row())
|
|
|
|
elif key_item.row() > item_to_safe[0].row():
|
|
|
|
self.env_vars_table.removeRow(item_to_safe[0].row())
|
|
|
|
else:
|
|
|
|
self.env_vars_table.removeRow(item_to_safe[1].row())
|
|
|
|
|
2022-03-20 11:23:36 +13:00
|
|
|
self.append_row()
|
2022-03-02 10:36:16 +13:00
|
|
|
return
|
|
|
|
|
|
|
|
elif response == 1:
|
|
|
|
self.env_vars_table.removeRow(row)
|
2022-03-20 11:23:36 +13:00
|
|
|
self.append_row()
|
2022-03-02 10:36:16 +13:00
|
|
|
return
|
|
|
|
|
|
|
|
# When the value_item is None, we just use an empty string for the value.
|
|
|
|
if value_item is None:
|
|
|
|
if self.latest_item in list_of_config_keys:
|
|
|
|
config_helper.remove_option(f"{self.app_name}.env", self.latest_item)
|
|
|
|
config_helper.save_config()
|
|
|
|
|
|
|
|
config_helper.add_option(f"{self.app_name}.env", key_item.text(), "")
|
|
|
|
config_helper.save_config()
|
|
|
|
else:
|
|
|
|
if self.latest_item in list_of_config_keys:
|
|
|
|
config_helper.remove_option(f"{self.app_name}.env", self.latest_item)
|
|
|
|
config_helper.save_config()
|
|
|
|
|
|
|
|
config_helper.add_option(
|
|
|
|
f"{self.app_name}.env",
|
|
|
|
key_item.text(),
|
|
|
|
value_item.text()
|
|
|
|
)
|
|
|
|
config_helper.save_config()
|
|
|
|
|
2022-03-20 11:23:36 +13:00
|
|
|
self.append_row()
|
|
|
|
self.config_file_watcher.addPath(str(self.core.lgd.config_path))
|
2022-03-02 10:36:16 +13:00
|
|
|
|
|
|
|
def remove_row(self, index):
|
2022-03-20 11:23:36 +13:00
|
|
|
self.config_file_watcher.removePath(str(self.core.lgd.config_path))
|
2022-03-02 10:36:16 +13:00
|
|
|
key_item = self.env_vars_table.item(index, 0)
|
2022-03-20 11:23:36 +13:00
|
|
|
value_item = self.env_vars_table.item(index, 1)
|
|
|
|
|
2022-03-02 10:36:16 +13:00
|
|
|
if key_item is None:
|
2022-03-20 11:23:36 +13:00
|
|
|
if value_item is not None:
|
|
|
|
value_item.setText("")
|
2022-03-02 10:36:16 +13:00
|
|
|
return
|
|
|
|
|
|
|
|
# If the user tries to delete one of the readonly vars, we return immediately.
|
|
|
|
if key_item.text() in self.list_of_readonly:
|
|
|
|
return
|
|
|
|
|
|
|
|
if key_item is not None:
|
|
|
|
self.env_vars_table.removeRow(index)
|
|
|
|
try:
|
|
|
|
list_of_keys = []
|
|
|
|
for key in self.core.lgd.config[f"{self.app_name}.env"]:
|
|
|
|
list_of_keys.append(key)
|
|
|
|
config_helper.remove_option(f"{self.app_name}.env", list_of_keys[index])
|
|
|
|
except (KeyError, IndexError):
|
|
|
|
pass
|
2022-03-20 11:23:36 +13:00
|
|
|
self.config_file_watcher.addPath(str(self.core.lgd.config_path))
|
2022-03-02 10:36:16 +13:00
|
|
|
|
|
|
|
def check_if_item(self, item: QTableWidgetItem) -> bool:
|
|
|
|
item_to_check = self.env_vars_table.findItems(item.text(), Qt.MatchExactly)
|
|
|
|
if item_to_check[0].column() == 0:
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
|
|
def keyPressEvent(self, e):
|
|
|
|
if e.key() == Qt.Key_Delete or e.key() == Qt.Key_Backspace:
|
|
|
|
selected_items = self.env_vars_table.selectedItems()
|
2022-03-20 11:23:36 +13:00
|
|
|
|
|
|
|
if len(selected_items) == 0:
|
|
|
|
return
|
|
|
|
|
2022-03-02 10:36:16 +13:00
|
|
|
item_in_table = self.env_vars_table.findItems(selected_items[0].text(), Qt.MatchExactly)
|
|
|
|
|
|
|
|
# Our first selection is in column 0. So, we have to find out if the user
|
|
|
|
# only selected keys, or keys and values. we use the check_if_item func
|
|
|
|
if item_in_table[0].column() == 0:
|
|
|
|
which_index_to_use = 1
|
|
|
|
if len(selected_items) == 1:
|
|
|
|
which_index_to_use = 0
|
|
|
|
if self.check_if_item(selected_items[which_index_to_use]):
|
|
|
|
# User selected keys and values, so we skip the values
|
|
|
|
for i in selected_items[::2]:
|
2022-03-20 12:04:14 +13:00
|
|
|
if i:
|
|
|
|
config_helper.remove_option(f"{self.app_name}.env", i.text())
|
|
|
|
self.env_vars_table.removeRow(i.row())
|
|
|
|
self.append_row()
|
2022-06-23 06:06:38 +12:00
|
|
|
else:
|
2022-03-02 10:36:16 +13:00
|
|
|
# user only selected keys
|
|
|
|
for i in selected_items:
|
2022-03-20 12:04:14 +13:00
|
|
|
if i:
|
|
|
|
config_helper.remove_option(f"{self.app_name}.env", i.text())
|
|
|
|
self.env_vars_table.removeRow(i.row())
|
|
|
|
self.append_row()
|
2022-03-02 10:36:16 +13:00
|
|
|
|
|
|
|
# User only selected values, so we just set the text to ""
|
|
|
|
elif item_in_table[0].column() == 1:
|
|
|
|
[i.setText("") for i in selected_items]
|
|
|
|
|
|
|
|
elif e.key() == Qt.Key_Escape:
|
|
|
|
e.ignore()
|
|
|
|
|
|
|
|
def update_game(self, app_name):
|
|
|
|
self.app_name = app_name
|
|
|
|
self.import_env_vars()
|