class Installer(QObject): setProgress = pyqtSignal(int) def __init__(self, options, schema, firer): QObject.__init__(self) if not hasattr(options, 'install_path') or not hasattr(options, 'distrib_path'): QMessageBox.warning(firer, u'Error', u'Incorrect options') firer.setEnabled(False) return self.schema = schema self.options = options self.firer = firer self.wizard = QWizard() self.wizard.setOptions(QWizard.NoBackButtonOnStartPage | QWizard.NoBackButtonOnLastPage) self.wizard.resize(800, 600) self.wizard.schema = schema self.unwizard = QWizard() self.unwizard.setOptions(QWizard.NoBackButtonOnStartPage | QWizard.NoBackButtonOnLastPage) self.unwizard.resize(800, 600) self.unwizard.schema = schema self.pip = self.PreInstallPage(self) self.cp = self.CheckPage(self) self.ip = self.InstallPage(self) self.puip = self.PreUnInstallPage(self) self.uip = self.UnInstallPage(self) self.wizard.addPage(self.pip) self.wizard.addPage(self.cp) self.wizard.addPage(self.ip) self.unwizard.addPage(self.puip) self.unwizard.addPage(self.uip) def install(self): self.wizard.setModal(True) self.wizard.show() def uninstall(self): self.unwizard.setModal(True) self.unwizard.show() class PreInstallPage(QWizardPage): def __init__(self, parent): QWizardPage.__init__(self) self.parent = parent self.setLayout(QGridLayout()) self.setTitle('Options') self.setSubTitle('Please select destination folder and folder which contains downloaded files.') self.path = PathPanel(default=self.parent.options.install_path) self.layout().addWidget(QLabel('Installation path:'), 1, 0) self.layout().addWidget(self.path, 1, 1) self.distrib_path = PathPanel(default=self.parent.options.distrib_path) self.layout().addWidget(QLabel('Downloaded files:'), 2, 0) self.layout().addWidget(self.distrib_path, 2, 1) self.registerField('path', self.path, 'getPath', self.path.path_input.textChanged) self.registerField('distrib_path', self.distrib_path, 'getPath', self.distrib_path.path_input.textChanged) self.path.updated.connect(self.changed) self.distrib_path.updated.connect(self.changed) def initializePage(self): self.path.setPath(self.parent.options.install_path) self.distrib_path.setPath(self.parent.options.distrib_path) def changed(self): self.completeChanged.emit() def isComplete(self): return os.path.isdir(self.path.getPath) and os.path.isdir(self.distrib_path.getPath) class CheckPage(QWizardPage): setProgress = pyqtSignal(int) addComponentItem = pyqtSignal(object, str, bool, bool) editComponentItem = pyqtSignal(str, str) def __init__(self, parent): QWizardPage.__init__(self) self.parent = parent self.setLayout(QGridLayout()) self.setTitle('Components') self.setSubTitle('Please select components which will be extracted to your destination folder.') self.status_label = QLabel() self.layout().addWidget(self.status_label, 1, 0) self.components_list = QListWidget() self.progress = QProgressBar() self.layout().addWidget(self.progress, 2, 0, 1, 4) self.layout().addWidget(self.components_list, 3, 0, 1, 4) addcomponent_button = QPushButton(u'Add component') addcomponent_button.setEnabled(False) self.layout().addWidget(addcomponent_button, 4, 0) self.is_done = False self.addComponentItem.connect(self.addListItem) self.setProgress.connect(self.progress.setValue) self.components_list.itemChanged.connect(self.completeChanged.emit) self.components_list.itemClicked.connect(self.completeChanged.emit) self.registerField('components', self, 'getComponents', self.components_list.itemClicked) def initializePage(self): self.components = [] self.distrib_path = str(self.field('distrib_path').toString()) self.status_label.setText('Search components in %s...' % self.distrib_path) self.components_list.clear() self.progress.setMaximum(0) self.startSearchComponents() def startSearchComponents(self): self.w = Worker(lambda: self.searchComponent(self.distrib_path)) self.w.done.connect(self.endSearchComponents) self.w.error.connect(self.parent.printError) self.w.start() def endSearchComponents(self): self.status_label.setText('Found components in %s' % self.distrib_path) self.is_done = True self.completeChanged.emit() def isComplete(self): self.wizard().components = self.getComponents return self.is_done and len(self.getComponents) @pyqtProperty(list) def getComponents(self): components = [] for item in self.getSelectedItems(): if item.component.available: components.append(item.component) return components def getSelectedItems(self): list_widget = self.components_list items = [] for i in range(list_widget.count()): item = list_widget.item(i) if item.checkState() == Qt.Checked: items.append(item) return items def addListItem(self, component, title, valid=True, checked=True): item = QListWidgetItem(title) item.component = component item.setFlags(item.flags() | Qt.ItemIsUserCheckable) if valid: pass else: item.setForeground(QColor('gray')) if checked: item.setCheckState(Qt.Checked) else: item.setCheckState(Qt.Unchecked) self.components_list.addItem(item) def searchComponent(self, distrib_path): self.setProgress.emit(0) self.progress.setMaximum(len(self.wizard().schema.components.keys())) for i, component_name in enumerate(self.wizard().schema.components.keys()): component = Component.create(component_name, distrib_path, self.wizard().schema.components[component_name]) self.setProgress.emit(i) if component is not None: self.addComponentItem.emit( component, component.title, component.available, component.default_install ) self.components.append(component) self.setProgress.emit(len(self.wizard().schema.components.keys())) class InstallPage(QWizardPage): setProgress = pyqtSignal(int) message = pyqtSignal(str) def __init__(self, parent): QWizardPage.__init__(self) self.parent = parent self.setLayout(QGridLayout()) self.setTitle('Installation') self.setSubTitle('All selected components will be extracted.') self.layout().addWidget(QLabel(u'Installation progress'), 0, 0) self.progress = QProgressBar() self.progress.setMaximum(0) self.layout().addWidget(self.progress, 1, 0, 1, 2) self.log = QTextBrowser() self.layout().addWidget(self.log, 2, 0, 1, 2) self.setProgress.connect(self.progress.setValue) self.message.connect(self.log.append) self.is_done = False def initializePage(self): self.components = self.wizard().components self.startInstallation() def startInstallation(self): self.distrib_path = str(self.field('distrib_path').toString()) self.path = str(self.field('path').toString()) self.w = Worker(lambda: self.install(self.distrib_path, self.path)) self.w.done.connect(self.endInstall) self.w.error.connect(self.parent.printError) self.w.start() def install(self, src, destination): self.message.emit(u'Started...') self.progress.setMaximum(len(self.components)) for i, component in enumerate(self.components): self.setProgress.emit(i) component.install(destination, message=self.message.emit) self.generateUninstallList(destination, src, self.components) def generateUninstallList(self, install_path, distrib_path, components): self.message.emit(u'Generating uninstall list...') with open('config/uninstall.yml', 'w') as f: l = '' for i, component in enumerate(components): file_list = {component.name: component.uninstall_info} l += yaml.dump(file_list, default_flow_style=False, indent=4, allow_unicode=True, encoding="utf-8") f.write(l) f.close() def endInstall(self): self.log.append(u'Finished') self.setProgress.emit(len(self.components)) self.is_done = True self.completeChanged.emit() def isComplete(self): if self.is_done: self.wizard().finished.emit(1) return self.is_done class PreUnInstallPage(QWizardPage): setProgress = pyqtSignal(int) addComponentItem = pyqtSignal(object, str, bool, bool) editComponentItem = pyqtSignal(str, str) def __init__(self, parent): QWizardPage.__init__(self) self.parent = parent self.setLayout(QGridLayout()) self.setTitle('Components') self.setSubTitle('This page cant handle manually installed components') self.components_list = QListWidget() self.progress = QProgressBar() self.layout().addWidget(self.progress, 2, 0, 1, 4) self.layout().addWidget(self.components_list, 3, 0, 1, 4) self.setProgress.connect(self.progress.setValue) self.is_done = False self.addComponentItem.connect(self.addListItem) self.setProgress.connect(self.progress.setValue) self.components_list.itemChanged.connect(self.completeChanged.emit) self.components_list.itemClicked.connect(self.completeChanged.emit) def initializePage(self): self.components = [] self.components_list.clear() schema = Config(open('config/uninstall.yml')) for component_name in schema.keys(): component = Component.create(component_name, None, schema[component_name]) if component is not None: self.addComponentItem.emit( component, component.title, True, component.default_uninstall ) self.components.append(component) self.is_done = True def isComplete(self): self.wizard().components = self.getComponents return self.is_done and len(self.wizard().components) @pyqtProperty(list) def getComponents(self): components = [] for item in self.getSelectedItems(): if item.component.available: components.append(item.component) return components def getSelectedItems(self): list_widget = self.components_list items = [] for i in range(list_widget.count()): item = list_widget.item(i) if item.checkState() == Qt.Checked: items.append(item) return items def addListItem(self, component, title, valid=True, checked=True): item = QListWidgetItem(title) item.component = component item.setFlags(item.flags() | Qt.ItemIsUserCheckable) if valid: pass else: item.setForeground(QColor('gray')) if checked: item.setCheckState(Qt.Checked) else: item.setCheckState(Qt.Unchecked) self.components_list.addItem(item) class UnInstallPage(QWizardPage): setProgress = pyqtSignal(int) message = pyqtSignal(str) def __init__(self, parent): QWizardPage.__init__(self) self.parent = parent self.setLayout(QGridLayout()) self.setTitle('Uninstallation') self.setSubTitle('All selected components will be removed.') self.layout().addWidget(QLabel(u'Uninstallation progress'), 0, 0) self.progress = QProgressBar() self.progress.setMaximum(0) self.layout().addWidget(self.progress, 1, 0, 1, 2) self.log = QTextBrowser() self.layout().addWidget(self.log, 2, 0, 1, 2) self.setProgress.connect(self.progress.setValue) self.message.connect(self.log.append) self.is_done = False def initializePage(self): self.components = self.wizard().components self.startUninstallation() def startUninstallation(self): self.path = str(self.parent.options.install_path) self.w = Worker(lambda: self.uninstall(self.path, self.components)) self.w.done.connect(self.endUninstall) self.w.error.connect(self.parent.printError) self.w.start() def uninstall(self, path, components): self.message.emit('Start uninstalling...') schema = Config(open('config/uninstall.yml')) self.progress.setMaximum(len(components)) component_names = [x.name for x in components] i = 0 for component in components: if component.name in component_names: i += 1 self.setProgress.emit(i) component.uninstall(schema[component.name], message=self.message.emit) def endUninstall(self): self.log.append(u'Finished') self.is_done = True self.completeChanged.emit() def isComplete(self): if self.is_done: self.wizard().finished.emit(1) return self.is_done def printError(self, e): print(e)