def _init_mods(self): p_dialog = dialogs.SplashProgress( parent=None, title=_("Computing data"), message=_("Please wait for the software to initialize it's data."), ) p_dialog.show() filehandler.build_game_files_crc32(p_dialog.progress) filehandler.build_loose_files_crc32(p_dialog.progress) self.managed_archives.build_archives_list(p_dialog.progress) p_dialog.progress("", category=_("Conflict detection")) filehandler.generate_conflicts_between_archives( self.managed_archives, progress=p_dialog.progress) self.managed_archives.initiate_conflicts_detection() item = None p_dialog.progress("", category=_("Parsing archives")) # HACK: pylint doesn't recognize aliased objects, which Typing's MutableMapping are. for archive_name in self.managed_archives.keys(): # pylint: disable=no-member p_dialog.progress(archive_name) item = ListRowItem(filename=archive_name, archive_manager=self.managed_archives) self.listWidget.addItem(item) self.managed_archives.diff_matched_with_loosefiles() self.listWidget.addItem(ListRowVirtualItem(self.managed_archives)) if item: self.listWidget.setCurrentItem(item) self.listWidget.scrollToItem(item) self.setup_schedulers() p_dialog.done(1)
def on_window_activate(self): if not self._ar_handler or not self._mod_handler: # handlers not init return False if (not self._wd_watchers[WatchDogSchedules.ARCHIVES] and self.autorefresh_checkbox.isChecked()): self._schedule_watchdog("archives") if self.is_mod_repo_dirty: logger.debug("Loose files are dirty, reparsing...") bucket.loosefiles = {} self.statusbar.showMessage(_("Refreshing loose files...")) filehandler.build_loose_files_crc32() if self.autorefresh_checkbox.isChecked(): self._schedule_watchdog("modules") logger.debug("Refreshing managed archives...") msg = " " msg.join([ self.statusbar.currentMessage(), _("Refreshing managed archive...") ]) self.statusbar.showMessage(msg) etype = None for etype, archive_name in self.managed_archives.refresh(): if etype == ArchiveEvents.FILE_ADDED: self.listWidget.addItem( ListRowItem(filename=archive_name, archive_manager=self.managed_archives)) if etype == ArchiveEvents.FILE_REMOVED: idx = self.get_row_index_by_name(archive_name) self._remove_row(archive_name, idx, preserve_managed=True) if etype or self.is_mod_repo_dirty: filehandler.generate_conflicts_between_archives( self.managed_archives) self.managed_archives.initiate_conflicts_detection() self.refresh_list_item_state() self._is_mod_repo_dirty = False msg = " " msg.join([self.statusbar.currentMessage(), _("Refresh done.")]) self.statusbar.showMessage(msg, 10000) return False
def _remove_row(self, filename: str, row: int, preserve_managed: bool = False): """Remove a row from the interface's list. The `filename` argument is only needed if `preserved_managed` is set to `False` (the default). It is needed to remove information stored in the `managed_archives` object. Will refresh the conflicting files once done. Args: filename: Only needed if preserve_managed is False row: integer matching the row to remove preserve_managed: if False, delete information from the managed_archives object """ if not preserve_managed: del self.managed_archives[filename] self.listWidget.takeItem(row) filehandler.generate_conflicts_between_archives(self.managed_archives)
def _do_uninstall_selected_mod(self, widgetslist=None): """Delete all the archive matched files from the filesystem. Will not process archives with known mismatch. """ if not widgetslist: # called from a non-contextual triggers widgetslist = self.listWidget.selectedItems() if not widgetslist: logger.error( "_do_uninstall_selected_mod called without selection.") return if isinstance(widgetslist, ListRowItem): widgetslist = [widgetslist] pd = QProgressDialog("Uninstalling mods...", "", 0, 100, parent=self) pd.setAutoClose(True) pd.setWindowModality(Qt.WindowModal) pd.setValue(pd.minimum()) step = int(100 / len(widgetslist)) # increase progress by `step` mismatched = [] failure = False self._do_enable_autorefresh(False) for item in widgetslist: if item.archive_instance.has_mismatched: mismatched.append(item.filename) continue logger.info("Uninstalling files from archive %s", item.filename) uninstall_status = filehandler.uninstall_files( item.archive_instance.uninstall_info(), pd, step) if not uninstall_status: failure = True pd.reset() self._do_enable_autorefresh(True) if mismatched: dialogs.q_information(_( "Some module couldn't be uninstalled, some of their files are mismatched.\n" "This is most likely due to another installed mod conflicting " "or changes occurred on the drive outside of the control of this software." ), detailed="\n".join(mismatched)) sp = dialogs.SplashProgress( parent=None, title=_("Computing data"), message=_("Please wait for the software to initialize it's data."), ) sp.show() sp.category.setText(_("Conflict detection:")) filehandler.generate_conflicts_between_archives(self.managed_archives, progress=sp.progress) self.refresh_list_item_state() self.on_selection_change() sp.done(1) if failure: dialogs.q_warning( _("The uninstallation process failed at some point. Please report " "this happened to the developper alongside with the error file " "{logfile}.").format(logfile=get_config_dir("error.log"))) return False return True
def _do_install_selected_mod(self, widgetslist=None): """Method to install an archive's files to the game location.""" if not widgetslist: # called from a non-contextual call widgetslist = self.listWidget.selectedItems() if not widgetslist: logger.error( "_do_install_selected_mod called without selection.") return if isinstance(widgetslist, ListRowItem): widgetslist = [widgetslist] self._do_enable_autorefresh(False) names = [item.filename for item in widgetslist] skipped, conflictors = [], [] changes = False p_dialog = dialogs.SplashProgress( parent=None, title=_("Installing modules"), message=_("Please wait for the software to initialize it's data."), ) p_dialog.show() for item in widgetslist: p_dialog.progress("Processing {}".format(item.filename)) if item.archive_instance.all_matching or item.archive_instance.empty: continue if item.archive_instance.has_matched: skipped.append(item.filename) continue if any(name in item.archive_instance.known_conflictors() for name in names): conflictors.append(item.filename) continue logger.info("Installing file %s", item.filename) files = filehandler.install_archive( item.filename, item.archive_instance.install_info()) if not files: dialogs.q_warning( _("The archive {filename} extracted with errors.\n" "Please refer to {loglocation} for more information."). format(filename=item.filename, loglocation=os.path.join(get_base_path(), "error.log"))) else: changes = True self._do_enable_autorefresh(True) if changes: p_dialog.category.setText(_("Recomputing conflicts:")) filehandler.generate_conflicts_between_archives( self.managed_archives, p_dialog.progress) self.refresh_list_item_state() else: dialogs.q_information( "You tried to install an archive, but the state of your game " "res/mods/ folder hasn't changed. This would indicate that your " "archive contains no recognized file able to be installed.") logger.warning( "Tried to install something, but no changes were made on the drive." ) p_dialog.done(1) if skipped: dialogs.q_information(_( "Some archives couldn't be installed during the process. " "Some of the files in those archives are already present " "on the disk."), detailed="\n".join(skipped)) if conflictors: dialogs.q_information(_( "Some archives have conflicting files with each others and " "couldn't be installed alongside each other. You should " "selectively install one or manually resolve the " "problematic files."), detailed="\n".join(conflictors)) self.on_selection_change()