|
|
|
import logging
|
|
|
|
import os.path
|
|
|
|
import sys
|
|
|
|
from typing import Dict, List
|
|
|
|
|
|
|
|
from PyQt6 import QtWidgets
|
|
|
|
from PyQt6.QtCore import Qt
|
|
|
|
from PyQt6.QtGui import QStandardItemModel, QStandardItem
|
|
|
|
|
|
|
|
from window.mod_manager_window_export import Ui_MainWindow
|
|
|
|
|
|
|
|
|
|
|
|
class MainWindow(QtWidgets.QMainWindow):
|
|
|
|
|
|
|
|
def __init__(self, parent, parent_logger: logging.Logger, version: str = ""):
|
|
|
|
super(MainWindow, self).__init__()
|
|
|
|
self.parent = parent
|
|
|
|
self.__logger = logging.getLogger("MainWindow")
|
|
|
|
for handler in parent_logger.handlers:
|
|
|
|
self.__logger.addHandler(handler)
|
|
|
|
self.__logger.setLevel(parent_logger.level)
|
|
|
|
|
|
|
|
self.ui = Ui_MainWindow()
|
|
|
|
self.ui.setupUi(self)
|
|
|
|
|
|
|
|
self.setWindowTitle(f"LC Mod Manager {version}")
|
|
|
|
|
|
|
|
self.ui.actionAdd_new_mod.triggered.connect(self.on_action_add_new_mod)
|
|
|
|
self.ui.actionrefresh_mods.triggered.connect(self.on_action_refresh_mods)
|
|
|
|
self.ui.actionCheck_for_Updates.triggered.connect(self.on_action_check_for_updates)
|
|
|
|
self.ui.actionSet_game_folder.triggered.connect(self.on_action_set_game_folder)
|
|
|
|
self.ui.actionRemove_ALL_manager_files.triggered.connect(self.on_action_remove_all_files)
|
|
|
|
|
|
|
|
self.ui.DeleteModFilesButton.pressed.connect(self.on_pressed_delete_mod_files_button)
|
|
|
|
self.ui.ApplyChangesButton.pressed.connect(self.on_pressed_apply_changes_button)
|
|
|
|
self.ui.DisacrdChangesButton.pressed.connect(self.on_pressed_discard_changes_button)
|
|
|
|
|
|
|
|
self.ui.TODOButton.hide()
|
|
|
|
self.ui.ApplyChangesButton.hide()
|
|
|
|
self.ui.DisacrdChangesButton.hide()
|
|
|
|
self.ui.DeleteModFilesButton.hide()
|
|
|
|
|
|
|
|
self.ui.actionCheck_for_Updates.setDisabled(True)
|
|
|
|
|
|
|
|
def set_available_mods(self, available_mods: Dict[str, str]):
|
|
|
|
"""
|
|
|
|
Sets the given mods as the list of available mods
|
|
|
|
:param available_mods:
|
|
|
|
:return:
|
|
|
|
"""
|
|
|
|
item_model = QStandardItemModel(self.ui.AvailableModsList)
|
|
|
|
for mod_name in available_mods.keys():
|
|
|
|
item = QStandardItem(mod_name + f" ({available_mods[mod_name]['version']})")
|
|
|
|
item.setFlags(Qt.ItemFlag.ItemIsUserCheckable | Qt.ItemFlag.ItemIsEnabled)
|
|
|
|
item.setData(Qt.CheckState.Unchecked, Qt.ItemDataRole.CheckStateRole)
|
|
|
|
item.setData(mod_name, Qt.ItemDataRole.UserRole)
|
|
|
|
|
|
|
|
item_model.appendRow(item)
|
|
|
|
if self.parent.is_mod_installed(mod_name):
|
|
|
|
item.setCheckState(Qt.CheckState.Checked)
|
|
|
|
|
|
|
|
item_model.itemChanged.connect(self.on_available_mod_item_changed)
|
|
|
|
self.ui.AvailableModsList.setModel(item_model)
|
|
|
|
|
|
|
|
def set_installed_mods(self, installed_mods: Dict[str, str]):
|
|
|
|
"""
|
|
|
|
Sets the given mods as the list of installed mods
|
|
|
|
:param installed_mods: string list of all the mods as to be written to the list
|
|
|
|
:return:
|
|
|
|
"""
|
|
|
|
item_model = QStandardItemModel(self.ui.InstalledModsListView)
|
|
|
|
for mod_name in installed_mods.keys():
|
|
|
|
if mod_name in self.parent.available_mods.keys():
|
|
|
|
mod_version = self.parent.available_mods[mod_name]['version']
|
|
|
|
else:
|
|
|
|
mod_version = "Not Tracked"
|
|
|
|
item = QStandardItem(mod_name + f" ({mod_version})")
|
|
|
|
item.setFlags(Qt.ItemFlag.ItemIsUserCheckable | Qt.ItemFlag.ItemIsEnabled)
|
|
|
|
item.setData(Qt.CheckState.Unchecked, Qt.ItemDataRole.CheckStateRole)
|
|
|
|
item.setData(mod_name, Qt.ItemDataRole.UserRole)
|
|
|
|
|
|
|
|
item_model.appendRow(item)
|
|
|
|
item.setCheckState(Qt.CheckState.Checked)
|
|
|
|
|
|
|
|
item_model.itemChanged.connect(self.on_installed_mod_item_changed)
|
|
|
|
self.ui.InstalledModsListView.setModel(item_model)
|
|
|
|
|
|
|
|
# UI Callback functions
|
|
|
|
## Actions
|
|
|
|
def on_action_add_new_mod(self):
|
|
|
|
self.__logger.debug("Action: \"add new mod\" triggered!")
|
|
|
|
dialog = QtWidgets.QFileDialog(self, "Select Lethal Company mod")
|
|
|
|
dialog.setFileMode(QtWidgets.QFileDialog.FileMode.ExistingFiles)
|
|
|
|
|
|
|
|
result = dialog.getOpenFileName(filter='ZIP (*.zip)')
|
|
|
|
self.__logger.debug(f"user selected \"{result[0]}\"")
|
|
|
|
if not os.path.isfile(result[0]):
|
|
|
|
dialog = QtWidgets.QMessageBox()
|
|
|
|
dialog.setWindowTitle("Not a file")
|
|
|
|
dialog.setInformativeText(f"The given file \"{result}\" did not look like a file!")
|
|
|
|
dialog.setIcon(QtWidgets.QMessageBox.Icon.Warning)
|
|
|
|
dialog.exec()
|
|
|
|
if not self.parent.is_valid_mod_file(result[0]):
|
|
|
|
dialog = QtWidgets.QMessageBox()
|
|
|
|
dialog.setWindowTitle("Not a valid mod file")
|
|
|
|
dialog.setInformativeText(
|
|
|
|
f"The given file \"{result}\" did not look like a mod file. Is the manifest.json present?")
|
|
|
|
dialog.setIcon(QtWidgets.QMessageBox.Icon.Warning)
|
|
|
|
dialog.exec()
|
|
|
|
|
|
|
|
self.parent.add_mod_file(result[0])
|
|
|
|
|
|
|
|
def on_action_refresh_mods(self):
|
|
|
|
self.__logger.debug("Action: \"refresh mods\" triggered!")
|
|
|
|
self.parent.index_stored_mods()
|
|
|
|
self.parent.index_installed_mods()
|
|
|
|
|
|
|
|
def on_action_check_for_updates(self):
|
|
|
|
self.__logger.debug("Action: \"check for updates\" triggered!")
|
|
|
|
|
|
|
|
def on_action_set_game_folder(self):
|
|
|
|
self.__logger.debug("Action: \"set game folder\" triggered!")
|
|
|
|
dialog = QtWidgets.QFileDialog(self, "Select Lethal Company folder")
|
|
|
|
dialog.setFileMode(QtWidgets.QFileDialog.FileMode.Directory)
|
|
|
|
dialog.setOptions(QtWidgets.QFileDialog.Option.ShowDirsOnly)
|
|
|
|
|
|
|
|
result = dialog.getExistingDirectory()
|
|
|
|
dir_accepted = self.parent.set_game_folder(result)
|
|
|
|
|
|
|
|
attempt = 0
|
|
|
|
while not dir_accepted:
|
|
|
|
attempt += 1
|
|
|
|
dialog = QtWidgets.QMessageBox()
|
|
|
|
dialog.setWindowTitle("Invalid game path")
|
|
|
|
dialog.setInformativeText(f"The given path \"{result}\" did not look like the Lethal Company game folder!\n"
|
|
|
|
f"If you can't find it. Try using steam and select \"browse local files\"!")
|
|
|
|
dialog.setIcon(QtWidgets.QMessageBox.Icon.Warning)
|
|
|
|
dialog.exec()
|
|
|
|
|
|
|
|
dialog = QtWidgets.QFileDialog(self, "Select Lethal Company folder")
|
|
|
|
dialog.setFileMode(QtWidgets.QFileDialog.FileMode.Directory)
|
|
|
|
dialog.setOptions(QtWidgets.QFileDialog.Option.ShowDirsOnly)
|
|
|
|
|
|
|
|
result = dialog.getExistingDirectory()
|
|
|
|
dir_accepted = self.parent.set_game_folder(result)
|
|
|
|
if attempt > 2:
|
|
|
|
return
|
|
|
|
|
|
|
|
def on_action_remove_all_files(self):
|
|
|
|
self.__logger.debug("Action: \"remove all manager files\" triggered!")
|
|
|
|
self.parent.nuke_manager_files()
|
|
|
|
|
|
|
|
## Buttons
|
|
|
|
|
|
|
|
def on_pressed_delete_mod_files_button(self):
|
|
|
|
self.__logger.debug("Pressed button: \"Delete Mod Files\"")
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
def on_pressed_apply_changes_button(self):
|
|
|
|
self.__logger.debug("Pressed button: \"Apply Changes\"")
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
def on_pressed_discard_changes_button(self):
|
|
|
|
self.__logger.debug("Pressed button: \"Discard Changes\"")
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
def on_available_mod_item_changed(self, item: QStandardItem):
|
|
|
|
self.__logger.debug(f"Available Mod list item \"{item.text()}\" changed to {item.checkState()}")
|
|
|
|
mod_name = item.data(Qt.ItemDataRole.UserRole)
|
|
|
|
if item.checkState() == Qt.CheckState.Checked:
|
|
|
|
self.parent.install_mod(mod_name)
|
|
|
|
elif item.checkState() == Qt.CheckState.Unchecked:
|
|
|
|
self.parent.uninstall_mod(mod_name)
|
|
|
|
|
|
|
|
def on_installed_mod_item_changed(self, item: QStandardItem):
|
|
|
|
self.__logger.debug(f"Installed Mod list item \"{item.text()}\" changed to {item.checkState()}")
|
|
|
|
mod_name = item.data(Qt.ItemDataRole.UserRole)
|
|
|
|
if item.checkState() == Qt.CheckState.Unchecked: # mod should be uninstalled
|
|
|
|
accepted = QtWidgets.QMessageBox.question(self, "Really uninstall mod?",
|
|
|
|
f"Do you really want to uninstall the mod \"{mod_name}\"?\n"
|
|
|
|
"This could lead to permanent data loss if it wasn't tracked!")
|
|
|
|
if accepted:
|
|
|
|
self.parent.uninstall_mod(mod_name)
|
|
|
|
else:
|
|
|
|
return
|