def sessionOpened(self): if self.networkSession is not None: config = self.networkSession.configuration() if config.type() == QNetworkConfiguration.UserChoice: id = self.networkSession.sessionProperty('UserChoiceConfiguration') else: id = config.identifier() settings = QSettings(QSettings.UserScope, 'QtProject') settings.beginGroup('QtNetwork') settings.setValue('DefaultNetworkConfiguration', id) settings.endGroup(); self.tcpServer = QTcpServer(self) if not self.tcpServer.listen(): QMessageBox.critical(self, "Fortune Server", "Unable to start the server: %s." % self.tcpServer.errorString()) self.close() return for ipAddress in QNetworkInterface.allAddresses(): if ipAddress != QHostAddress.LocalHost and ipAddress.toIPv4Address() != 0: break else: ipAddress = QHostAddress(QHostAddress.LocalHost) ipAddress = ipAddress.toString() self.statusLabel.setText("The server is running on\n\nIP: %s\nport %d\n\n" "Run the Fortune Client example now." % (ipAddress, self.tcpServer.serverPort()))
class CookieJar(QNetworkCookieJar): def __init__(self): super(CookieJar, self).__init__() cookie_location = os.path.join(QStandardPaths.writableLocation(QStandardPaths.DataLocation) ,'cookies.ini') self.cookie_store = QSettings(cookie_location, QSettings.IniFormat) self.load() def load(self): data = self.cookie_store.value('cookies', []) if data: self.setAllCookies([QNetworkCookie.parseCookies(c)[0] for c in data]) def save(self): self.remove_expired_cookies() lines = [] for cookie in self.allCookies(): if not cookie.isSessionCookie(): lines.append(cookie.toRawForm()) self.cookie_store.setValue('cookies', QVariant(lines)) def remove_expired_cookies(self): now = QDateTime.currentDateTime() cookies = [c for c in self.allCookies() if c.isSessionCookie() or c.expirationDate() >= now] self.setAllCookies(cookies)
def writeSettings(self): s = QSettings() s.beginGroup("pitch-menu") s.setValue("relative-first-pitch-absolute", self.actionCollection.pitch_relative_assume_first_pitch_absolute.isChecked()) s.setValue("relative-write-startpitch", self.actionCollection.pitch_relative_write_startpitch.isChecked())
def setCurrentFile(self, fileName): self.curFile = QFileInfo(fileName).canonicalFilePath() self.isUntitled = False self.setWindowModified(False) if self.curFile: self.setWindowTitle("Recent Files %s" % self.strippedName(self.curFile)) else: self.setWindowTitle("Recent Files") settings = QSettings('Trolltech', 'Recent Files Example') files = settings.value('recentFileList', []) try: files.remove(fileName) except ValueError: pass files.insert(0, fileName) del files[MainWindow.MaxRecentFiles:] settings.setValue('recentFileList', files) for widget in QApplication.topLevelWidgets(): if isinstance(widget, MainWindow): widget.updateRecentFileActions()
def updateRecentFileActions(self, insert_file=None): settings = QSettings('Cemu', 'Recent Files') files = settings.value('recentFileList') if files is None: # if setting doesn't exist, create it settings.setValue('recentFileList', []) files = settings.value('recentFileList') maxRecentFiles = CEmuWindow.MaxRecentFiles if insert_file: # insert new file to list if insert_file not in files: files.insert(0, insert_file) # ensure list size if len(files) > maxRecentFiles: files = files[0:maxRecentFiles] # save the setting settings.setValue('recentFileList', files) numRecentFiles = min(len(files), maxRecentFiles) for i in range(numRecentFiles): text = "&%d %s" % (i + 1, self.strippedName(files[i])) self.recentFileActions[i].setText(text) self.recentFileActions[i].setData(files[i]) self.recentFileActions[i].setVisible(True) for j in range(numRecentFiles, maxRecentFiles): self.recentFileActions[j].setVisible(False) return
def closeEvent(self, event): print("Main window close event") # Save layout settings settings = QSettings("PhotoCalendar") settings.beginGroup("MainWindow") curSize = self.size() settings.setValue("Size", QVariant(curSize)) curPos = self.pos() settings.setValue("Position", QVariant(curPos)) #settings.setValue("MainWindow/State", QVariant(self.saveState())) horzSplitterState = self.horzSplitter.saveState() #print("HorzSplitter save", horzSplitterState) settings.setValue("HorzSplitter", QVariant(horzSplitterState)) leftPaneSplitterState = self.leftPane.saveState() settings.setValue("LeftPaneSplitter", QVariant(leftPaneSplitterState)) #print("LeftPaneSplitter save", leftPaneSplitterState) rightPaneSplitterState = self.rightPane.saveState() settings.setValue("RightPaneSplitter", QVariant(rightPaneSplitterState)) #print("RightPaneSplitter save", leftPaneSplitterState) settings.endGroup() # Stop the sub-elements self.calendar.stop() self.clock.stop() self.photos.stop() # Accept the close event event.accept()
def add_path(self, path): "Adds path to recent documents" recent = self.read_paths() # Make the path absolute, resolving any symlinks. path = self._resolved_if_possible(Path(path)) # Remove the existing occurrence of path, if present. # A linear scan is acceptable here because the list will always # be very short try: recent.remove(path) except ValueError: # path is not currently in recent pass # Prepend the path recent.insert(0, str(path)) # Limit to MAX_RECENT_DOCS recent = recent[:self.MAX_RECENT_DOCS] debug_print('Writing {0} recent document paths'.format(len(recent))) settings = QSettings() settings.beginWriteArray(self.KEY, len(recent)) try: for index, path in enumerate(recent): settings.setArrayIndex(index) settings.setValue('path', str(path)) finally: settings.endArray()
def start(self): file = self.destination.text().strip() if not file: QMessageBox.warning(self, self.tr("Create mobile collection"), self.tr("Destination file not specified")) return density = self.densitySelector.currentText() settings = QSettings() settings.setValue('density', density) self.params['filter'] = self.filterSelector.itemData(self.filterSelector.currentIndex()) self.params['density'] = density self.params['file'] = file if self.obverseRadio.isChecked(): self.params['image'] = self.IMAGE_OBVERSE elif self.reverseRadio.isChecked(): self.params['image'] = self.IMAGE_REVERSE elif self.noneRadio.isChecked(): self.params['image'] = self.IMAGE_NONE else: self.params['image'] = self.IMAGE_BOTH self.accept()
def _on_click_on_favorite(self, path, value): settings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat) recent_projects = settings.value("recentProjects") properties = recent_projects[path] properties["isFavorite"] = value recent_projects[path] = properties settings.setValue("recentProjects", recent_projects)
def dropEvent(self, event): if event.mimeData().hasFormat('text/uri-list'): paths = [url for url in event.mimeData().urls()] # If we drop many files, only the first one will be take into # acount fileName = paths[0] index = self.indexAt(event.pos()) row, col = index.row(), index.column() settings = QSettings() if col == UploadListView.COL_VIDEO: if(VideoTools.isVideofile(fileName)): settings.setValue("mainwindow/workingDirectory", fileName) video = VideoFile(fileName) self.model().layoutAboutToBeChanged.emit() self.model().addVideos(row, [video]) subtitle = Subtitle.AutoDetectSubtitle(video.getFilePath()) if subtitle: sub = SubtitleFile(False, subtitle) self.model().addSubs(row, [sub]) thread.start_new_thread( self.uploadModel.ObtainUploadInfo, ()) self.resizeRowsToContents() self.model().layoutChanged.emit() else: # if it's the column in SUBTITLES print(fileName) if(Subtitle.isSubtitle(fileName)): settings.setValue("mainwindow/workingDirectory", fileName) sub = SubtitleFile(False, fileName) self.model().layoutAboutToBeChanged.emit() self.model().addSubs(row, [sub]) self.resizeRowsToContents() self.model().layoutChanged.emit() thread.start_new_thread( self.uploadModel.ObtainUploadInfo, ())
def saveSettings(self): s = QSettings() s.beginGroup("documentstructure") if self.patternList.value() != documentstructure.default_outline_patterns: s.setValue("outline_patterns", self.patternList.value()) else: s.remove("outline_patterns")
def SetLanguage(self): global actualLanguage settings = QSettings('Pandoc', 'PanConvert') settings.setValue('default_language', str(self.ui.comboBoxLanguageSelector.currentText())) actualLanguage = str(self.ui.comboBoxLanguageSelector.currentText()) settings.sync() settings.status()
def on_save_defaults(self): settings = QSettings() parameters = MaskParameters() self.update_parameters_from_ui(parameters) defaults = parameters.serialize() settings.setValue("mask/defaults", defaults)
def _save_settings(self): """ Save the user specific settings. """ settings = QSettings() settings.setValue('size', self.size()) settings.setValue('pos', self.pos())
def saveSettings(self): s = QSettings() s.beginGroup("typographical_quotes") s.setValue("language", self._langs[self.languageCombo.currentIndex()]) s.setValue("primary_left", self.primaryLeft.text()) s.setValue("primary_right", self.primaryRight.text()) s.setValue("secondary_left", self.secondaryLeft.text()) s.setValue("secondary_right", self.secondaryRight.text())
def save_sizes(self): """ Save sizes of Splitters """ qsettings = QSettings(settings.SETTINGS_PATH, QSettings.IniFormat) qsettings.setValue('result_splitter_query_sizes', self.result_splitter.saveState()) qsettings.setValue('editor_splitter_query_sizes', self._editor_splitter.saveState())
def saveSettings(self): s = QSettings() s.beginGroup("log") s.setValue("fontfamily", self.fontChooser.currentFont().family()) s.setValue("fontsize", self.fontSize.value()) s.setValue("show_on_start", self.showlog.isChecked()) s.setValue("rawview", self.rawview.isChecked()) s.setValue("hide_auto_engrave", self.hideauto.isChecked())
def saveSettings(self): s = QSettings() s.beginGroup("hyphenation") paths = self.listedit.value() if paths: s.setValue("paths", paths) else: s.remove("paths")
def done(self, r): settings = QSettings() orig_class_name = self.__class__.__name__ settings.setValue('%s/maximized' % orig_class_name, self.isMaximized()) if not self.isMaximized(): settings.setValue('%s/size' % orig_class_name, self.size()) orig_done(self, r) # call the original done
def saveSettings(self): s = QSettings() s.beginGroup("documentation") paths = self.paths.value() if paths: s.setValue("paths", paths) else: s.remove("paths")
def writeSettings(self): s = QSettings() s.beginGroup("copy_image") s.setValue("dpi", self.dpiCombo.currentText()) s.setValue("papercolor", self.colorButton.color()) s.setValue("autocrop", self.crop.isChecked()) s.setValue("antialias", self.antialias.isChecked()) s.setValue("scaleup", self.scaleup.isChecked())
def save_sizes(self): """ Save sizes of Splitters """ qsettings = QSettings(settings.SETTINGS_PATH, QSettings.IniFormat) qsettings.setValue('hsplitter_query_sizes', self._hsplitter.saveState()) qsettings.setValue('vsplitter_query_sizes', self._vsplitter.saveState())
def closeEvent(self, event): device_settings = QSettings('superboucle', 'devices') device_settings.setValue('devices', [pickle.dumps(x.mapping) for x in self.devices]) self.settings.setValue('playlist', self.playlist) self.settings.setValue('paths_used', self.paths_used) self.settings.setValue('auto_connect', self.auto_connect)
def closeEvent(self, event): qsettings = QSettings(settings.SETTINGS_PATH, QSettings.IniFormat) # Save window geometry if self.isMaximized(): qsettings.setValue('window_max', True) else: qsettings.setValue('window_max', False) qsettings.setValue('window_pos', self.pos()) qsettings.setValue('window_size', self.size()) central_widget = Pireal.get_service("central") # Save recent databases qsettings.setValue('recent_databases', central_widget.recent_databases) db = central_widget.get_active_db() if db is not None: # Save splitters size db.save_sizes() # Databases unsaved if db.modified: msg = QMessageBox(self) msg.setIcon(QMessageBox.Question) msg.setWindowTitle(self.tr("Some changes where not saved")) msg.setText( self.tr("Do you want to save changes to the database?")) cancel_btn = msg.addButton(self.tr("Cancel"), QMessageBox.RejectRole) msg.addButton(self.tr("No"), QMessageBox.NoRole) yes_btn = msg.addButton(self.tr("Yes"), QMessageBox.YesRole) msg.exec_() r = msg.clickedButton() if r == yes_btn: central_widget.save_database() if r == cancel_btn: event.ignore() # Query files unsaved_editors = central_widget.get_unsaved_queries() if unsaved_editors: msg = QMessageBox(self) msg.setIcon(QMessageBox.Question) msg.setWindowTitle(self.tr("Unsaved Queries")) text = '\n'.join([editor.name for editor in unsaved_editors]) msg.setText(self.tr("{files}<br><br>Do you want to " "save them?".format(files=text))) cancel_btn = msg.addButton(self.tr("Cancel"), QMessageBox.RejectRole) msg.addButton(self.tr("No"), QMessageBox.NoRole) yes_btn = msg.addButton(self.tr("Yes"), QMessageBox.YesRole) msg.exec_() if msg.clickedButton() == yes_btn: for editor in unsaved_editors: central_widget.save_query(editor) if msg.clickedButton() == cancel_btn: event.ignore()
def GetFirstRunTime(): settings = QSettings() firstRunTime = settings.value("mainwindow/size2", "") if firstRunTime != "": return float(firstRunTime) else: now = time.time() settings.setValue("mainwindow/size2", now) return now
def test_init(init_patch, config_tmpdir): configfiles.init() # Make sure qsettings land in a subdir if utils.is_linux: settings = QSettings() settings.setValue("hello", "world") settings.sync() assert (config_tmpdir / 'qsettings').exists()
def write_settings(self): """Saves known application settings to disk""" settings = QSettings() settings.setValue('myValue', 123456) # per PyQt docs to force write almost immediately... del settings
def save_profile(self, profileName): """Save the updates from a profile.""" projects_obj = self.ide.explorer.get_opened_projects() projects = [p.path for p in projects_obj] files = self.ide.mainContainer.get_opened_documents() files = files[0] + files[1] settings.PROFILES[profileName] = [files, projects] qsettings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat) qsettings.setValue('ide/profiles', settings.PROFILES)
def save_state(self): assert self.ROLE settings = QSettings() settings.beginGroup(self.ROLE) settings.setValue('geometry', self.saveGeometry()) if isinstance(self, QMainWindow): settings.setValue('state', self.saveState()) self._save_state(settings) settings.endGroup()
def closeEvent(self, event): Settings = QSettings('kicad-tools', 'Schematic Component Manager') Settings.setValue( 'geometry', self.saveGeometry() ) Settings.setValue( 'cmptable', [self.CmpTable.columnWidth(0), self.CmpTable.columnWidth(1)] ) Settings.setValue( 'selector', [self.Selector.columnWidth(0), self.Selector.columnWidth(1)] ) Settings.setValue( 'inspector', [self.Inspector.columnWidth(0), self.Inspector.columnWidth(1)] ) Settings.setValue( 'splitter', self.Splitter.saveState() ) Settings.setValue( 'inssplitter', self.InspectorSplit.saveState() ) QWidget.closeEvent(self, event)
class Geo360Dialog(QWidget, Ui_orbitalDialog): """Geo360 Dialog Class""" def __init__(self, iface, parent=None, featuresId=None, layer=None): QDialog.__init__(self) self.setupUi(self) self.s = QSettings() self.plugin_path = os.path.dirname(os.path.realpath(__file__)) self.iface = iface self.canvas = self.iface.mapCanvas() self.parent = parent # Orientation from image self.yaw = math.pi self.bearing = None self.layer = layer self.featuresId = featuresId self.actualPointDx = None self.actualPointSx = None self.actualPointOrientation = None self.selected_features = qgsutils.getToFeature(self.layer, self.featuresId) # Get image path self.current_image = self.GetImage() # Create Viewer self.CreateViewer() self.RestoreSize() # Check if image exist if os.path.exists(self.current_image) is False: qgsutils.showUserAndLogMessage(u"Information: ", u"There is no associated image.") self.resetQgsRubberBand() time.sleep(1) self.ChangeUrlViewer(config.DEFAULT_EMPTY) return # Copy file to local server self.CopyFile(self.current_image) # Set RubberBand self.resetQgsRubberBand() self.setOrientation() self.setPosition() def SetInitialYaw(self): ''' Set Initial Yaw ''' self.bearing = self.selected_features.attribute(config.column_yaw) self.view.browser.GetMainFrame().ExecuteFunction( "InitialYaw", self.bearing) return def CreateViewer(self): ''' Create Viewer ''' qgsutils.showUserAndLogMessage(u"Information: ", u"Create viewer", onlyLog=True) self.view = CefWidget(self) self.ViewerLayout.addWidget(self.view) self.view.embedBrowser() return def RemoveImage(self): ''' Remove Image ''' try: os.remove(self.plugin_path + "\\viewer\\image.jpg") except OSError: pass def CopyFile(self, src): ''' Copy Image File in Local Server ''' qgsutils.showUserAndLogMessage(u"Information: ", u"Copiar imagem", onlyLog=True) src_dir = src dst_dir = self.plugin_path + "\\viewer" # Copy image in local folder # Uncomment for large images if viewer is blank screen img = Image.open(src_dir) newwidth = 8000 dst_dir = dst_dir + "\\image.jpg" try: os.remove(dst_dir) except OSError: pass width, _ = img.size if width > newwidth: wpercent = (newwidth / float(img.size[0])) hsize = int((float(img.size[1]) * float(wpercent))) img = img.resize((newwidth, hsize), Image.ANTIALIAS) img.save(dst_dir, optimize=True, quality=95) # Comment for large images if viewer is blank screen else: shutil.copy(src_dir, dst_dir) return def RestoreSize(self): ''' Restore Dialog Size ''' dw = self.s.value("EquirectangularViewer/width") dh = self.s.value("EquirectangularViewer/height") if dw is None: return size = self.size() anim = QPropertyAnimation(self, b'size', self) anim.setStartValue(size) anim.setEndValue(QSize(int(dw), int(dh))) anim.setDuration(1) anim.start() return def SaveSize(self): ''' Save Dialog Size ''' dw = self.width() dh = self.height() self.s.setValue("EquirectangularViewer/width", dw) self.s.setValue("EquirectangularViewer/height", dh) return def GetImage(self): ''' Get Selected Image ''' try: path = qgsutils.getAttributeFromFeature(self.selected_features, config.column_name) if not os.path.isabs(path): # Relative Path to Project path_project = QgsProject.instance().readPath("./") path = os.path.normpath(os.path.join(path_project, path)) except Exception: qgsutils.showUserAndLogMessage(u"Information: ", u"Column not found.") return qgsutils.showUserAndLogMessage(u"Information: ", str(path), onlyLog=True) return path def ChangeUrlViewer(self, new_url): ''' Change Url Viewer ''' self.view.browser.GetMainFrame().ExecuteJavascript( "window.location='%s'" % new_url) return def ReloadView(self, newId): ''' Reaload Image viewer ''' self.setWindowState(self.windowState() & ~Qt.WindowMinimized | Qt.WindowActive) # this will activate the window self.activateWindow() self.selected_features = qgsutils.getToFeature(self.layer, newId) self.current_image = self.GetImage() # Check if image exist if os.path.exists(self.current_image) is False: qgsutils.showUserAndLogMessage(u"Information: ", u"There is no associated image.") self.ChangeUrlViewer(config.DEFAULT_EMPTY) self.resetQgsRubberBand() return # Set RubberBand self.resetQgsRubberBand() self.setOrientation() self.setPosition() # Copy file to local server self.CopyFile(self.current_image) self.ChangeUrlViewer(config.DEFAULT_URL) return def ResizeDialog(self): ''' Expanded/Decreased Dialog ''' sender = QObject.sender(self) w = self.width() h = self.height() size = self.size() anim = QPropertyAnimation(self, b'size', self) anim.setStartValue(size) if sender.objectName() == "btn_ZoomOut": anim.setEndValue(QSize(w - 50, h - 50)) else: anim.setEndValue(QSize(w + 50, h + 50)) anim.setDuration(300) anim.start() return def GetBackNextImage(self): ''' Get to Back Image ''' sender = QObject.sender(self) lys = self.canvas.layers() # Check if mapa foto is loaded if len(lys) == 0: qgsutils.showUserAndLogMessage( u"Information: ", u"You need to upload the photo layer.") return for layer in lys: if layer.name() == config.layer_name: self.encontrado = True self.iface.setActiveLayer(layer) f = self.selected_features ac_lordem = f.attribute(config.column_order) if sender.objectName() == "btn_back": new_lordem = int(ac_lordem) - 1 else: new_lordem = int(ac_lordem) + 1 # Filter mapa foto layer ids = [ feat.id() for feat in layer.getFeatures(QgsFeatureRequest( ).setFilterExpression(config.column_order + " ='" + str(new_lordem) + "'")) ] if len(ids) == 0: qgsutils.showUserAndLogMessage( u"Information: ", u"There is no superiority that follows.") # Filter mapa foto layer ids = [ feat.id() for feat in layer.getFeatures(QgsFeatureRequest( ).setFilterExpression(config.column_order + " ='" + str(ac_lordem) + "'")) ] # Update selected feature self.ReloadView(ids[0]) return self.ReloadView(ids[0]) if self.encontrado is False: qgsutils.showUserAndLogMessage( u"Information: ", u"You need to upload the photo layer.") return def FullScreen(self, value): ''' FullScreen action button ''' qgsutils.showUserAndLogMessage(u"Information: ", u"Fullscreen.", onlyLog=True) if (value): self.showFullScreen() else: self.showNormal() return @staticmethod def ActualOrientation(yaw): ''' Get Actual yaw ''' geo360Plugin = qgis.utils.plugins["EquirectangularViewer"] if geo360Plugin is not None: geo360Dialog = qgis.utils.plugins["EquirectangularViewer"].dlg if geo360Dialog is not None: geo360Dialog.UpdateOrientation(yaw=float(yaw)) return def UpdateOrientation(self, yaw=None): ''' Update Orientation ''' self.bearing = self.selected_features.attribute(config.column_yaw) try: self.actualPointOrientation.reset() except Exception: pass self.actualPointOrientation = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.LineGeometry) self.actualPointOrientation.setColor(Qt.blue) self.actualPointOrientation.setWidth(5) self.actualPointOrientation.addPoint(self.actualPointDx) # End Point CS = self.canvas.mapUnitsPerPixel() * 25 A1x = self.actualPointDx.x() - CS * math.cos(math.pi / 2) A1y = self.actualPointDx.y() + CS * math.sin(math.pi / 2) self.actualPointOrientation.addPoint(QgsPointXY( float(A1x), float(A1y))) # Vision Angle if yaw is not None: angle = float(self.bearing + yaw) * math.pi / -180 else: angle = float(self.bearing) * math.pi / -180 tmpGeom = self.actualPointOrientation.asGeometry() self.actualPointOrientation.setToGeometry( self.rotateTool.rotate(tmpGeom, self.actualPointDx, angle), self.dumLayer) def setOrientation(self, yaw=None): ''' Set Orientation in the firt time ''' self.bearing = self.selected_features.attribute(config.column_yaw) self.actualPointDx = self.selected_features.geometry().asPoint() self.actualPointOrientation = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.LineGeometry) self.actualPointOrientation.setColor(Qt.blue) self.actualPointOrientation.setWidth(5) self.actualPointOrientation.addPoint(self.actualPointDx) # End Point CS = self.canvas.mapUnitsPerPixel() * 25 A1x = self.actualPointDx.x() - CS * math.cos(math.pi / 2) A1y = self.actualPointDx.y() + CS * math.sin(math.pi / 2) self.actualPointOrientation.addPoint(QgsPointXY( float(A1x), float(A1y))) # Vision Angle if yaw is not None: angle = float(self.bearing + yaw) * math.pi / -180 else: angle = float(self.bearing) * math.pi / -180 tmpGeom = self.actualPointOrientation.asGeometry() self.rotateTool = transformGeometry() epsg = self.canvas.mapSettings().destinationCrs().authid() self.dumLayer = QgsVectorLayer("Point?crs=" + epsg, "temporary_points", "memory") self.actualPointOrientation.setToGeometry( self.rotateTool.rotate(tmpGeom, self.actualPointDx, angle), self.dumLayer) def setPosition(self): ''' Set RubberBand Position ''' self.actualPointDx = self.selected_features.geometry().asPoint() self.positionDx = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PointGeometry) self.positionDx.setWidth(6) self.positionDx.setIcon(QgsRubberBand.ICON_CIRCLE) self.positionDx.setIconSize(6) self.positionDx.setColor(Qt.black) self.positionSx = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PointGeometry) self.positionSx.setWidth(5) self.positionSx.setIcon(QgsRubberBand.ICON_CIRCLE) self.positionSx.setIconSize(4) self.positionSx.setColor(Qt.blue) self.positionInt = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PointGeometry) self.positionInt.setWidth(5) self.positionInt.setIcon(QgsRubberBand.ICON_CIRCLE) self.positionInt.setIconSize(3) self.positionInt.setColor(Qt.white) self.positionDx.addPoint(self.actualPointDx) self.positionSx.addPoint(self.actualPointDx) self.positionInt.addPoint(self.actualPointDx) def closeEvent(self, _): ''' Close dialog ''' self.resetQgsRubberBand() self.canvas.refresh() self.iface.actionPan().trigger() self.SaveSize() self.parent.dlg = None self.RemoveImage() return def resetQgsRubberBand(self): ''' Remove RubbeBand ''' try: self.positionSx.reset() self.positionInt.reset() self.positionDx.reset() self.actualPointOrientation.reset() except Exception: None
def closeEvent(self, event): settings = QSettings() settings.setValue('splitterSize', self.split.sizes()) settings.setValue('guiIcon', self.windowIcon()) settings.setValue('guiGeometry', self.geometry())
class CreateDirs(QDialog): ''' CreateDirs is a dialog that enables the user to disable the auto gen of directories and provides a facility to choose what months of subdirectories to be created. ''' def __init__(self, testSettings=None): ''' :params testSettings: Override the settings key. Intended for testing. Proividing a value for testSettings will prevent show from being called. ''' super().__init__(parent=None) if testSettings: self.settings = testSettings else: self.settings = QSettings('zero_substance', 'structjour') self.ui = CreateDirsDialog() self.ui.setupUi(self) self.setWindowIcon(QIcon("structjour/images/ZSLogo.png")) self.ui.createDirsBtn.pressed.connect(self.createDirs) self.ui.enabledRb.clicked.connect(self.enableAutoGen) self.ui.disabledRb.clicked.connect(self.disableAutoGen) autog = self.settings.value('directories_autogen', defaultValue=True, type=bool) if autog: self.ui.enabledRb.setChecked(True) self.enableAutoGen() else: self.ui.disabledRb.setChecked(True) self.disableAutoGen() lastDir = self.settings.value('lastDirCreated') if lastDir: dd = pd.Timestamp(lastDir) year = dd.strftime('%Y') month = dd.strftime('%B') self.ui.createDirsYear.setCurrentText(year) self.ui.createDirsMonth.setCurrentText(month) if not testSettings: self.show() def createDirs(self): '''Create the sub directories in the journal directory''' if not self.settings.value('journal') or self.settings.value('journal') == "": if hasattr(self, 'debug') and self.debug: return "" msg = f'<h3>Please select a journal directory</h3>' msg += f'<p>Go to file->filesettings and select a location for your journal files.</p>' msgbx = QMessageBox() msgbx.setIconPixmap(QPixmap("structjour/images/ZSLogo.png")) msgbx.setText(msg) msgbx.exec() m = pd.Timestamp(f'{self.ui.createDirsMonth.currentText()} {self.ui.createDirsYear.currentText()}') try: theDir = createDirsStructjour(m, self.settings) except ValueError as m: if m.args[0].startswith('Directory Already'): msg = f'<h3>{m.args[0]}</h3>' msg += f'<p>{m.args[1]}</p>' msgbx = QMessageBox() msgbx.setIconPixmap(QPixmap("structjour/images/ZSLogo.png")) msgbx.setText(msg) msgbx.exec() else: raise ValueError(m) else: # self.settings.setValue('lastDir') self.settings.setValue('lastDirCreated', m.strftime('%Y%m01')) if hasattr(self, 'debug') and self.debug: return theDir msg = f'<h3>Directories created</h3>' msg += f'<p>under {theDir}</p>' msgbx = QMessageBox() msgbx.setIconPixmap(QPixmap("structjour/images/ZSLogo.png")) msgbx.setText(msg) msgbx.exec() return theDir def disableAutoGen(self): self.settings.setValue('directories_autogen', 'false') self.ui.createDirsBtn.setEnabled(True) def enableAutoGen(self): self.settings.setValue('directories_autogen', 'true') self.ui.createDirsBtn.setEnabled(False)
def writeSettings(self): settings = QSettings('china', 'seven') settings.setValue('pos', self.pos()) settings.setValue('size', self.size())
def saveSettings(self): settings = QSettings("Cadence", "JackSettings") settings.setValue("Geometry", self.saveGeometry()) settings.setValue("CurrentTab", self.ui.tabWidget.currentIndex())
def close(self): #save window position (only; not size!) settings = QSettings() settings.setValue("AxisPosition", self.frameGeometry().topLeft()) self.aw.closeEventSettings() super(WindowsDlg, self).close()
def write_settings(**kwargs): """Write application settings.""" settings = QSettings() for key, value in kwargs.items(): settings.setValue(key, value)
class MainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.ui = Ui_MainWindowForm() self.ui.setupUi(self) self.ui.actionOpen_DB_File.triggered.connect(self.open_db) self.ui.actionOpen_SPS_File.triggered.connect(self.open_sps) self.ui.actionProcess.triggered.connect(self.process) self.ui.actionAbout.triggered.connect(about) self.ui.actionLicense.triggered.connect(license) self.ui.actionHelp.triggered.connect(help) self.ui.actionQuit.triggered.connect(self.close_application) self.ui.actionCreate_DB.triggered.connect(self.create_db_file) self.ui.actionUpdate_DB.triggered.connect(db_update) # status tips copied from tool tip ? # self.ui.actionOpen_DB_File.setStatusTip(self.ui.actionOpen_DB_File.toolTip()) self.ui.lblDb.setText('') self.ui.lblSPS.setText('') self.db_file = None self.sps_file = None self.log_file = None self.settings = QSettings(app_settings.ORG, app_settings.APP) self.settings_read() def warning_nothing_to_process(self): dlg = Warning() dlg.set_label( 'Are you dumb ?\nWhat do you want to process ?\nSelect both DB & SPS files' ) dlg.exec_() def open_db(self): """ Opens DB file """ previous_db_file = self.db_file self.db_file, _ = QFileDialog.getOpenFileName( self, "Open file", "", "SQLite (*.sqlite );;All files (*.*)", # options=QFileDialog.DontUseNativeDialog ) if not self.db_file: self.db_file = previous_db_file self.ui.lblDb.setText(self.db_file) def open_sps(self): """ Opens SPS file """ previous_sps_file = self.sps_file self.sps_file, _ = QFileDialog.getOpenFileName( self, "Open file", "", "SPS Source (*.S *.SPS *.s *.sps);;SPS Receiver (*.R *.RPS *.r *.rps);;All files (*.*)", # options=QFileDialog.DontUseNativeDialog ) if not self.sps_file: self.sps_file = previous_sps_file self.ui.lblSPS.setText(self.sps_file) self.log_file = self.sps_file + LOG_EXT def process(self): if self.db_file and self.sps_file: self.runner() else: self.warning_nothing_to_process() def runner(self): common.log_file_create(self.log_file) start_time = time.time() if self.db_file and self.sps_file: line_numbers = common.count_file_line_number(self.sps_file) self.ui.progressBar.setMaximum(line_numbers) limit_x = float(self.ui.limitX.text()) limit_y = float(self.ui.limitY.text()) self.log(datetime.today().strftime("%Y-%m-%d %H:%M:%S")) self.log('DB: %s' % self.db_file) self.log('DB record count: %d' % db.count_db_records(self.db_file)) self.log('SPS: %s' % self.sps_file) self.log('SPS record count: %d' % line_numbers) self.log('Limits: E: %.2f, N: %.2f' % (limit_x, limit_y)) result = self.check(limit_x, limit_y) timing = time.time() - start_time point_count = result['PC'] not_in_db_count = result['NDB'] offset_count_x = result['OCX'] offset_count_y = result['OCY'] poffset_count_x = offset_count_x / point_count * 100 poffset_count_y = offset_count_y / point_count * 100 self.log('Number of points: %d' % point_count) self.log('Number of points not in DB: %d' % not_in_db_count) self.log('Errors Easting: %d points, %.2f%s' % (offset_count_x, poffset_count_x, '%')) self.log('Errors Nothing: %d points, %.2f%s' % (offset_count_y, poffset_count_y, '%')) self.log('Elapsed time: %d sec' % timing) self.print2output( '-----------------------------------------------------------------' ) def print2output(self, text): self.ui.txtOutput.append(text) def log(self, text): self.print2output(text) common.log_file_record_add(self.log_file, text) def settings_save(self): self.settings.setValue(app_settings.LIMIT_X, self.ui.limitX.text()) self.settings.setValue(app_settings.LIMIT_Y, self.ui.limitY.text()) self.settings.setValue(app_settings.DB_PATH, self.db_file) def settings_read(self): self.ui.limitX.setText( self.settings.value(app_settings.LIMIT_X, '0.0', type=str)) self.ui.limitY.setText( self.settings.value(app_settings.LIMIT_Y, '0.0', type=str)) db_file = self.settings.value(app_settings.DB_PATH, '', type=str) if 0 == len(db_file): db_file = None self.db_file = db_file self.ui.lblDb.setText(db_file) def close_application(self): self.settings_save() self.close() def create_db_file(self): db_file, _ = QFileDialog.getSaveFileName( self, "Create DB", "", "SQLite files (*.sqlite);;All Files (*)", # options=QFileDialog.DontUseNativeDialog ) if not db_file: return if not db_file.endswith(db.DB_FILE_EXT): db_file += db.DB_FILE_EXT db.create_db(db_file) db_log_file = db_file + common.DB_LOG_FILE_EXT common.log_file_create(db_log_file) common.log_file_record_add( db_log_file, f"Created: {datetime.today().strftime('%Y-%m-%d %H:%M:%S')}") common.log_file_record_add( db_log_file, '-----------------------------------------------------------------' ) def check(self, limit_x, limit_y): connection = db.create_connection(self.db_file) parser = Sps21Parser() check_file = self.sps_file + CHECK_EXT not_in_db_file = self.sps_file + NOT_IN_DB_EXT common.csv_file_create(check_file, CHECK_CSV_HEADER) common.csv_file_create(not_in_db_file, NOT_IN_DB_CSV_HEADER) with open(self.sps_file) as sps: line = sps.readline() sps_counter = 0 not_in_db_counter = 0 offset_counter_x = 0 offset_counter_y = 0 while line: stats = parser.parse_point(line) if stats is not None: point = Point(stats) stats = db.get_record_for_point(connection, point) if stats is None: sps_counter += 1 not_in_db_counter += 1 record = "%.2f,%.2f,%.1f,%.1f" \ % ( point.line, point.point, point.easting, point.northing) common.csv_file_record_add(not_in_db_file, record) line = sps.readline() continue de = point.easting - stats[0] dn = point.northing - stats[1] error_easting = 0 if abs(de) > limit_x: offset_counter_x += 1 error_easting = 1 error_northing = 0 if abs(dn) > limit_y: offset_counter_y += 1 error_northing = 1 record = "%.2f,%.2f,%.1f,%.1f,%.1f,%.1f,%d,%d" \ % ( point.line, point.point, point.easting, point.northing, de, dn, error_easting, error_northing) common.csv_file_record_add(check_file, record) sps_counter += 1 self.ui.progressBar.setValue(sps_counter) line = sps.readline() sps.close() stats = { 'PC': sps_counter, 'NDB': not_in_db_counter, 'OCX': offset_counter_x, 'OCY': offset_counter_y } connection.close() return stats
def saveSettings(self): s = QSettings() s.setValue("strip_trailing_whitespace", self.stripwsp.isChecked()) s.setValue("backup_keep", self.backup.isChecked()) s.setValue("metainfo", self.metainfo.isChecked()) s.setValue("basedir", self.basedir.path()) s.setValue("custom_default_filename", self.customFilename.isChecked()) s.setValue("default_filename_template", self.filenameTemplate.text())
# user download folder path download_path = os.path.join(str(home_address), 'Downloads', 'Persepolis') # Persepolis default setting default_setting_dict = {'toolbar_icon_size': 32, 'wait-queue': [0, 0], 'awake': 'no', 'custom-font': 'no', 'column0': 'yes', 'column1': 'yes', 'column2': 'yes', 'column3': 'yes', 'column4': 'yes', 'column5': 'yes', 'column6': 'yes', 'column7': 'yes', 'column10': 'yes', 'column11': 'yes', 'column12': 'yes', 'subfolder': 'yes', 'startup': 'no', 'show-progress': 'yes', 'show-menubar': 'no', 'show-sidepanel': 'yes', 'rpc-port': 6801, 'notification': 'Native notification', 'after-dialog': 'yes', 'tray-icon': 'yes', 'max-tries': 5, 'retry-wait': 0, 'timeout': 60, 'connections': 16, 'download_path_temp': download_path_temp, 'download_path': download_path, 'sound': 'yes', 'sound-volume': 100, 'style': 'Fusion', 'color-scheme': 'Persepolis Light Blue', 'icons': 'Papirus-Light', 'font': 'Ubuntu', 'font-size': 9, 'aria2_path': ''} # this loop is checking values in persepolis_setting . if value is not # valid then value replaced by default_setting_dict value for key in default_setting_dict.keys(): setting_value = persepolis_setting.value(key, default_setting_dict[key]) persepolis_setting.setValue(key, setting_value) persepolis_setting.sync() # this section creates temporary download folder and download folder and # download sub folders if they did not existed. download_path_temp = persepolis_setting.value('download_path_temp') download_path = persepolis_setting.value('download_path') folder_list = [download_path_temp, download_path] # add subfolders to folder_list if user checked subfolders check box in setting window. if persepolis_setting.value('subfolder') == 'yes': for folder in ['Audios', 'Videos', 'Others', 'Documents', 'Compressed']: folder_list.append(os.path.join(download_path, folder))
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.settings = QSettings() self.ui.exitAction.triggered.connect(QApplication.quit) self.ui.zoomInAction.triggered.connect(self.ui.imageLabel.zoomIn) self.ui.zoomOutAction.triggered.connect(self.ui.imageLabel.zoomOut) self.enableImageActions(False) self.enableSamplesActions(False) @pyqtSlot() def on_openAction_triggered(self): dir = self.settings.value(Settings.LAST_DIRECTORY_KEY, Settings.DEFAULT_LAST_DIRECTORY) (filename, _) = QFileDialog.getOpenFileName(self, self.tr('Open Image'), dir, self.tr('Images (*.png *.jpg)')) if filename: self.settings.setValue(Settings.LAST_DIRECTORY_KEY, QFileInfo(filename).absolutePath()) self.ui.imageLabel.loadImage(filename) self.statusBar().showMessage(QDir.toNativeSeparators(filename)) self.enableImageActions(True) self.on_clearAction_triggered() @pyqtSlot() def on_saveAction_triggered(self): dir = self.settings.value(Settings.LAST_DIRECTORY_KEY, Settings.DEFAULT_LAST_DIRECTORY) (filename, _) = QFileDialog.getSaveFileName( self, self.tr('Open Image'), dir, self.tr( 'Comma Separated Values files (*.csv)\nText files (*.txt)\n')) if filename: self.settings.setValue(Settings.LAST_DIRECTORY_KEY, QFileInfo(filename).absolutePath()) text = self.getCoordinatesAsCsv() with open(filename, 'w') as file: file.write(text) @pyqtSlot() def on_settingsAction_triggered(self): settingsDialog = SettingsDialog(self) if settingsDialog.exec_(): self.ui.imageLabel.reset() @pyqtSlot() def on_clearAction_triggered(self): self.ui.listWidget.clear() self.ui.imageLabel.clearSamples() self.enableSamplesActions(False) @pyqtSlot() def on_copyAction_triggered(self): text = self.getCoordinatesAsTsv() clipboard = QApplication.clipboard() clipboard.setText(text) @pyqtSlot() def on_aboutQtAction_triggered(self): QMessageBox.aboutQt(self) @pyqtSlot() def on_aboutAction_triggered(self): QMessageBox.about( self, self.tr('About'), self.tr('<h1>%s %s</h1>\n' + '<p>Developed by <a href="%s">%s</a></p>') % (QApplication.applicationName(), QApplication.applicationVersion(), QApplication.organizationDomain(), QApplication.organizationName())) @pyqtSlot() def on_pathLengthAction_triggered(self): coordinates = list(self.getCoordinates()) totalDistance = lengthOfPath(coordinates) QMessageBox.information( self, self.tr('Path Length'), self.tr("The path's length is %f" % totalDistance)) @pyqtSlot() def on_polygonAreaAction_triggered(self): coordinates = list(self.getCoordinates()) totalArea = areaOfPolygon(coordinates) QMessageBox.information( self, self.tr('Polygon Area'), self.tr("The polygon's area is %f" % totalArea)) @pyqtSlot(float, float) def on_imageLabel_mouseMoved(self, x, y): self.ui.coordinatesLineEdit.setText("%f × %f" % (x, y)) @pyqtSlot(float, float) def on_imageLabel_clicked(self, x, y): item = QListWidgetItem("%f × %f" % (x, y)) item.setData(Qt.UserRole, x) item.setData(Qt.UserRole + 1, y) self.ui.listWidget.addItem(item) self.enableSamplesActions(True) def getCoordinates(self): items = self.ui.listWidget.findItems('*', Qt.MatchWildcard) return map( lambda item: (item.data(Qt.UserRole), item.data(Qt.UserRole + 1)), items) def getCoordinatesAsCsv(self): coordinates = self.getCoordinates() lines = map(lambda coordinate: "%f,%f" % coordinate, coordinates) return 'x,y\n' + '\n'.join(lines) def getCoordinatesAsTsv(self): coordinates = self.getCoordinates() lines = map(lambda coordinate: "%f\t%f" % coordinate, coordinates) return 'x\ty\n' + '\n'.join(lines) def enableSamplesActions(self, enable): self.ui.saveAction.setEnabled(enable) self.ui.clearAction.setEnabled(enable) self.ui.copyAction.setEnabled(enable) self.ui.pathLengthAction.setEnabled(enable) self.ui.polygonAreaAction.setEnabled(enable) def enableImageActions(self, enable): self.ui.zoomInAction.setEnabled(enable) self.ui.zoomOutAction.setEnabled(enable)
def setStyle(self, style): # Save style to Qt Settings sttgs = QSettings(qApp.organizationName(), qApp.applicationName()) sttgs.setValue("applicationStyle", style) qApp.setStyle(style)
class TriblerWindow(QMainWindow): resize_event = pyqtSignal() escape_pressed = pyqtSignal() received_search_completions = pyqtSignal(object) def on_exception(self, *exc_info): # Stop the download loop self.downloads_page.stop_loading_downloads() # Add info about whether we are stopping Tribler or not os.environ['TRIBLER_SHUTTING_DOWN'] = str( self.core_manager.shutting_down) if not self.core_manager.shutting_down: self.core_manager.stop(stop_app_on_shutdown=False) self.setHidden(True) if self.debug_window: self.debug_window.setHidden(True) exception_text = "".join(traceback.format_exception(*exc_info)) logging.error(exception_text) if not self.feedback_dialog_is_open: dialog = FeedbackDialog( self, exception_text, self.core_manager.events_manager.tribler_version) self.feedback_dialog_is_open = True _ = dialog.exec_() def __init__(self): QMainWindow.__init__(self) self.navigation_stack = [] self.feedback_dialog_is_open = False self.tribler_started = False self.tribler_settings = None self.debug_window = None self.core_manager = CoreManager() self.pending_requests = {} self.pending_uri_requests = [] self.download_uri = None self.dialog = None self.start_download_dialog_active = False self.request_mgr = None self.search_request_mgr = None self.search_suggestion_mgr = None self.selected_torrent_files = [] self.vlc_available = True self.has_search_results = False sys.excepthook = self.on_exception uic.loadUi(get_ui_file_path('mainwindow.ui'), self) TriblerRequestManager.window = self self.magnet_handler = MagnetHandler(self.window) QDesktopServices.setUrlHandler("magnet", self.magnet_handler, "on_open_magnet_link") QCoreApplication.setOrganizationDomain("nl") QCoreApplication.setOrganizationName("TUDelft") QCoreApplication.setApplicationName("Tribler") QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps) self.read_settings() # Remove the focus rect on OS X for widget in self.findChildren(QLineEdit) + self.findChildren( QListWidget) + self.findChildren(QTreeWidget): widget.setAttribute(Qt.WA_MacShowFocusRect, 0) self.menu_buttons = [ self.left_menu_button_home, self.left_menu_button_search, self.left_menu_button_my_channel, self.left_menu_button_subscriptions, self.left_menu_button_video_player, self.left_menu_button_downloads, self.left_menu_button_discovered ] self.video_player_page.initialize_player() self.search_results_page.initialize_search_results_page() self.settings_page.initialize_settings_page() self.subscribed_channels_page.initialize() self.edit_channel_page.initialize_edit_channel_page() self.downloads_page.initialize_downloads_page() self.home_page.initialize_home_page() self.loading_page.initialize_loading_page() self.discovering_page.initialize_discovering_page() self.discovered_page.initialize_discovered_page() self.trust_page.initialize_trust_page() self.stackedWidget.setCurrentIndex(PAGE_LOADING) # Create the system tray icon if QSystemTrayIcon.isSystemTrayAvailable(): self.tray_icon = QSystemTrayIcon() use_monochrome_icon = get_gui_setting(self.gui_settings, "use_monochrome_icon", False, is_bool=True) self.update_tray_icon(use_monochrome_icon) self.hide_left_menu_playlist() self.left_menu_button_debug.setHidden(True) self.top_menu_button.setHidden(True) self.left_menu.setHidden(True) self.trust_button.setHidden(True) self.settings_button.setHidden(True) self.add_torrent_button.setHidden(True) self.top_search_bar.setHidden(True) # Set various icons self.top_menu_button.setIcon(QIcon(get_image_path('menu.png'))) self.search_completion_model = QStringListModel() completer = QCompleter() completer.setModel(self.search_completion_model) completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) self.item_delegate = QStyledItemDelegate() completer.popup().setItemDelegate(self.item_delegate) completer.popup().setStyleSheet(""" QListView { background-color: #404040; } QListView::item { color: #D0D0D0; padding-top: 5px; padding-bottom: 5px; } QListView::item:hover { background-color: #707070; } """) self.top_search_bar.setCompleter(completer) # Toggle debug if developer mode is enabled self.window().left_menu_button_debug.setHidden(not get_gui_setting( self.gui_settings, "debug", False, is_bool=True)) self.core_manager.start() self.core_manager.events_manager.received_search_result_channel.connect( self.search_results_page.received_search_result_channel) self.core_manager.events_manager.received_search_result_torrent.connect( self.search_results_page.received_search_result_torrent) self.core_manager.events_manager.torrent_finished.connect( self.on_torrent_finished) self.core_manager.events_manager.new_version_available.connect( self.on_new_version_available) self.core_manager.events_manager.tribler_started.connect( self.on_tribler_started) # Install signal handler for ctrl+c events def sigint_handler(*_): self.close_tribler() signal.signal(signal.SIGINT, sigint_handler) self.installEventFilter(self.video_player_page) self.show() def update_tray_icon(self, use_monochrome_icon): if use_monochrome_icon: self.tray_icon.setIcon( QIcon(QPixmap(get_image_path('monochrome_tribler.png')))) else: self.tray_icon.setIcon( QIcon(QPixmap(get_image_path('tribler.png')))) self.tray_icon.show() def on_torrent_finished(self, torrent_info): self.window().tray_icon.showMessage( "Download finished", "Download of %s has finished." % torrent_info["name"]) def show_loading_screen(self): self.top_menu_button.setHidden(True) self.left_menu.setHidden(True) self.trust_button.setHidden(True) self.settings_button.setHidden(True) self.add_torrent_button.setHidden(True) self.top_search_bar.setHidden(True) self.stackedWidget.setCurrentIndex(PAGE_LOADING) def on_tribler_started(self): self.tribler_started = True self.top_menu_button.setHidden(False) self.left_menu.setHidden(False) self.trust_button.setHidden(False) self.settings_button.setHidden(False) self.add_torrent_button.setHidden(False) self.top_search_bar.setHidden(False) # fetch the variables, needed for the video player port self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("variables", self.received_variables) self.downloads_page.start_loading_downloads() self.home_page.load_popular_torrents() if not self.gui_settings.value( "first_discover", False) and not self.core_manager.use_existing_core: self.window().gui_settings.setValue("first_discover", True) self.discovering_page.is_discovering = True self.stackedWidget.setCurrentIndex(PAGE_DISCOVERING) else: self.clicked_menu_button_home() def process_uri_request(self): """ Process a URI request if we have one in the queue. """ if len(self.pending_uri_requests) == 0: return uri = self.pending_uri_requests.pop() if uri.startswith('file') or uri.startswith('magnet'): self.start_download_from_uri(uri) def perform_start_download_request(self, uri, anon_download, safe_seeding, destination, selected_files, total_files=0, callback=None): selected_files_uri = "" if len(selected_files) != total_files: # Not all files included selected_files_uri = u'&' + u''.join( u"selected_files[]=%s&" % file for file in selected_files)[:-1] anon_hops = int(self.tribler_settings['Tribler'] ['default_number_hops']) if anon_download else 0 safe_seeding = 1 if safe_seeding else 0 post_data = "uri=%s&anon_hops=%d&safe_seeding=%d&destination=%s%s" % ( uri, anon_hops, safe_seeding, destination, selected_files_uri) post_data = post_data.encode( 'utf-8') # We need to send bytes in the request, not unicode request_mgr = TriblerRequestManager() self.pending_requests[request_mgr.request_id] = request_mgr request_mgr.perform_request( "downloads", callback if callback else self.on_download_added, method='PUT', data=post_data) # Save the download location to the GUI settings current_settings = get_gui_setting(self.gui_settings, "recent_download_locations", "") recent_locations = current_settings.split( ",") if len(current_settings) > 0 else [] encoded_destination = destination.encode('hex') if encoded_destination in recent_locations: recent_locations.remove(encoded_destination) recent_locations.insert(0, encoded_destination) if len(recent_locations) > 5: recent_locations = recent_locations[:5] self.gui_settings.setValue("recent_download_locations", ','.join(recent_locations)) def on_new_version_available(self, version): if version == str(self.gui_settings.value('last_reported_version')): return self.dialog = ConfirmationDialog( self, "New version available", "Version %s of Tribler is available.Do you want to visit the website to " "download the newest version?" % version, [('IGNORE', BUTTON_TYPE_NORMAL), ('LATER', BUTTON_TYPE_NORMAL), ('OK', BUTTON_TYPE_NORMAL)]) self.dialog.button_clicked.connect( lambda action: self.on_new_version_dialog_done(version, action)) self.dialog.show() def on_new_version_dialog_done(self, version, action): if action == 0: # ignore self.gui_settings.setValue("last_reported_version", version) elif action == 2: # ok import webbrowser webbrowser.open("https://tribler.org") self.dialog.setParent(None) self.dialog = None def read_settings(self): self.gui_settings = QSettings() center = QApplication.desktop().availableGeometry(self).center() pos = self.gui_settings.value( "pos", QPoint(center.x() - self.width() * 0.5, center.y() - self.height() * 0.5)) size = self.gui_settings.value("size", self.size()) self.move(pos) self.resize(size) def on_search_text_change(self, text): self.search_suggestion_mgr = TriblerRequestManager() self.search_suggestion_mgr.perform_request( "search/completions?q=%s" % text, self.on_received_search_completions) def on_received_search_completions(self, completions): self.received_search_completions.emit(completions) self.search_completion_model.setStringList(completions["completions"]) def received_variables(self, variables): self.video_player_page.video_player_port = variables["variables"][ "ports"]["video~port"] self.fetch_settings() def fetch_settings(self): self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("settings", self.received_settings, capture_errors=False) def received_settings(self, settings): # If we cannot receive the settings, stop Tribler with an option to send the crash report. if 'error' in settings: raise RuntimeError( TriblerRequestManager.get_message_from_error(settings)) else: self.tribler_settings = settings['settings'] # Disable various components based on the settings if not self.tribler_settings['search_community']['enabled']: self.window().top_search_bar.setHidden(True) if not self.tribler_settings['video']['enabled']: self.left_menu_button_video_player.setHidden(True) # process pending file requests (i.e. someone clicked a torrent file when Tribler was closed) # We do this after receiving the settings so we have the default download location. self.process_uri_request() def on_top_search_button_click(self): self.left_menu_button_search.setChecked(True) self.has_search_results = True self.clicked_menu_button_search() self.search_results_page.perform_search(self.top_search_bar.text()) self.search_request_mgr = TriblerRequestManager() self.search_request_mgr.perform_request( "search?q=%s" % self.top_search_bar.text(), None) def on_settings_button_click(self): self.deselect_all_menu_buttons() self.stackedWidget.setCurrentIndex(PAGE_SETTINGS) self.settings_page.load_settings() self.navigation_stack = [] self.hide_left_menu_playlist() def on_trust_button_click(self): self.deselect_all_menu_buttons() self.stackedWidget.setCurrentIndex(PAGE_TRUST) self.trust_page.load_trust_statistics() self.navigation_stack = [] self.hide_left_menu_playlist() def on_add_torrent_button_click(self, pos): menu = TriblerActionMenu(self) browse_files_action = QAction('Import torrent from file', self) browse_directory_action = QAction('Import torrents from directory', self) add_url_action = QAction('Import torrent from magnet/URL', self) browse_files_action.triggered.connect(self.on_add_torrent_browse_file) browse_directory_action.triggered.connect( self.on_add_torrent_browse_dir) add_url_action.triggered.connect(self.on_add_torrent_from_url) menu.addAction(browse_files_action) menu.addAction(browse_directory_action) menu.addAction(add_url_action) menu.exec_(self.mapToGlobal(self.add_torrent_button.pos())) def on_add_torrent_browse_file(self): filenames = QFileDialog.getOpenFileNames( self, "Please select the .torrent file", "", "Torrent files (*.torrent)") if len(filenames[0]) > 0: [ self.pending_uri_requests.append(u"file:%s" % filename) for filename in filenames[0] ] self.process_uri_request() def start_download_from_uri(self, uri): self.download_uri = uri if get_gui_setting(self.gui_settings, "ask_download_settings", True, is_bool=True): self.dialog = StartDownloadDialog(self.window().stackedWidget, self.download_uri) self.dialog.button_clicked.connect(self.on_start_download_action) self.dialog.show() self.start_download_dialog_active = True else: self.window().perform_start_download_request( self.download_uri, get_gui_setting(self.gui_settings, "default_anonymity_enabled", True, is_bool=True), get_gui_setting(self.gui_settings, "default_safeseeding_enabled", True, is_bool=True), self.tribler_settings['downloadconfig']['saveas'], [], 0) self.process_uri_request() def on_start_download_action(self, action): if action == 1: self.window().perform_start_download_request( self.download_uri, self.dialog.dialog_widget.anon_download_checkbox.isChecked(), self.dialog.dialog_widget.safe_seed_checkbox.isChecked(), self.dialog.dialog_widget.destination_input.currentText(), self.dialog.get_selected_files(), self.dialog.dialog_widget.files_list_view.topLevelItemCount()) self.dialog.request_mgr.cancel_request( ) # To abort the torrent info request self.dialog.setParent(None) self.dialog = None self.start_download_dialog_active = False if action == 0: # We do this after removing the dialog since process_uri_request is blocking self.process_uri_request() def on_add_torrent_browse_dir(self): chosen_dir = QFileDialog.getExistingDirectory( self, "Please select the directory containing the .torrent files", "", QFileDialog.ShowDirsOnly) if len(chosen_dir) != 0: self.selected_torrent_files = [ torrent_file for torrent_file in glob.glob(chosen_dir + "/*.torrent") ] self.dialog = ConfirmationDialog( self, "Add torrents from directory", "Are you sure you want to add %d torrents to Tribler?" % len(self.selected_torrent_files), [('ADD', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)]) self.dialog.button_clicked.connect( self.on_confirm_add_directory_dialog) self.dialog.show() def on_confirm_add_directory_dialog(self, action): if action == 0: for torrent_file in self.selected_torrent_files: escaped_uri = quote_plus( (u"file:%s" % torrent_file).encode('utf-8')) self.perform_start_download_request( escaped_uri, get_gui_setting(self.gui_settings, "default_anonymity_enabled", True, is_bool=True), get_gui_setting(self.gui_settings, "default_safeseeding_enabled", True, is_bool=True), self.tribler_settings['downloadconfig']['saveas'], [], 0) self.dialog.setParent(None) self.dialog = None def on_add_torrent_from_url(self): self.dialog = ConfirmationDialog( self, "Add torrent from URL/magnet link", "Please enter the URL/magnet link in the field below:", [('ADD', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)], show_input=True) self.dialog.dialog_widget.dialog_input.setPlaceholderText( 'URL/magnet link') self.dialog.button_clicked.connect( self.on_torrent_from_url_dialog_done) self.dialog.show() def on_torrent_from_url_dialog_done(self, action): uri = self.dialog.dialog_widget.dialog_input.text() # Remove first dialog self.dialog.setParent(None) self.dialog = None if action == 0: self.start_download_from_uri(uri) def on_download_added(self, result): if len(self.pending_uri_requests ) == 0: # Otherwise, we first process the remaining requests. self.window().left_menu_button_downloads.click() else: self.process_uri_request() def on_top_menu_button_click(self): if self.left_menu.isHidden(): self.left_menu.show() else: self.left_menu.hide() def deselect_all_menu_buttons(self, except_select=None): for button in self.menu_buttons: if button == except_select: button.setEnabled(False) continue button.setEnabled(True) if button == self.left_menu_button_search and not self.has_search_results: button.setEnabled(False) button.setChecked(False) def clicked_menu_button_home(self): self.deselect_all_menu_buttons(self.left_menu_button_home) self.stackedWidget.setCurrentIndex(PAGE_HOME) self.navigation_stack = [] self.hide_left_menu_playlist() def clicked_menu_button_search(self): self.deselect_all_menu_buttons(self.left_menu_button_search) self.stackedWidget.setCurrentIndex(PAGE_SEARCH_RESULTS) self.navigation_stack = [] self.hide_left_menu_playlist() def clicked_menu_button_discovered(self): self.deselect_all_menu_buttons(self.left_menu_button_discovered) self.stackedWidget.setCurrentIndex(PAGE_DISCOVERED) self.discovered_page.load_discovered_channels() self.navigation_stack = [] self.hide_left_menu_playlist() def clicked_menu_button_my_channel(self): self.deselect_all_menu_buttons(self.left_menu_button_my_channel) self.stackedWidget.setCurrentIndex(PAGE_EDIT_CHANNEL) self.edit_channel_page.load_my_channel_overview() self.navigation_stack = [] self.hide_left_menu_playlist() def clicked_menu_button_video_player(self): self.deselect_all_menu_buttons(self.left_menu_button_video_player) self.stackedWidget.setCurrentIndex(PAGE_VIDEO_PLAYER) self.navigation_stack = [] self.show_left_menu_playlist() def clicked_menu_button_downloads(self): self.deselect_all_menu_buttons(self.left_menu_button_downloads) self.stackedWidget.setCurrentIndex(PAGE_DOWNLOADS) self.navigation_stack = [] self.hide_left_menu_playlist() def clicked_menu_button_debug(self): self.debug_window = DebugWindow(self.tribler_settings) self.debug_window.show() def clicked_menu_button_subscriptions(self): self.deselect_all_menu_buttons(self.left_menu_button_subscriptions) self.subscribed_channels_page.load_subscribed_channels() self.stackedWidget.setCurrentIndex(PAGE_SUBSCRIBED_CHANNELS) self.navigation_stack = [] self.hide_left_menu_playlist() def hide_left_menu_playlist(self): self.left_menu_seperator.setHidden(True) self.left_menu_playlist_label.setHidden(True) self.left_menu_playlist.setHidden(True) def show_left_menu_playlist(self): self.left_menu_seperator.setHidden(False) self.left_menu_playlist_label.setHidden(False) self.left_menu_playlist.setHidden(False) def on_channel_item_click(self, channel_list_item): list_widget = channel_list_item.listWidget() from TriblerGUI.widgets.channel_list_item import ChannelListItem if isinstance(list_widget.itemWidget(channel_list_item), ChannelListItem): channel_info = channel_list_item.data(Qt.UserRole) self.channel_page.initialize_with_channel(channel_info) self.navigation_stack.append(self.stackedWidget.currentIndex()) self.stackedWidget.setCurrentIndex(PAGE_CHANNEL_DETAILS) def on_playlist_item_click(self, playlist_list_item): list_widget = playlist_list_item.listWidget() from TriblerGUI.widgets.playlist_list_item import PlaylistListItem if isinstance(list_widget.itemWidget(playlist_list_item), PlaylistListItem): playlist_info = playlist_list_item.data(Qt.UserRole) self.playlist_page.initialize_with_playlist(playlist_info) self.navigation_stack.append(self.stackedWidget.currentIndex()) self.stackedWidget.setCurrentIndex(PAGE_PLAYLIST_DETAILS) def on_page_back_clicked(self): prev_page = self.navigation_stack.pop() self.stackedWidget.setCurrentIndex(prev_page) def on_edit_channel_clicked(self): self.stackedWidget.setCurrentIndex(PAGE_EDIT_CHANNEL) self.navigation_stack = [] self.channel_page.on_edit_channel_clicked() def resizeEvent(self, _): # Resize home page cells cell_width = self.home_page_table_view.width( ) / 3 - 3 # We have some padding to the right cell_height = cell_width / 2 + 60 for i in range(0, 3): self.home_page_table_view.setColumnWidth(i, cell_width) self.home_page_table_view.setRowHeight(i, cell_height) self.resize_event.emit() def exit_full_screen(self): self.top_bar.show() self.left_menu.show() self.video_player_page.is_full_screen = False self.showNormal() def close_tribler(self): if not self.core_manager.shutting_down: self.show_loading_screen() self.gui_settings.setValue("pos", self.pos()) self.gui_settings.setValue("size", self.size()) if self.core_manager.use_existing_core: # Don't close the core that we are using QApplication.quit() self.core_manager.stop() self.core_manager.shutting_down = True self.downloads_page.stop_loading_downloads() def closeEvent(self, close_event): self.close_tribler() close_event.ignore() def keyReleaseEvent(self, event): if event.key() == Qt.Key_Escape: self.escape_pressed.emit() if self.isFullScreen(): self.exit_full_screen()
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.setStyleSheet(myStyleSheet(self)) self.MaxRecentFiles = 5 self.windowList = [] self.recentFileActs = [] self.curFile = '' self.setAcceptDrops(True) self. settings = QSettings("QTextEdit", "QTextEdit") self.myeditor = QTextEdit() #assert(self.locale().language() == QLocale.German) self.myeditor.setAcceptRichText(False) self.myeditor.setUndoRedoEnabled(True) self.myeditor.setStyleSheet(myStyleSheet(self)) self.myeditor.setContextMenuPolicy(Qt.CustomContextMenu) self.myeditor.customContextMenuRequested.connect(self.contextMenuRequested) self.createActions() self.createToolBars() self.createMenus() self.createStatusBar() self.setWindowIcon(QIcon.fromTheme("gnome-documents")) self.readSettings() self.myeditor.document().contentsChanged.connect(self.documentWasModified) self.setCurrentFile('') self.setCentralWidget(self.myeditor) self.myeditor.setFocus() def closeEvent(self, event): if self.maybeSave(): self.writeSettings() event.accept() else: event.ignore() def newFile(self): if self.maybeSave(): self.myeditor.clear() self.setCurrentFile('') def open(self): if self.maybeSave(): documents = QStandardPaths.standardLocations(QStandardPaths.DocumentsLocation)[0] fileName, _ = QFileDialog.getOpenFileName(self, "open File", documents, "Text Files (*.txt *.csv *.sh *.py) ;; all Files (*.*)") if fileName: self.loadFile(fileName) else: self.statusBar().showMessage("cancelled", 3000) def save(self): if not self.myeditor.toPlainText() == "": if self.myeditor.document().isModified(): if self.curFile: return self.saveFile(self.curFile) self.setCurrentFile(fileName) else: return self.saveAs() else: self.statusBar().showMessage("File '" + self.curFile + "' already saved", 3000) else: self.statusBar().showMessage("no Text") def saveAs(self): if not self.myeditor.toPlainText() == "": if self.curFile: fileName, _ = QFileDialog.getSaveFileName(self, "Save as...", self.curFile, "Text Files (*.txt)") else: documents = QStandardPaths.standardLocations(QStandardPaths.DocumentsLocation)[0] fileName, _ = QFileDialog.getSaveFileName(self, "Save as...", documents + "/newDocument.txt", "Text Files (*.txt)" ) if fileName: return self.saveFile(fileName) return False else: self.statusBar().showMessage("no Text") def contextMenuRequested(self, point): cmenu = QMenu() cmenu = self.myeditor.createStandardContextMenu() if not self.myeditor.textCursor().selectedText() == "": cmenu.addSeparator() cmenu.addAction(QIcon.fromTheme("edit-find-and-replace"),"replace all occurrences", self.replaceThis) cmenu.exec_(self.myeditor.mapToGlobal(point)) def replaceThis(self): if not self.myeditor.textCursor().selectedText() == "": rtext = self.myeditor.textCursor().selectedText() dlg = QInputDialog(self, Qt.Dialog) dlg.setOkButtonText("Replace") text = dlg.getText(self, "Replace","replace '" + rtext + "' with:", QLineEdit.Normal, "") oldtext = self.myeditor.document().toPlainText() if not (text[0] == ""): newtext = oldtext.replace(rtext, text[0]) self.myeditor.setPlainText(newtext) self.myeditor.document().setModified(True) def about(self): link = "<p><a title='Axel Schneider' href='http://goodoldsongs.jimdo.com' target='_blank'>Axel Schneider</a></p>" title = "über QTextEdit" message = ("<span style='text-shadow: #2e3436 2px 2px 2px; color: #6169e1; font-size: 24pt;font-weight: bold;'><strong>QTextEdit 1.2</strong></span></p><br><br>created by<h2 >" + link + "</h2> with PyQt5" "<br><br>Copyright © 2018 The Qt Company Ltd and other contributors." "<br>Qt and the Qt logo are trademarks of The Qt Company Ltd.") msg = QMessageBox(QMessageBox.Information, title, message, QMessageBox.NoButton, self, Qt.Dialog|Qt.NoDropShadowWindowHint).show() def documentWasModified(self): self.setWindowModified(self.myeditor.document().isModified()) def createActions(self): self.newAct = QAction(QIcon.fromTheme('document-new'), "&Neu", self, shortcut=QKeySequence.New, statusTip="new Document", triggered=self.newFile) self.openAct = QAction(QIcon.fromTheme('document-open'), "open File", self, shortcut=QKeySequence.Open, statusTip="open File", triggered=self.open) self.saveAct = QAction(QIcon.fromTheme('document-save'), "Save", self, shortcut=QKeySequence.Save, statusTip="save Document", triggered=self.save) self.saveAsAct = QAction(QIcon.fromTheme('document-save-as'),"Save as...", self, shortcut=QKeySequence.SaveAs, statusTip="save Document to new filename", triggered=self.saveAs) self.exitAct = QAction(QIcon.fromTheme('application-exit'),"Exit", self, shortcut="Ctrl+Q", statusTip="exit", triggered=self.close) self.cutAct = QAction(QIcon.fromTheme('edit-cut'), "Cut", self, shortcut=QKeySequence.Cut, statusTip="Cut", triggered=self.myeditor.cut) self.copyAct = QAction(QIcon.fromTheme('edit-copy'), "Copy", self, shortcut=QKeySequence.Copy, statusTip="Copy", triggered=self.myeditor.copy) self.pasteAct = QAction(QIcon.fromTheme('edit-paste'), "Paste", self, shortcut=QKeySequence.Paste, statusTip="Paste", triggered=self.myeditor.paste) self.undoAct = QAction(QIcon.fromTheme('edit-undo'), "Undo", self, shortcut=QKeySequence.Undo, statusTip="Undo", triggered=self.myeditor.undo) self.redoAct = QAction(QIcon.fromTheme('edit-redo'), "Redo", self, shortcut=QKeySequence.Redo, statusTip="Redo", triggered=self.myeditor.redo) self.aboutAct = QAction(QIcon.fromTheme('help-about'),"Info", self, statusTip="about QTextEdit", triggered=self.about) self.aboutQtAct = QAction(QIcon.fromTheme('help-about'),"über Qt", self, statusTip="über Qt", triggered=QApplication.instance().aboutQt) self.repAllAct = QPushButton("replace all") self.repAllAct.setFixedWidth(100) self.repAllAct.setIcon(QIcon.fromTheme("edit-find-and-replace")) self.repAllAct.setStatusTip("replace all") self.repAllAct.clicked.connect(self.replaceAll) self.cutAct.setEnabled(False) self.copyAct.setEnabled(False) self.myeditor.copyAvailable.connect(self.cutAct.setEnabled) self.myeditor.copyAvailable.connect(self.copyAct.setEnabled) self.undoAct.setEnabled(False) self.redoAct.setEnabled(False) self.myeditor.undoAvailable.connect(self.undoAct.setEnabled) self.myeditor.redoAvailable.connect(self.redoAct.setEnabled) ### print preview self.printPreviewAct = QAction("Print Preview", self, shortcut=QKeySequence.Print,statusTip="Print Preview", triggered=self.handlePrintPreview) self.printPreviewAct.setIcon(QIcon.fromTheme("document-print-preview")) ### print self.printAct = QAction("print Document", self, shortcut=QKeySequence.Print,statusTip="print Document", triggered=self.handlePrint) self.printAct.setIcon(QIcon.fromTheme("document-print")) for i in range(self.MaxRecentFiles): self.recentFileActs.append( QAction(self, visible=False, triggered=self.openRecentFile)) def findText(self): word = self.findfield.text() if self.myeditor.find(word): self.statusBar().showMessage("found '" + word + "'", 2000) else: self.myeditor.moveCursor(QTextCursor.Start) if self.myeditor.find(word): return else: self.statusBar().showMessage("found nothing", 3000) def replaceAll(self): oldtext = self.findfield.text() newtext = self.replacefield.text() if not oldtext == "": h = self.myeditor.toHtml().replace(oldtext, newtext) self.myeditor.setText(h) self.setModified(True) self.statusBar().showMessage("all replaced", 3000) else: self.statusBar().showMessage("nothing to replace", 3000) def replaceOne(self): oldtext = self.findfield.text() newtext = self.replacefield.text() if not oldtext == "": h = self.myeditor.toHtml().replace(oldtext, newtext, 1) self.myeditor.setText(h) self.setModified(True) self.statusBar().showMessage("1 replaced", 3000) else: self.statusBar().showMessage("nothing to replace", 3000) def openRecentFile(self): action = self.sender() if action: if (self.maybeSave()): self.loadFile(action.data()) def createMenus(self): self.fileMenu = self.menuBar().addMenu("&File") self.separatorAct = self.fileMenu.addSeparator() self.fileMenu.addAction(self.newAct) self.fileMenu.addAction(self.openAct) self.fileMenu.addAction(self.saveAct) self.fileMenu.addAction(self.saveAsAct) self.fileMenu.addSeparator() for i in range(self.MaxRecentFiles): self.fileMenu.addAction(self.recentFileActs[i]) self.updateRecentFileActions() self.fileMenu.addSeparator() self.clearRecentAct = QAction("clear List", self, triggered=self.clearRecentFiles) self.clearRecentAct.setIcon(QIcon.fromTheme("edit-clear")) self.fileMenu.addAction(self.clearRecentAct) self.fileMenu.addSeparator() self.fileMenu.addAction(self.exitAct) self.editMenu = self.menuBar().addMenu("&Edit") self.editMenu.addAction(self.undoAct) self.editMenu.addAction(self.redoAct) self.editMenu.addSeparator(); self.editMenu.addAction(self.cutAct) self.editMenu.addAction(self.copyAct) self.editMenu.addAction(self.pasteAct) self.menuBar().addSeparator() self.helpMenu = self.menuBar().addMenu("&Help") self.helpMenu.addAction(self.aboutAct) def createToolBars(self): self.fileToolBar = self.addToolBar("File") self.fileToolBar.setIconSize(QSize(16, 16)) self.fileToolBar.addAction(self.newAct) self.fileToolBar.addAction(self.openAct) self.fileToolBar.addAction(self.saveAct) self.fileToolBar.addAction(self.saveAsAct) self.fileToolBar.addSeparator() self.fileToolBar.addAction(self.printPreviewAct) self.fileToolBar.addAction(self.printAct) self.fileToolBar.setStyleSheet("QToolBar { border: 0px }") self.fileToolBar.setMovable(False) self.setContextMenuPolicy(Qt.NoContextMenu) self.editToolBar = self.addToolBar("Edit") self.editToolBar.setIconSize(QSize(16, 16)) self.editToolBar.addAction(self.undoAct) self.editToolBar.addAction(self.redoAct) self.editToolBar.addSeparator() self.editToolBar.addAction(self.cutAct) self.editToolBar.addAction(self.copyAct) self.editToolBar.addAction(self.pasteAct) self.editToolBar.setMovable(False) self.editToolBar.setStyleSheet("QToolBar { border: 0px }") ### find / replace toolbar self.addToolBarBreak() self.findToolBar = self.addToolBar("Find") self.findToolBar.setIconSize(QSize(16, 16)) self.findfield = QLineEdit() self.findfield.addAction(QIcon.fromTheme("edit-find"), 0) self.findfield.setClearButtonEnabled(True) self.findfield.setFixedWidth(200) self.findfield.setPlaceholderText("find") self.findfield.setStatusTip("press RETURN to find") self.findfield.setText("") self.findfield.returnPressed.connect(self.findText) self.findToolBar.addWidget(self.findfield) self.replacefield = QLineEdit() self.replacefield.addAction(QIcon.fromTheme("edit-find-replace"), 0) self.replacefield.setClearButtonEnabled(True) self.replacefield.setFixedWidth(200) self.replacefield.setPlaceholderText("replace with") self.replacefield.setStatusTip("press RETURN to replace first only") self.replacefield.returnPressed.connect(self.replaceOne) self.findToolBar.addSeparator() self.findToolBar.addWidget(self.replacefield) self.findToolBar.addSeparator() self.findToolBar.addWidget(self.repAllAct) self.findToolBar.setMovable(False) self.findToolBar.setStyleSheet("QToolBar { border: 0px }") def createStatusBar(self): self.statusBar().setStyleSheet(myStyleSheet(self)) self.statusBar().showMessage("Welcome") self.DigitalClock = DigitalClock() self.DigitalClock.setStyleSheet("QLCDNumber {padding: 2px, 2px 2px 2px; border: 0px solid #2e3436; color: #3465a4; background-color: transparent }") self.statusBar().addPermanentWidget(self.DigitalClock) def readSettings(self): pos = self.settings.value("pos", QPoint(200, 200)) size = self.settings.value("size", QSize(400, 400)) self.resize(size) self.move(pos) def writeSettings(self): self.settings.setValue("pos", self.pos()) self.settings.setValue("size", self.size()) def maybeSave(self): if self.myeditor.document().isModified(): ret = QMessageBox.warning(self, "QTextEdit Message", "Document was changed.\nSave changes?", QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel, defaultButton = QMessageBox.Save) if ret == QMessageBox.Save: return self.save() if ret == QMessageBox.Cancel: return False return True def loadFile(self, fileName): file = QFile(fileName) if not file.open(QFile.ReadOnly | QFile.Text): QMessageBox.warning(self, "Message", "Cannot read file %s:\n%s." % (fileName, file.errorString())) return infile = QTextStream(file) QApplication.setOverrideCursor(Qt.WaitCursor) self.myeditor.setPlainText(infile.readAll()) QApplication.restoreOverrideCursor() self.setCurrentFile(fileName) self.statusBar().showMessage("File '" + fileName + "' loaded", 3000) def saveFile(self, fileName): file = QFile(fileName) if not file.open(QFile.WriteOnly | QFile.Text): QMessageBox.warning(self, "Message", "Cannot write file %s:\n%s." % (fileName, file.errorString())) return False outfile = QTextStream(file) QApplication.setOverrideCursor(Qt.WaitCursor) outfile << self.myeditor.toPlainText() QApplication.restoreOverrideCursor() self.setCurrentFile(fileName); self.statusBar().showMessage("File '" + fileName + "' saved", 3000) return True def setCurrentFile(self, fileName): self.curFile = fileName self.myeditor.document().setModified(False) self.setWindowModified(False) if self.curFile: self.setWindowTitle(self.strippedName(self.curFile) + "[*]") else: self.setWindowTitle('New.txt' + "[*]") files = self.settings.value('recentFileList', []) if not files == "": try: files.remove(fileName) except ValueError: pass if fileName: files.insert(0, fileName) del files[self.MaxRecentFiles:] self.settings.setValue('recentFileList', files) self.updateRecentFileActions() def updateRecentFileActions(self): mytext = "" files = self.settings.value('recentFileList', []) numRecentFiles = min(len(files), self.MaxRecentFiles) # if not files == "": for i in range(numRecentFiles): text = "&%d %s" % (i + 1, self.strippedName(files[i])) self.recentFileActs[i].setText(text) self.recentFileActs[i].setData(files[i]) self.recentFileActs[i].setVisible(True) self.recentFileActs[i].setIcon(QIcon.fromTheme("text-x-generic")) for j in range(numRecentFiles, self.MaxRecentFiles): self.recentFileActs[j].setVisible(False) self.separatorAct.setVisible((numRecentFiles > 0)) def clearRecentFiles(self, fileName): self.settings.clear() self.updateRecentFileActions() def strippedName(self, fullFileName): return QFileInfo(fullFileName).fileName() def msgbox(self, message): QMessageBox.warning(self, "Message", message) def handlePrint(self): if self.myeditor.toPlainText() == "": self.statusBar().showMessage("no Text to print") self.msgbox("kein Text zum Drucken") else: dialog = QtPrintSupport.QPrintDialog() if dialog.exec_() == QDialog.Accepted: self.handlePaintRequest(dialog.printer()) self.statusBar().showMessage("Document printed") def handlePrintPreview(self): if self.myeditor.toPlainText() == "": self.statusBar().showMessage("no text to preview") self.msgbox("kein Text für Vorschau") else: dialog = QtPrintSupport.QPrintPreviewDialog() dialog.setGeometry(10, 0, self.width() - 60, self.height() - 60) dialog.paintRequested.connect(self.handlePaintRequest) dialog.exec_() self.statusBar().showMessage("Preview closed") def handlePaintRequest(self, printer): printer.setDocName(self.curFile) document = self.myeditor.document() document.print_(printer) def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: event.ignore() def dropEvent(self, event): f = str(event.mimeData().urls()[0].toLocalFile()) self.loadFile(f)
class TriblerWindow(QMainWindow): resize_event = pyqtSignal() escape_pressed = pyqtSignal() tribler_crashed = pyqtSignal(str) received_search_completions = pyqtSignal(object) def __init__(self, core_args=None, core_env=None, api_port=None, api_key=None): QMainWindow.__init__(self) self._logger = logging.getLogger(self.__class__.__name__) QCoreApplication.setOrganizationDomain("nl") QCoreApplication.setOrganizationName("TUDelft") QCoreApplication.setApplicationName("Tribler") self.setWindowIcon(QIcon(QPixmap(get_image_path('tribler.png')))) self.gui_settings = QSettings('nl.tudelft.tribler') api_port = api_port or int(get_gui_setting(self.gui_settings, "api_port", DEFAULT_API_PORT)) api_key = api_key or get_gui_setting(self.gui_settings, "api_key", hexlify(os.urandom(16)).encode('utf-8')) self.gui_settings.setValue("api_key", api_key) api_port = get_first_free_port(start=api_port, limit=100) request_manager.port, request_manager.key = api_port, api_key self.tribler_started = False self.tribler_settings = None # TODO: move version_id to tribler_common and get core version in the core crash message self.tribler_version = version_id self.debug_window = None self.error_handler = ErrorHandler(self) self.core_manager = CoreManager(api_port, api_key, self.error_handler) self.pending_requests = {} self.pending_uri_requests = [] self.download_uri = None self.dialog = None self.create_dialog = None self.chosen_dir = None self.new_version_dialog = None self.start_download_dialog_active = False self.selected_torrent_files = [] self.has_search_results = False self.last_search_query = None self.last_search_time = None self.start_time = time.time() self.token_refresh_timer = None self.shutdown_timer = None self.add_torrent_url_dialog_active = False sys.excepthook = self.error_handler.gui_error uic.loadUi(get_ui_file_path('mainwindow.ui'), self) TriblerRequestManager.window = self self.tribler_status_bar.hide() self.token_balance_widget.mouseReleaseEvent = self.on_token_balance_click def on_state_update(new_state): self.loading_text_label.setText(new_state) connect(self.core_manager.core_state_update, on_state_update) self.magnet_handler = MagnetHandler(self.window) QDesktopServices.setUrlHandler("magnet", self.magnet_handler, "on_open_magnet_link") self.debug_pane_shortcut = QShortcut(QKeySequence("Ctrl+d"), self) connect(self.debug_pane_shortcut.activated, self.clicked_menu_button_debug) self.import_torrent_shortcut = QShortcut(QKeySequence("Ctrl+o"), self) connect(self.import_torrent_shortcut.activated, self.on_add_torrent_browse_file) self.add_torrent_url_shortcut = QShortcut(QKeySequence("Ctrl+i"), self) connect(self.add_torrent_url_shortcut.activated, self.on_add_torrent_from_url) connect(self.top_search_bar.clicked, self.clicked_search_bar) # Remove the focus rect on OS X for widget in self.findChildren(QLineEdit) + self.findChildren(QListWidget) + self.findChildren(QTreeWidget): widget.setAttribute(Qt.WA_MacShowFocusRect, 0) self.menu_buttons = [ self.left_menu_button_downloads, self.left_menu_button_discovered, self.left_menu_button_trust_graph, self.left_menu_button_popular, ] hide_xxx = get_gui_setting(self.gui_settings, "family_filter", True, is_bool=True) self.search_results_page.initialize_content_page(hide_xxx=hide_xxx) self.search_results_page.channel_torrents_filter_input.setHidden(True) self.settings_page.initialize_settings_page() self.downloads_page.initialize_downloads_page() self.loading_page.initialize_loading_page() self.discovering_page.initialize_discovering_page() self.discovered_page.initialize_content_page(hide_xxx=hide_xxx) self.popular_page.initialize_content_page(hide_xxx=hide_xxx, controller_class=PopularContentTableViewController) self.trust_page.initialize_trust_page() self.trust_graph_page.initialize_trust_graph() self.stackedWidget.setCurrentIndex(PAGE_LOADING) # Create the system tray icon if QSystemTrayIcon.isSystemTrayAvailable(): self.tray_icon = QSystemTrayIcon() use_monochrome_icon = get_gui_setting(self.gui_settings, "use_monochrome_icon", False, is_bool=True) self.update_tray_icon(use_monochrome_icon) # Create the tray icon menu menu = self.create_add_torrent_menu() show_downloads_action = QAction('Show downloads', self) connect(show_downloads_action.triggered, self.clicked_menu_button_downloads) token_balance_action = QAction('Show token balance', self) connect(token_balance_action.triggered, lambda _: self.on_token_balance_click(None)) quit_action = QAction('Quit Tribler', self) connect(quit_action.triggered, self.close_tribler) menu.addSeparator() menu.addAction(show_downloads_action) menu.addAction(token_balance_action) menu.addSeparator() menu.addAction(quit_action) self.tray_icon.setContextMenu(menu) else: self.tray_icon = None self.left_menu_button_debug.setHidden(True) self.top_menu_button.setHidden(True) self.left_menu.setHidden(True) self.token_balance_widget.setHidden(True) self.settings_button.setHidden(True) self.add_torrent_button.setHidden(True) self.top_search_bar.setHidden(True) # Set various icons self.top_menu_button.setIcon(QIcon(get_image_path('menu.png'))) self.search_completion_model = QStringListModel() completer = QCompleter() completer.setModel(self.search_completion_model) completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) self.item_delegate = QStyledItemDelegate() completer.popup().setItemDelegate(self.item_delegate) completer.popup().setStyleSheet( """ QListView { background-color: #404040; } QListView::item { color: #D0D0D0; padding-top: 5px; padding-bottom: 5px; } QListView::item:hover { background-color: #707070; } """ ) self.top_search_bar.setCompleter(completer) # Toggle debug if developer mode is enabled self.window().left_menu_button_debug.setHidden( not get_gui_setting(self.gui_settings, "debug", False, is_bool=True) ) # Start Tribler self.core_manager.start(core_args=core_args, core_env=core_env) connect(self.core_manager.events_manager.torrent_finished, self.on_torrent_finished) connect(self.core_manager.events_manager.new_version_available, self.on_new_version_available) connect(self.core_manager.events_manager.tribler_started, self.on_tribler_started) connect(self.core_manager.events_manager.low_storage_signal, self.on_low_storage) connect(self.core_manager.events_manager.tribler_shutdown_signal, self.on_tribler_shutdown_state_update) connect(self.core_manager.events_manager.config_error_signal, self.on_config_error_signal) # Install signal handler for ctrl+c events def sigint_handler(*_): self.close_tribler() signal.signal(signal.SIGINT, sigint_handler) # Resize the window according to the settings center = QApplication.desktop().availableGeometry(self).center() pos = self.gui_settings.value("pos", QPoint(center.x() - self.width() * 0.5, center.y() - self.height() * 0.5)) size = self.gui_settings.value("size", self.size()) self.move(pos) self.resize(size) self.show() self.add_to_channel_dialog = AddToChannelDialog(self.window()) self.add_torrent_menu = self.create_add_torrent_menu() self.add_torrent_button.setMenu(self.add_torrent_menu) self.channels_menu_list = self.findChild(ChannelsMenuListWidget, "channels_menu_list") connect(self.channels_menu_list.itemClicked, self.open_channel_contents_page) # The channels content page is only used to show subscribed channels, so we always show xxx # contents in it. connect( self.core_manager.events_manager.node_info_updated, lambda data: self.channels_menu_list.reload_if_necessary([data]), ) connect(self.left_menu_button_new_channel.clicked, self.create_new_channel) def create_new_channel(self, checked): # TODO: DRY this with tablecontentmodel, possibly using QActions def create_channel_callback(channel_name): TriblerNetworkRequest( "channels/mychannel/0/channels", self.channels_menu_list.load_channels, method='POST', raw_data=json.dumps({"name": channel_name}) if channel_name else None, ) NewChannelDialog(self, create_channel_callback) def open_channel_contents_page(self, channel_list_item): if not channel_list_item.flags() & Qt.ItemIsEnabled: return self.channel_contents_page.initialize_root_model_from_channel_info(channel_list_item.channel_info) self.stackedWidget.setCurrentIndex(PAGE_CHANNEL_CONTENTS) self.deselect_all_menu_buttons() def update_tray_icon(self, use_monochrome_icon): if not QSystemTrayIcon.isSystemTrayAvailable() or not self.tray_icon: return if use_monochrome_icon: self.tray_icon.setIcon(QIcon(QPixmap(get_image_path('monochrome_tribler.png')))) else: self.tray_icon.setIcon(QIcon(QPixmap(get_image_path('tribler.png')))) self.tray_icon.show() def delete_tray_icon(self): if self.tray_icon: try: self.tray_icon.deleteLater() except RuntimeError: # The tray icon might have already been removed when unloading Qt. # This is due to the C code actually being asynchronous. logging.debug("Tray icon already removed, no further deletion necessary.") self.tray_icon = None def on_low_storage(self, _): """ Dealing with low storage space available. First stop the downloads and the core manager and ask user to user to make free space. :return: """ def close_tribler_gui(): self.close_tribler() # Since the core has already stopped at this point, it will not terminate the GUI. # So, we quit the GUI separately here. if not QApplication.closingDown(): QApplication.quit() self.downloads_page.stop_loading_downloads() self.core_manager.stop(False) close_dialog = ConfirmationDialog( self.window(), tr("<b>CRITICAL ERROR</b>"), tr( "You are running low on disk space (<100MB). Please make sure to have " "sufficient free space available and restart Tribler again." ), [(tr("Close Tribler"), BUTTON_TYPE_NORMAL)], ) connect(close_dialog.button_clicked, lambda _: close_tribler_gui()) close_dialog.show() def on_torrent_finished(self, torrent_info): if "hidden" not in torrent_info or not torrent_info["hidden"]: self.tray_show_message(tr("Download finished"), tr("Download of %s has finished.") % {torrent_info['name']}) def show_loading_screen(self): self.top_menu_button.setHidden(True) self.left_menu.setHidden(True) self.token_balance_widget.setHidden(True) self.settings_button.setHidden(True) self.add_torrent_button.setHidden(True) self.top_search_bar.setHidden(True) self.stackedWidget.setCurrentIndex(PAGE_LOADING) def tray_set_tooltip(self, message): """ Set a tooltip message for the tray icon, if possible. :param message: the message to display on hover """ if self.tray_icon: try: self.tray_icon.setToolTip(message) except RuntimeError as e: logging.error("Failed to set tray tooltip: %s", str(e)) def tray_show_message(self, title, message): """ Show a message at the tray icon, if possible. :param title: the title of the message :param message: the message to display """ if self.tray_icon: try: self.tray_icon.showMessage(title, message) except RuntimeError as e: logging.error("Failed to set tray message: %s", str(e)) def on_tribler_started(self, version): if self.tribler_started: logging.warning("Received duplicate Tribler Core started event") return self.tribler_started = True self.tribler_version = version self.top_menu_button.setHidden(False) self.left_menu.setHidden(False) self.token_balance_widget.setHidden(False) self.settings_button.setHidden(False) self.add_torrent_button.setHidden(False) self.top_search_bar.setHidden(False) self.fetch_settings() self.downloads_page.start_loading_downloads() self.setAcceptDrops(True) self.setWindowTitle(f"Tribler {self.tribler_version}") autocommit_enabled = ( get_gui_setting(self.gui_settings, "autocommit_enabled", True, is_bool=True) if self.gui_settings else True ) self.channel_contents_page.initialize_content_page(autocommit_enabled=autocommit_enabled, hide_xxx=False) hide_xxx = get_gui_setting(self.gui_settings, "family_filter", True, is_bool=True) self.discovered_page.initialize_root_model( DiscoveredChannelsModel( channel_info={"name": tr("Discovered channels")}, endpoint_url="channels", hide_xxx=hide_xxx ) ) connect(self.core_manager.events_manager.discovered_channel, self.discovered_page.model.on_new_entry_received) self.popular_page.initialize_root_model( PopularTorrentsModel(channel_info={"name": "Popular torrents"}, hide_xxx=hide_xxx) ) self.popular_page.explanation_text.setText( tr("This page show the list of popular torrents collected by Tribler during the last 24 hours.") ) self.popular_page.explanation_container.setHidden(False) self.add_to_channel_dialog.load_channel(0) if not self.gui_settings.value("first_discover", False) and not self.core_manager.use_existing_core: connect(self.core_manager.events_manager.discovered_channel, self.stop_discovering) self.window().gui_settings.setValue("first_discover", True) self.discovering_page.is_discovering = True self.stackedWidget.setCurrentIndex(PAGE_DISCOVERING) else: self.clicked_menu_button_discovered() self.left_menu_button_discovered.setChecked(True) self.channels_menu_list.load_channels() def stop_discovering(self, response): if not self.discovering_page.is_discovering: return disconnect(self.core_manager.events_manager.discovered_channel, self.stop_discovering) self.discovering_page.is_discovering = False if self.stackedWidget.currentIndex() == PAGE_DISCOVERING: self.clicked_menu_button_discovered() self.left_menu_button_discovered.setChecked(True) def on_events_started(self, json_dict): self.setWindowTitle(f"Tribler {json_dict['version']}") def show_status_bar(self, message): self.tribler_status_bar_label.setText(message) self.tribler_status_bar.show() def hide_status_bar(self): self.tribler_status_bar.hide() def process_uri_request(self): """ Process a URI request if we have one in the queue. """ if len(self.pending_uri_requests) == 0: return uri = self.pending_uri_requests.pop() if uri.startswith('file') or uri.startswith('magnet'): self.start_download_from_uri(uri) def update_recent_download_locations(self, destination): # Save the download location to the GUI settings current_settings = get_gui_setting(self.gui_settings, "recent_download_locations", "") recent_locations = current_settings.split(",") if len(current_settings) > 0 else [] if isinstance(destination, str): destination = destination.encode('utf-8') encoded_destination = hexlify(destination) if encoded_destination in recent_locations: recent_locations.remove(encoded_destination) recent_locations.insert(0, encoded_destination) if len(recent_locations) > 5: recent_locations = recent_locations[:5] self.gui_settings.setValue("recent_download_locations", ','.join(recent_locations)) def perform_start_download_request( self, uri, anon_download, safe_seeding, destination, selected_files, total_files=0, add_to_channel=False, callback=None, ): # Check if destination directory is writable is_writable, error = is_dir_writable(destination) if not is_writable: gui_error_message = tr( "Insufficient write permissions to <i>%s</i> directory. Please add proper " "write permissions on the directory and add the torrent again. %s" ) % (destination, error) ConfirmationDialog.show_message( self.window(), tr("Download error <i>%s</i>") % uri, gui_error_message, "OK" ) return selected_files_list = [] if len(selected_files) != total_files: # Not all files included selected_files_list = [filename for filename in selected_files] anon_hops = int(self.tribler_settings['download_defaults']['number_hops']) if anon_download else 0 safe_seeding = 1 if safe_seeding else 0 post_data = { "uri": uri, "anon_hops": anon_hops, "safe_seeding": safe_seeding, "destination": destination, "selected_files": selected_files_list, } TriblerNetworkRequest( "downloads", callback if callback else self.on_download_added, method='PUT', data=post_data ) self.update_recent_download_locations(destination) if add_to_channel: def on_add_button_pressed(channel_id): post_data = {} if uri.startswith("file:"): with open(uri[5:], "rb") as torrent_file: post_data['torrent'] = b64encode(torrent_file.read()).decode('utf8') elif uri.startswith("magnet:"): post_data['uri'] = uri if post_data: TriblerNetworkRequest( f"channels/mychannel/{channel_id}/torrents", lambda _: self.tray_show_message(tr("Channel update"), tr("Torrent(s) added to your channel")), method='PUT', data=post_data, ) self.window().add_to_channel_dialog.show_dialog(on_add_button_pressed, confirm_button_text="Add torrent") def on_new_version_available(self, version): if version == str(self.gui_settings.value('last_reported_version')): return # To prevent multiple dialogs on top of each other, # close any existing dialog first. if self.new_version_dialog: self.new_version_dialog.close_dialog() self.new_version_dialog = None self.new_version_dialog = ConfirmationDialog( self, tr("New version available"), tr("Version %s of Tribler is available.Do you want to visit the " "website to download the newest version?") % version, [(tr("IGNORE"), BUTTON_TYPE_NORMAL), (tr("LATER"), BUTTON_TYPE_NORMAL), (tr("OK"), BUTTON_TYPE_NORMAL)], ) connect(self.new_version_dialog.button_clicked, lambda action: self.on_new_version_dialog_done(version, action)) self.new_version_dialog.show() def on_new_version_dialog_done(self, version, action): if action == 0: # ignore self.gui_settings.setValue("last_reported_version", version) elif action == 2: # ok import webbrowser webbrowser.open("https://tribler.org") if self.new_version_dialog: self.new_version_dialog.close_dialog() self.new_version_dialog = None def on_search_text_change(self, text): # We do not want to bother the database on petty 1-character queries if len(text) < 2: return TriblerNetworkRequest( "search/completions", self.on_received_search_completions, url_params={'q': sanitize_for_fts(text)} ) def on_received_search_completions(self, completions): if completions is None: return self.received_search_completions.emit(completions) self.search_completion_model.setStringList(completions["completions"]) def fetch_settings(self): TriblerNetworkRequest("settings", self.received_settings, capture_core_errors=False) def received_settings(self, settings): if not settings: return # If we cannot receive the settings, stop Tribler with an option to send the crash report. if 'error' in settings: raise RuntimeError(TriblerRequestManager.get_message_from_error(settings)) # If there is any pending dialog (likely download dialog or error dialog of setting not available), # close the dialog if self.dialog: self.dialog.close_dialog() self.dialog = None self.tribler_settings = settings['settings'] self.downloads_all_button.click() # process pending file requests (i.e. someone clicked a torrent file when Tribler was closed) # We do this after receiving the settings so we have the default download location. self.process_uri_request() # Set token balance refresh timer and load the token balance self.token_refresh_timer = QTimer() connect(self.token_refresh_timer.timeout, self.load_token_balance) self.token_refresh_timer.start(60000) self.load_token_balance() def on_top_search_button_click(self): current_ts = time.time() query = self.top_search_bar.text() if ( self.last_search_query and self.last_search_time and self.last_search_query == self.top_search_bar.text() and current_ts - self.last_search_time < 1 ): logging.info("Same search query already sent within 500ms so dropping this one") return if not query: return self.has_search_results = True self.search_results_page.initialize_root_model( SearchResultsModel( channel_info={"name": (tr("Search results for %s") % query) if len(query) < 50 else f"{query[:50]}..."}, endpoint_url="search", hide_xxx=get_gui_setting(self.gui_settings, "family_filter", True, is_bool=True), text_filter=to_fts_query(query), type_filter=[REGULAR_TORRENT, CHANNEL_TORRENT, COLLECTION_NODE], ) ) self.clicked_search_bar() # Trigger remote search self.search_results_page.preview_clicked() self.last_search_query = query self.last_search_time = current_ts def on_settings_button_click(self): self.deselect_all_menu_buttons() self.stackedWidget.setCurrentIndex(PAGE_SETTINGS) self.settings_page.load_settings() def on_token_balance_click(self, _): self.raise_window() self.deselect_all_menu_buttons() self.stackedWidget.setCurrentIndex(PAGE_TRUST) self.load_token_balance() self.trust_page.load_history() def load_token_balance(self): TriblerNetworkRequest("bandwidth/statistics", self.received_bandwidth_statistics, capture_core_errors=False) def received_bandwidth_statistics(self, statistics): if not statistics or "statistics" not in statistics: return self.trust_page.received_bandwidth_statistics(statistics) statistics = statistics["statistics"] balance = statistics["total_given"] - statistics["total_taken"] self.set_token_balance(balance) # If trust page is currently visible, then load the graph as well if self.stackedWidget.currentIndex() == PAGE_TRUST: self.trust_page.load_history() def set_token_balance(self, balance): if abs(balance) > 1024 ** 4: # Balance is over a TB balance /= 1024.0 ** 4 self.token_balance_label.setText(f"{balance:.1f} TB") elif abs(balance) > 1024 ** 3: # Balance is over a GB balance /= 1024.0 ** 3 self.token_balance_label.setText(f"{balance:.1f} GB") else: balance /= 1024.0 ** 2 self.token_balance_label.setText("%d MB" % balance) def raise_window(self): self.setWindowState(self.windowState() & ~Qt.WindowMinimized | Qt.WindowActive) self.raise_() self.activateWindow() def create_add_torrent_menu(self): """ Create a menu to add new torrents. Shows when users click on the tray icon or the big plus button. """ menu = TriblerActionMenu(self) browse_files_action = QAction(tr("Import torrent from file"), self) browse_directory_action = QAction(tr("Import torrent(s) from directory"), self) add_url_action = QAction(tr("Import torrent from magnet/URL"), self) create_torrent_action = QAction(tr("Create torrent from file(s)"), self) connect(browse_files_action.triggered, self.on_add_torrent_browse_file) connect(browse_directory_action.triggered, self.on_add_torrent_browse_dir) connect(add_url_action.triggered, self.on_add_torrent_from_url) connect(create_torrent_action.triggered, self.on_create_torrent) menu.addAction(browse_files_action) menu.addAction(browse_directory_action) menu.addAction(add_url_action) menu.addSeparator() menu.addAction(create_torrent_action) return menu def on_create_torrent(self, checked): if self.create_dialog: self.create_dialog.close_dialog() self.create_dialog = CreateTorrentDialog(self) connect(self.create_dialog.create_torrent_notification, self.on_create_torrent_updates) self.create_dialog.show() def on_create_torrent_updates(self, update_dict): self.tray_show_message(tr("Torrent updates"), update_dict['msg']) def on_add_torrent_browse_file(self, index): filenames = QFileDialog.getOpenFileNames( self, tr("Please select the .torrent file"), QDir.homePath(), tr("Torrent files%s") % " (*.torrent)" ) if len(filenames[0]) > 0: for filename in filenames[0]: self.pending_uri_requests.append(f"file:{quote(filename)}") self.process_uri_request() def start_download_from_uri(self, uri): uri = uri.decode('utf-8') if isinstance(uri, bytes) else uri self.download_uri = uri if get_gui_setting(self.gui_settings, "ask_download_settings", True, is_bool=True): # FIXME: instead of using this workaround, make sure the settings are _available_ by this moment # If tribler settings is not available, fetch the settings and inform the user to try again. if not self.tribler_settings: self.fetch_settings() self.dialog = ConfirmationDialog.show_error( self, tr("Download Error"), tr("Tribler settings is not available yet. Fetching it now. Please try again later."), ) # By re-adding the download uri to the pending list, the request is re-processed # when the settings is received self.pending_uri_requests.append(uri) return # Clear any previous dialog if exists if self.dialog: self.dialog.close_dialog() self.dialog = None self.dialog = StartDownloadDialog(self, self.download_uri) connect(self.dialog.button_clicked, self.on_start_download_action) self.dialog.show() self.start_download_dialog_active = True else: # FIXME: instead of using this workaround, make sure the settings are _available_ by this moment # In the unlikely scenario that tribler settings are not available yet, try to fetch settings again and # add the download uri back to self.pending_uri_requests to process again. if not self.tribler_settings: self.fetch_settings() if self.download_uri not in self.pending_uri_requests: self.pending_uri_requests.append(self.download_uri) return self.window().perform_start_download_request( self.download_uri, self.window().tribler_settings['download_defaults']['anonymity_enabled'], self.window().tribler_settings['download_defaults']['safeseeding_enabled'], self.tribler_settings['download_defaults']['saveas'], [], ) self.process_uri_request() def on_start_download_action(self, action): if action == 1: if self.dialog and self.dialog.dialog_widget: self.window().perform_start_download_request( self.download_uri, self.dialog.dialog_widget.anon_download_checkbox.isChecked(), self.dialog.dialog_widget.safe_seed_checkbox.isChecked(), self.dialog.dialog_widget.destination_input.currentText(), self.dialog.get_selected_files(), self.dialog.dialog_widget.files_list_view.topLevelItemCount(), add_to_channel=self.dialog.dialog_widget.add_to_channel_checkbox.isChecked(), ) else: ConfirmationDialog.show_error( self, tr("Tribler UI Error"), tr("Something went wrong. Please try again.") ) logging.exception("Error while trying to download. Either dialog or dialog.dialog_widget is None") if self.dialog: self.dialog.close_dialog() self.dialog = None self.start_download_dialog_active = False if action == 0: # We do this after removing the dialog since process_uri_request is blocking self.process_uri_request() def on_add_torrent_browse_dir(self, checked): chosen_dir = QFileDialog.getExistingDirectory( self, tr("Please select the directory containing the .torrent files"), QDir.homePath(), QFileDialog.ShowDirsOnly, ) self.chosen_dir = chosen_dir if len(chosen_dir) != 0: self.selected_torrent_files = [torrent_file for torrent_file in glob.glob(chosen_dir + "/*.torrent")] self.dialog = ConfirmationDialog( self, tr("Add torrents from directory"), tr("Add %s torrent files from the following directory to your Tribler channel: \n\n%s") % (len(self.selected_torrent_files), chosen_dir), [(tr("ADD"), BUTTON_TYPE_NORMAL), (tr("CANCEL"), BUTTON_TYPE_CONFIRM)], checkbox_text=tr("Add torrents to My Channel"), ) connect(self.dialog.button_clicked, self.on_confirm_add_directory_dialog) self.dialog.show() def on_confirm_add_directory_dialog(self, action): if action == 0: if self.dialog.checkbox.isChecked(): # TODO: add recursive directory scanning def on_add_button_pressed(channel_id): TriblerNetworkRequest( f"collections/mychannel/{channel_id}/torrents", lambda _: self.tray_show_message( tr("Channels update"), tr("%s added to your channel") % self.chosen_dir ), method='PUT', data={"torrents_dir": self.chosen_dir}, ) self.window().add_to_channel_dialog.show_dialog( on_add_button_pressed, confirm_button_text=tr("Add torrent(s)") ) for torrent_file in self.selected_torrent_files: self.perform_start_download_request( f"file:{torrent_file}", self.window().tribler_settings['download_defaults']['anonymity_enabled'], self.window().tribler_settings['download_defaults']['safeseeding_enabled'], self.tribler_settings['download_defaults']['saveas'], [], ) if self.dialog: self.dialog.close_dialog() self.dialog = None def on_add_torrent_from_url(self, checked=False): # Make sure that the window is visible (this action might be triggered from the tray icon) self.raise_window() if not self.add_torrent_url_dialog_active: self.dialog = ConfirmationDialog( self, tr("Add torrent from URL/magnet link"), tr("Please enter the URL/magnet link in the field below:"), [(tr("ADD"), BUTTON_TYPE_NORMAL), (tr("CANCEL"), BUTTON_TYPE_CONFIRM)], show_input=True, ) self.dialog.dialog_widget.dialog_input.setPlaceholderText(tr("URL/magnet link")) self.dialog.dialog_widget.dialog_input.setFocus() connect(self.dialog.button_clicked, self.on_torrent_from_url_dialog_done) self.dialog.show() self.add_torrent_url_dialog_active = True def on_torrent_from_url_dialog_done(self, action): self.add_torrent_url_dialog_active = False if self.dialog and self.dialog.dialog_widget: uri = self.dialog.dialog_widget.dialog_input.text().strip() # If the URI is a 40-bytes hex-encoded infohash, convert it to a valid magnet link if len(uri) == 40: valid_ih_hex = True try: int(uri, 16) except ValueError: valid_ih_hex = False if valid_ih_hex: uri = "magnet:?xt=urn:btih:" + uri # Remove first dialog self.dialog.close_dialog() self.dialog = None if action == 0: self.start_download_from_uri(uri) def on_download_added(self, result): if not result: return if len(self.pending_uri_requests) == 0: # Otherwise, we first process the remaining requests. self.window().left_menu_button_downloads.click() else: self.process_uri_request() def on_top_menu_button_click(self): if self.left_menu.isHidden(): self.left_menu.show() else: self.left_menu.hide() def deselect_all_menu_buttons(self, except_select=None): for button in self.menu_buttons: if button == except_select: button.setEnabled(False) continue button.setEnabled(True) button.setChecked(False) def clicked_search_bar(self, checked=False): query = self.top_search_bar.text() if query and self.has_search_results: self.deselect_all_menu_buttons() if self.stackedWidget.currentIndex() == PAGE_SEARCH_RESULTS: self.search_results_page.go_back_to_level(0) self.stackedWidget.setCurrentIndex(PAGE_SEARCH_RESULTS) def clicked_menu_button_discovered(self): self.deselect_all_menu_buttons() self.left_menu_button_discovered.setChecked(True) if self.stackedWidget.currentIndex() == PAGE_DISCOVERED: self.discovered_page.go_back_to_level(0) self.discovered_page.reset_view() self.stackedWidget.setCurrentIndex(PAGE_DISCOVERED) self.discovered_page.content_table.setFocus() def clicked_menu_button_popular(self): self.deselect_all_menu_buttons() self.left_menu_button_popular.setChecked(True) # We want to reset the view every time to show updates self.popular_page.go_back_to_level(0) self.popular_page.reset_view() self.stackedWidget.setCurrentIndex(PAGE_POPULAR) self.popular_page.content_table.setFocus() def clicked_menu_button_trust_graph(self): self.deselect_all_menu_buttons(self.left_menu_button_trust_graph) self.stackedWidget.setCurrentIndex(PAGE_TRUST_GRAPH_PAGE) def clicked_menu_button_downloads(self, checked): self.deselect_all_menu_buttons(self.left_menu_button_downloads) self.raise_window() self.left_menu_button_downloads.setChecked(True) self.stackedWidget.setCurrentIndex(PAGE_DOWNLOADS) def clicked_menu_button_debug(self, index=False): if not self.debug_window: self.debug_window = DebugWindow(self.tribler_settings, self.gui_settings, self.tribler_version) self.debug_window.show() def resizeEvent(self, _): # This thing here is necessary to send the resize event to dialogs, etc. self.resize_event.emit() def close_tribler(self, checked=False): if self.core_manager.shutting_down: return def show_force_shutdown(): self.window().force_shutdown_btn.show() self.delete_tray_icon() self.show_loading_screen() self.hide_status_bar() self.loading_text_label.setText(tr("Shutting down...")) if self.debug_window: self.debug_window.setHidden(True) self.shutdown_timer = QTimer() connect(self.shutdown_timer.timeout, show_force_shutdown) self.shutdown_timer.start(SHUTDOWN_WAITING_PERIOD) self.gui_settings.setValue("pos", self.pos()) self.gui_settings.setValue("size", self.size()) if self.core_manager.use_existing_core: # Don't close the core that we are using QApplication.quit() self.core_manager.stop() self.core_manager.shutting_down = True self.downloads_page.stop_loading_downloads() request_manager.clear() # Stop the token balance timer if self.token_refresh_timer: self.token_refresh_timer.stop() def closeEvent(self, close_event): self.close_tribler() close_event.ignore() def dragEnterEvent(self, e): file_urls = [_qurl_to_path(url) for url in e.mimeData().urls()] if e.mimeData().hasUrls() else [] if any(os.path.isfile(filename) for filename in file_urls): e.accept() else: e.ignore() def dropEvent(self, e): file_urls = ( [(_qurl_to_path(url), url.toString()) for url in e.mimeData().urls()] if e.mimeData().hasUrls() else [] ) for filename, fileurl in file_urls: if os.path.isfile(filename): self.start_download_from_uri(fileurl) e.accept() def clicked_force_shutdown(self): process_checker = ProcessChecker() if process_checker.already_running: core_pid = process_checker.get_pid_from_lock_file() os.kill(int(core_pid), 9) # Stop the Qt application QApplication.quit() def clicked_skip_conversion(self): self.dialog = ConfirmationDialog( self, tr("Abort the conversion of Channels database"), tr( "The upgrade procedure is now <b>converting your personal channel</b> and channels " "collected by the previous installation of Tribler.<br>" "Are you sure you want to abort the conversion process?<br><br>" "<p style='color:red'><b> !!! WARNING !!! <br>" "You will lose your personal channel and subscribed channels if you ABORT now! </b> </p> <br>" ), [(tr("ABORT"), BUTTON_TYPE_CONFIRM), (tr("CONTINUE"), BUTTON_TYPE_NORMAL)], ) connect(self.dialog.button_clicked, self.on_skip_conversion_dialog) self.dialog.show() def on_channel_subscribe(self, channel_info): patch_data = [{"public_key": channel_info['public_key'], "id": channel_info['id'], "subscribed": True}] TriblerNetworkRequest( "metadata", lambda data: self.core_manager.events_manager.node_info_updated.emit(data[0]), raw_data=json.dumps(patch_data), method='PATCH', ) def on_channel_unsubscribe(self, channel_info): def _on_unsubscribe_action(action): if action == 0: patch_data = [{"public_key": channel_info['public_key'], "id": channel_info['id'], "subscribed": False}] TriblerNetworkRequest( "metadata", lambda data: self.core_manager.events_manager.node_info_updated.emit(data[0]), raw_data=json.dumps(patch_data), method='PATCH', ) if self.dialog: self.dialog.close_dialog() self.dialog = None self.dialog = ConfirmationDialog( self, tr("Unsubscribe from channel"), tr("Are you sure you want to <b>unsubscribe</b> from channel<br/>") + '\"' + f"<b>{channel_info['name']}</b>" + '\"' + tr("<br/>and remove its contents?"), [(tr("UNSUBSCRIBE"), BUTTON_TYPE_NORMAL), (tr("CANCEL"), BUTTON_TYPE_CONFIRM)], ) connect(self.dialog.button_clicked, _on_unsubscribe_action) self.dialog.show() def on_channel_delete(self, channel_info): def _on_delete_action(action): if action == 0: delete_data = [{"public_key": channel_info['public_key'], "id": channel_info['id']}] TriblerNetworkRequest( "metadata", lambda data: self.core_manager.events_manager.node_info_updated.emit(data[0]), raw_data=json.dumps(delete_data), method='DELETE', ) if self.dialog: self.dialog.close_dialog() self.dialog = None self.dialog = ConfirmationDialog( self, tr("Delete channel"), tr("Are you sure you want to <b>delete</b> your personal channel<br/>") + '\"' + f"<b>{channel_info['name']}</b>" + '\"' + tr("<br/>and all its contents?"), [(tr("DELETE"), BUTTON_TYPE_NORMAL), (tr("CANCEL"), BUTTON_TYPE_CONFIRM)], ) connect(self.dialog.button_clicked, _on_delete_action) self.dialog.show() def on_skip_conversion_dialog(self, action): if action == 0: TriblerNetworkRequest("upgrader", lambda _: None, data={"skip_db_upgrade": True}, method='POST') if self.dialog: self.dialog.close_dialog() self.dialog = None def on_tribler_shutdown_state_update(self, state): self.loading_text_label.setText(state) def on_config_error_signal(self, stacktrace): self._logger.error(f"Config error: {stacktrace}") user_message = tr( "Tribler recovered from a corrupted config. Please check your settings and update if necessary." ) ConfirmationDialog.show_error(self, tr("Tribler config error"), user_message)
class Window(QMainWindow): def __init__(self, user): super().__init__() self.id_user = user self.widget = Wewnatrz(self) self.title = 'Wykaz narzędzi' self.width = 1440 self.height = 900 # Odpowiedzialne za utrzymanie rozmiaru i pozycji self.settings = QSettings('Kuźnia Jawor', 'PBPZ') geometry = self.settings.value('geometria', bytes('', 'utf-8')) self.restoreGeometry(geometry) # Edycja podwietlenia głównego okna paleta = self.palette() paleta.setColor(QPalette.Highlight, QColor(233, 107, 57)) self.setPalette(paleta) self.initUI() # Odpowiedzialne za utrzymanie rozmiaru i pozycji def closeEvent(self, event): geometry = self.saveGeometry() self.settings.setValue('geometria', geometry) super(Window, self).closeEvent(event) def initUI(self): normy_lista = ( 'Normy', 'SELECT * FROM detale', 'Baza nie zawiera żadnych norm. Plik nie zostanie zapisany.', ) self.setWindowTitle(self.title) self.setWindowIcon(QIcon('icons/cow.png')) self.resize(self.width, self.height) center(self) self.setCentralWidget(self.widget) # centrowanie widżetu na pełneokno # Wyswietlanie # todo zaproponowanie skrótów wysw_act1 = QAction('Wyświetl normy pozycji', self) # wysw_act1.setShortcut('Ctrl+Q') wysw_act1.triggered.connect(self.norma) wysw_act2 = QAction('Wyświetl narzędzia pozycji', self) # wysw_act2.setShortcut('Ctrl+Q') wysw_act2.triggered.connect(self.wyswietl) # Wydruk wydr_act1 = QAction('Wyeksportuj normy do pliku', self) # wydr_act1.setShortcut('Ctrl+Q') wydr_act1.triggered.connect( lambda checked, normyl=normy_lista: self.wybor_norma( normyl) ) wydr_act2 = QAction('Wyeksportuj wykaz narzędzi do pliku', self) # wydr_act2.setShortcut('Ctrl+Q') # wydr_act2.triggered.connect( # lambda checked, pozl=None: self.wybor(pozl) # ) wydr_act2.triggered.connect(self.wybor) # Opcje # TODO Dodać opcję zapisu do Dropboxa i pobrania bazy jedynie dla odpowiednich użytkowników opcje_act1 = QAction('Zmiana hasła', self) # wydr_act1.setShortcut('Ctrl+Q') opcje_act1.triggered.connect(self.uzytkownik) opcje_act2 = QAction('Dodaj użytkownika', self) opcje_act2.triggered.connect(self.nowy_uzytkownik) opcje_act3 = QAction('Informacje o autorze', self) # opcje_act2.setShortcut('Ctrl+Q') opcje_act3.triggered.connect(self.about) opcje_act4 = QAction('Usuń konto', self) opcje_act4.triggered.connect(self.usun_konto) opcje_act5 = QAction('Lista użytkowników', self) opcje_act5.triggered.connect(self.lista_uz) opcje_act6 = QAction('Zmiana nazwy użytkownika', self) opcje_act6.triggered.connect(self.zm_loginu) opcje_act7 = QAction('Zgłoś problem', self) opcje_act7.triggered.connect(self.problem) opcje_act8 = QAction('Wyślij bazę na Dropboxa', self) opcje_act8.triggered.connect(self.drp_backup) opcje_act9 = QAction('Pobierz bazę z Dropboxa', self) opcje_act9.triggered.connect(self.drp_download) menubar = self.menuBar() wyswietlanie = menubar.addMenu('Wyświetl') wydrukowanie = menubar.addMenu('Wyeksportuj') opcje = menubar.addMenu('Opcje') wyswietlanie.addAction(wysw_act1) wyswietlanie.addAction(wysw_act2) wydrukowanie.addAction(wydr_act1) wydrukowanie.addAction(wydr_act2) opcje.addAction(opcje_act1) opcje.addAction(opcje_act6) opcje.addAction(opcje_act4) if id_user[0] == 1: opcje.addSeparator() opcje.addAction(opcje_act2) opcje.addAction(opcje_act5) opcje.addAction(opcje_act8) opcje.addAction(opcje_act9) opcje.addSeparator() opcje.addAction(opcje_act7) opcje.addAction(opcje_act3) self.show() def problem(self): tekst, ok = QInputDialog.getMultiLineText( self, 'Zgłoś problem', 'Wpisz poniżej rodzaj problemu') if ok and tekst: wysylanie(tekst, self.id_user[0]) def drp_download(self): download() def drp_backup(self): backup() def norma(self): from norma import Norma nor = Norma(self) self.setCentralWidget(nor) def wyswietl(self): wysw = Wyswietl(self) self.setCentralWidget(wysw) def nowy_uzytkownik(self): text, ok = QInputDialog.getText(self, 'Dodaj użytkownika', 'Wprowadź nowego użytkownika:') if ok and text: dodaj_uzytkownik(text) self.statusBar().showMessage("Dodano nowego użytkownika", 10000) def zm_loginu(self): text, ok = QInputDialog.getText(self, 'Zmiana nazwy użytkownika', 'Wprowadź nową nazwę użytkownika:') if ok and text: zmiana_uzytkownik(text, id_user) self.statusBar().showMessage("Zmieniono nazwę użytkownika", 10000) def uzytkownik(self): text, ok = QInputDialog.getText(self, 'Zmiana hasła', 'Wprowadź nowe hasło:', QLineEdit.Password) if ok and text: opcje_uzytkownik(text, id_user) self.statusBar().showMessage("Zmieniono hasło", 10000) def lista_uz(self): from lista_uz import Ui_Form from widget import Ui_H_Form query = 'SELECT "nazwa_uz" FROM "uzytkownicy" ORDER BY "iduzytkownicy" ASC;' loginy = multipolaczenie(query) self.Form = QtWidgets.QWidget() self.Form.setWindowIcon(QIcon('icons/cow.png')) self.Form.setWindowTitle('Lista użytkowników') self.ui = Ui_Form() self.ui.setupUi(self.Form) self.Form.show() # Lista składana klas dla każdego użytkownika self.ui2 = [Ui_H_Form() for i in loginy] # Przypisanie każdego użytkownika do widoku for i, login in enumerate(loginy): self.H_Form = QtWidgets.QWidget() self.ui2[i].setupUi(self.H_Form) self.ui2[i].label.setText(login[0]) self.ui.verticalLayout_2.addWidget(self.H_Form) def usun_konto(self): msg = QMessageBox(self) msg.setIcon(QMessageBox.Warning) msg.setText('Czy na pewno chcesz usunąć swoje konto?') msg.setWindowTitle('Usuwanie konta') msg.addButton('Tak', QMessageBox.YesRole) msg.addButton('Nie', QMessageBox.NoRole) msg = msg.exec_() if not msg and id_user[0] != 1: query = 'DELETE FROM "uzytkownicy" WHERE "iduzytkownicy" IS ("' + str( id_user[0]) + '");' polaczenie(query) self.statusBar().showMessage("Usunięto użytkownika", 10000) def about(self): self.window = QMainWindow() from o_mnie import Ui_O_mnie self.ui = Ui_O_mnie() self.ui.setupUi(self.window) self.window.show() # uzytk = Uzytkownik(self) # self.setCentralWidget(uzytk) def wybor(self): poz_lista = [ 'Wykaz narzędzi ', "SELECT * FROM ", 'Baza nie zawiera żadnych pozycji. Plik nie zostanie zapisany.', ] lista_poz = [] lista_poz.append('Brak') from narzedzia_poz import naglowki for i in naglowki(): if "/" in i[0]: lista_poz.append(i[0]) inp = QInputDialog(self) inp.setWhatsThis('Wybierz pozycję aby eksportować do pliku') inp.setLabelText('Wybierz pozycję:') inp.setWindowTitle('Pozycje') inp.setComboBoxItems(lista_poz) inp.setCancelButtonText('Anuluj') if inp.exec_() == QDialog.Accepted: print(inp.textValue()) poz_lista[0] += inp.textValue() poz_lista[1] += "'" + inp.textValue() + "'" if inp.textValue() != 'Brak': self.export(poz_lista) self.statusBar().showMessage( "Wyeksportowano do pliku", 10000) else: QMessageBox.critical(self, 'Wybierz pozycję', 'Nie wybrano żadnej pozycji!', QMessageBox.Ok, QMessageBox.Ok) def wybor_norma(self, lista): item, ok = QInputDialog.getItem(self, 'Wybierz', 'Typ:', ['Odkuwki', 'Kołnierze'], 0, False) if ok and item: if item == 'Kołnierze': lista = list(lista) lista[1] = 'SELECT * FROM kolnierze' lista = tuple(lista) else: return self.export(lista) self.statusBar().showMessage( "Wyeksportowano do pliku", 10000) def export(self, lista_arg): options = QFileDialog.Options() file_name, _ = QFileDialog.getSaveFileName( self, "Zapisywanie jako", os.path.expanduser("~") + '/desktop/' + lista_arg[0].replace('/', '-'), "Skoroszyt programu Excel (*.xlsx)", options=options ) if file_name: print(file_name) import sqlite3 sciezka = czy_istnieje() conn = sqlite3.connect(sciezka) cursor = conn.cursor() mysel = cursor.execute(lista_arg[1]) dane = mysel.fetchall() if not dane: QMessageBox.warning(self, 'Pusta zawartość', lista_arg[2], QMessageBox.Ok, QMessageBox.Ok) else: from xlsxwriter import Workbook workbook = Workbook(file_name) worksheet = workbook.add_worksheet() for i, row in enumerate(dane): for j, value in enumerate(row): if j == 0: continue worksheet.write(i, j, value) workbook.close() if 'Normy' in lista_arg: stylizacja(file_name) pass else: styl_pozycje(file_name, lista_arg[0][-7:])
def save_settings(self): settings = QSettings(CONFIG_FILE_NAME, QSettings.IniFormat) settings.setValue('BoolValue1', int(self.checkBox1.isChecked())) settings.setValue('BoolValue2', int(self.checkBox2.isChecked())) settings.setValue('BoolValue3', int(self.checkBox3.isChecked())) settings.setValue('BoolValue4', int(self.checkBox4.isChecked())) settings.setValue('BoolValue5', int(self.checkBox5.isChecked())) settings.setValue('BoolValue6', int(self.checkBox6.isChecked())) settings.setValue('BoolValue7', int(self.checkBox7.isChecked())) settings.setValue('BoolValue_1', int(self.checkBox.isChecked())) settings.setValue('BoolValue_2', int(self.checkBox_2.isChecked())) settings.setValue('BoolValue_3', int(self.checkBox_3.isChecked())) settings.setValue('BoolValue_4', int(self.checkBox_4.isChecked())) settings.setValue('BoolValue_5', int(self.checkBox_5.isChecked())) settings.setValue('BoolValue_6', int(self.checkBox_6.isChecked())) settings.setValue('BoolValue_7', int(self.checkBox_7.isChecked())) settings.setValue('BoolValue__1', int(self.checkBox__1.isChecked())) settings.setValue('BoolValue__2', int(self.checkBox__2.isChecked())) settings.setValue('BoolValue__3', int(self.checkBox__3.isChecked())) settings.setValue('BoolValue__4', int(self.checkBox__4.isChecked())) settings.setValue('BoolValue__5', int(self.checkBox__5.isChecked())) settings.setValue('BoolValue__6', int(self.checkBox__6.isChecked())) settings.setValue('BoolValue__7', int(self.checkBox__7.isChecked()))
def story_save_state(): settings = QSettings("rlbotgui", "story_save") serialized = CURRENT_STATE.__dict__ settings.setValue("save", serialized) return serialized
class AppWindow(QMainWindow): onRestart = pyqtSignal(name='onRestart') onSystemUIElementCreated = pyqtSignal(str, QWidget, name='onSystemUIElementCreated') onSystemUIElementRemoved = pyqtSignal(str, name='onSystemUIElementRemoved') def __init__(self, dwarf_args, flags=None): super(AppWindow, self).__init__(flags) self.dwarf_args = dwarf_args self.session_manager = SessionManager(self) self.session_manager.sessionCreated.connect(self.session_created) self.session_manager.sessionStopped.connect(self.session_stopped) self.session_manager.sessionClosed.connect(self.session_closed) self._tab_order = [ 'debug', 'modules', 'ranges', 'jvm-inspector', 'jvm-debugger' ] self._is_newer_dwarf = False self.q_settings = QSettings("dwarf_window_pos.ini", QSettings.IniFormat) self.menu = self.menuBar() self.view_menu = None self._initialize_ui_elements() self.setWindowTitle( 'Dwarf - A debugger for reverse engineers, crackers and security analyst' ) # load external assets _app = QApplication.instance() self.remove_tmp_dir() # themes self.prefs = Prefs() utils.set_theme(self.prefs.get('dwarf_ui_theme', 'black'), self.prefs) # load font if os.path.exists(utils.resource_path('assets/Anton.ttf')): QFontDatabase.addApplicationFont( utils.resource_path('assets/Anton.ttf')) if os.path.exists(utils.resource_path('assets/OpenSans-Regular.ttf')): QFontDatabase.addApplicationFont( utils.resource_path('assets/OpenSans-Regular.ttf')) font = QFont("OpenSans", 9, QFont.Normal) # TODO: add settingsdlg font_size = self.prefs.get('dwarf_ui_font_size', 12) font.setPixelSize(font_size) _app.setFont(font) if os.path.exists(utils.resource_path('assets/OpenSans-Bold.ttf')): QFontDatabase.addApplicationFont( utils.resource_path('assets/OpenSans-Bold.ttf')) # mainwindow statusbar self.progressbar = QProgressBar() self.progressbar.setRange(0, 0) self.progressbar.setVisible(False) self.progressbar.setFixedHeight(15) self.progressbar.setFixedWidth(100) self.progressbar.setTextVisible(False) self.progressbar.setValue(30) self.statusbar = QStatusBar(self) self.statusbar.setAutoFillBackground(False) self.statusbar.addPermanentWidget(self.progressbar) self.statusbar.setObjectName("statusbar") self.setStatusBar(self.statusbar) self.main_tabs = QTabWidget(self) self.main_tabs.setMovable(False) self.main_tabs.setTabsClosable(True) self.main_tabs.setAutoFillBackground(True) self.main_tabs.tabCloseRequested.connect(self._on_close_tab) self.setCentralWidget(self.main_tabs) # pluginmanager self.plugin_manager = PluginManager(self) self.plugin_manager.reload_plugins() if self.dwarf_args.package is None: self.welcome_window = WelcomeDialog(self) self.welcome_window.setModal(True) self.welcome_window.onIsNewerVersion.connect( self._enable_update_menu) self.welcome_window.onUpdateComplete.connect( self._on_dwarf_updated) self.welcome_window.setWindowTitle( 'Welcome to Dwarf - A debugger for reverse engineers, crackers and security analyst' ) self.welcome_window.onSessionSelected.connect(self._start_session) # wait for welcome screen self.hide() self.welcome_window.show() else: if dwarf_args.package is not None: if dwarf_args.type is None: # no device given check if package is local path if os.path.exists(dwarf_args.package): print('* Starting new LocalSession') self._start_session('local') else: print('use -t to set sessiontype') exit(0) else: print('* Starting new Session') self._start_session(dwarf_args.type) def _initialize_ui_elements(self): # dockwidgets self.watchers_dwidget = None self.hooks_dwiget = None self.bookmarks_dwiget = None self.registers_dock = None self.console_dock = None self.backtrace_dock = None self.threads_dock = None # panels self.asm_panel = None self.backtrace_panel = None self.bookmarks_panel = None self.console_panel = None self.context_panel = None self.debug_panel = None self.contexts_list_panel = None self.data_panel = None self.ftrace_panel = None self.hooks_panel = None self.java_inspector_panel = None self.java_explorer_panel = None self.java_trace_panel = None self.modules_panel = None self.ranges_panel = None self.search_panel = None self.smali_panel = None self.watchers_panel = None self.welcome_window = None self._ui_elems = [] def _setup_main_menu(self): self.menu = self.menuBar() dwarf_menu = QMenu('Dwarf', self) theme = QMenu('Theme', dwarf_menu) theme.addAction('Black') theme.addAction('Dark') theme.addAction('Light') theme.triggered.connect(self._set_theme) dwarf_menu.addMenu(theme) dwarf_menu.addSeparator() dwarf_bin_path = None if sys.platform == 'linux': dwarf_bin_path = os.path.join('/'.join(os.path.realpath(__file__).split('/')[:-2]), 'bin/dwarf') if not os.path.exists(dwarf_bin_path): dwarf_menu.addAction('Create launcher', utils.create_launcher) dwarf_menu.addSeparator() if self._is_newer_dwarf: dwarf_menu.addAction('Update', self._update_dwarf) dwarf_menu.addAction('Close', self.session_manager.session.stop) self.menu.addMenu(dwarf_menu) session = self.session_manager.session if session is not None: session_menu = session.main_menu if isinstance(session_menu, list): for menu in session_menu: self.menu.addMenu(menu) else: self.menu.addMenu(session_menu) # plugins if self.plugin_manager.plugins: self.plugin_menu = QMenu('Plugins', self) for plugin in self.plugin_manager.plugins: plugin_instance = self.plugin_manager.plugins[plugin] plugin_sub_menu = self.plugin_menu.addMenu(plugin_instance.name) try: actions = plugin_instance.__get_top_menu_actions__() for action in actions: plugin_sub_menu.addAction(action) except: pass if not plugin_sub_menu.isEmpty(): plugin_sub_menu.addSeparator() about = plugin_sub_menu.addAction('About') about.triggered.connect( lambda x, item=plugin: self._show_plugin_about(item)) if not self.plugin_menu.isEmpty(): self.menu.addMenu(self.plugin_menu) self.view_menu = QMenu('View', self) self.panels_menu = QMenu('Panels', self.view_menu) self.panels_menu.addAction( 'Search', lambda: self.show_main_tab('search'), shortcut=QKeySequence(Qt.CTRL + Qt.Key_F3)) self.view_menu.addMenu(self.panels_menu) self.debug_view_menu = self.view_menu.addMenu('Debug') self.view_menu.addSeparator() self.view_menu.addAction('Hide all', self._hide_all_widgets, shortcut=QKeySequence(Qt.CTRL + Qt.Key_F1)) self.view_menu.addAction('Show all', self._show_all_widgets, shortcut=QKeySequence(Qt.CTRL + Qt.Key_F2)) self.view_menu.addSeparator() self.menu.addMenu(self.view_menu) if self.dwarf_args.debug_script: debug_menu = QMenu('Debug', self) debug_menu.addAction('Reload core', self._menu_reload_core) debug_menu.addAction('Debug dwarf js core', self._menu_debug_dwarf_js) self.menu.addMenu(debug_menu) # tools _tools = self.prefs.get('tools') if _tools: tools_menu = QMenu('Tools', self) for _tool in _tools: if _tool and _tool['name']: if _tool['name'] == 'sep': tools_menu.addSeparator() continue _cmd = _tool['cmd'] tools_menu.addAction(_tool['name']) if not tools_menu.isEmpty(): tools_menu.triggered.connect(self._execute_tool) self.menu.addMenu(tools_menu) about_menu = QMenu('About', self) about_menu.addAction('Dwarf on GitHub', self._menu_github) about_menu.addAction('Documention', self._menu_documentation) about_menu.addAction('Api', self._menu_api) about_menu.addAction('Slack', self._menu_slack) about_menu.addSeparator() about_menu.addAction('Info', self._show_about_dlg) self.menu.addMenu(about_menu) def _show_plugin_about(self, plugin): plugin = self.plugin_manager.plugins[plugin] if plugin: info = plugin.__get_plugin_info__() version = utils.safe_read_map(info, 'version', '') description = utils.safe_read_map(info, 'description', '') author = utils.safe_read_map(info, 'author', '') homepage = utils.safe_read_map(info, 'homepage', '') license_ = utils.safe_read_map(info, 'license', '') utils.show_message_box( 'Name: {0}\nVersion: {1}\nDescription: {2}\nAuthor: {3}\nHomepage: {4}\nLicense: {5}'. format(plugin.name, version, description, author, homepage, license_)) def _enable_update_menu(self): self._is_newer_dwarf = True def _update_dwarf(self): if self.welcome_window: self.welcome_window._update_dwarf() def _on_close_tab(self, index): tab_text = self.main_tabs.tabText(index) if tab_text: tab_text = tab_text.lower() if tab_text in self.session_manager.session.non_closable: return try: self._ui_elems.remove(tab_text) except ValueError: # recheck ValueError: list.remove(x): x not in list pass self.main_tabs.removeTab(index) self.onSystemUIElementRemoved.emit(tab_text) def _handle_tab_change(self): for index in range(self.main_tabs.count()): tab_name = self.main_tabs.tabText(index).lower().replace(' ', '-') if tab_name in self.session_manager.session.non_closable: self.main_tabs.tabBar().setTabButton(index, QTabBar.RightSide, None) if tab_name in self._tab_order: should_index = self._tab_order.index(tab_name) if index != should_index: self.main_tabs.tabBar().moveTab(index, should_index) def _on_dwarf_updated(self): self.onRestart.emit() def remove_tmp_dir(self): if os.path.exists('.tmp'): shutil.rmtree('.tmp', ignore_errors=True) def _execute_tool(self, qaction): if qaction: _tools = self.prefs.get('tools') if _tools: for _tool in _tools: if _tool and _tool['name'] and _tool['name'] != 'sep': if qaction.text() == _tool['name']: try: import subprocess subprocess.Popen(_tool['cmd'], creationflags=subprocess.CREATE_NEW_CONSOLE) except: pass break def _set_theme(self, qaction): if qaction: utils.set_theme(qaction.text(), self.prefs) def _hide_all_widgets(self): self.watchers_dwidget.hide() self.hooks_dwiget.hide() self.bookmarks_dwiget.hide() self.registers_dock.hide() self.console_dock.hide() self.backtrace_dock.hide() self.threads_dock.hide() def _show_all_widgets(self): self.watchers_dwidget.show() self.hooks_dwiget.show() self.bookmarks_dwiget.show() self.registers_dock.show() self.console_dock.show() self.backtrace_dock.show() self.threads_dock.show() def _menu_reload_core(self): self.dwarf.script.exports.reload() def _menu_debug_dwarf_js(self): you_know_what_to_do = json.loads( self.dwarf.script.exports.debugdwarfjs()) return you_know_what_to_do def show_main_tab(self, name): name = name.lower() # elem doesnt exists? create it if name not in self._ui_elems: self._create_ui_elem(name) index = 0 name = name.join(name.split()).lower() if name == 'ranges': index = self.main_tabs.indexOf(self.ranges_panel) elif name == 'search': index = self.main_tabs.indexOf(self.search_panel) elif name == 'modules': index = self.main_tabs.indexOf(self.modules_panel) elif name == 'data': index = self.main_tabs.indexOf(self.data_panel) elif name == 'java-trace': index = self.main_tabs.indexOf(self.java_trace_panel) elif name == 'jvm-inspector': index = self.main_tabs.indexOf(self.java_inspector_panel) elif name == 'jvm-debugger': index = self.main_tabs.indexOf(self.java_explorer_panel) elif name == 'smali': index = self.main_tabs.indexOf(self.smali_panel) self.main_tabs.setCurrentIndex(index) def jump_to_address(self, ptr, view=0, show_panel=True): if show_panel: self.show_main_tab('debug') self.debug_panel.jump_to_address(ptr, view=view) @pyqtSlot(name='mainMenuGitHub') def _menu_github(self): QDesktopServices.openUrl(QUrl('https://github.com/iGio90/Dwarf')) @pyqtSlot(name='mainMenuApi') def _menu_api(self): QDesktopServices.openUrl(QUrl('http://www.giovanni-rocca.com/dwarf/javascript/')) @pyqtSlot(name='mainMenuDocumentation') def _menu_documentation(self): QDesktopServices.openUrl(QUrl('http://www.giovanni-rocca.com/dwarf/')) @pyqtSlot(name='mainMenuSlack') def _menu_slack(self): QDesktopServices.openUrl( QUrl('https://join.slack.com/t/resecret/shared_invite' '/enQtMzc1NTg4MzE3NjA1LTlkNzYxNTIwYTc2ZTYyOWY1MT' 'Q1NzBiN2ZhYjQwYmY0ZmRhODQ0NDE3NmRmZjFiMmE1MDYwN' 'WJlNDVjZDcwNGE')) def _show_about_dlg(self): about_dlg = AboutDialog(self) about_dlg.show() def _create_ui_elem(self, elem): elem = elem.lower() if not isinstance(elem, str): return if elem not in self._ui_elems: self._ui_elems.append(elem) elem_wiget = None if elem == 'watchers': from ui.session_widgets.watchers import WatchersWidget self.watchers_dwidget = QDockWidget('Watchers', self) self.watchers_panel = WatchersWidget(self) # dont respond to dblclick mem cant be shown # self.watchers_panel.onItemDoubleClicked.connect( # self._on_watcher_clicked) self.watchers_panel.onItemRemoved.connect( self._on_watcher_removeditem) self.watchers_panel.onItemAdded.connect(self._on_watcher_added) self.watchers_dwidget.setWidget(self.watchers_panel) self.watchers_dwidget.setObjectName('WatchersWidget') self.addDockWidget(Qt.LeftDockWidgetArea, self.watchers_dwidget) self.view_menu.addAction(self.watchers_dwidget.toggleViewAction()) elem_wiget = self.watchers_panel elif elem == 'hooks': from ui.session_widgets.hooks import HooksWidget self.hooks_dwiget = QDockWidget('Breakpoints', self) self.hooks_panel = HooksWidget(self) self.hooks_panel.onHookRemoved.connect(self._on_hook_removed) self.hooks_dwiget.setWidget(self.hooks_panel) self.hooks_dwiget.setObjectName('HooksWidget') self.addDockWidget(Qt.LeftDockWidgetArea, self.hooks_dwiget) self.view_menu.addAction(self.hooks_dwiget.toggleViewAction()) elem_wiget = self.hooks_panel elif elem == 'bookmarks': from ui.session_widgets.bookmarks import BookmarksWidget self.bookmarks_dwiget = QDockWidget('Boomarks', self) self.bookmarks_panel = BookmarksWidget(self) self.bookmarks_dwiget.setWidget(self.bookmarks_panel) self.bookmarks_dwiget.setObjectName('BookmarksWidget') self.addDockWidget(Qt.LeftDockWidgetArea, self.bookmarks_dwiget) self.view_menu.addAction(self.bookmarks_dwiget.toggleViewAction()) elem_wiget = self.bookmarks_panel elif elem == 'registers': from ui.session_widgets.context import ContextWidget self.registers_dock = QDockWidget('Context', self) self.context_panel = ContextWidget(self) self.registers_dock.setWidget(self.context_panel) self.registers_dock.setObjectName('ContextWidget') self.addDockWidget(Qt.RightDockWidgetArea, self.registers_dock) self.view_menu.addAction(self.registers_dock.toggleViewAction()) elem_wiget = self.context_panel elif elem == 'debug': from ui.panels.panel_debug import QDebugPanel self.debug_panel = QDebugPanel(self) self.main_tabs.addTab(self.debug_panel, 'Debug') elem_wiget = self.debug_panel elif elem == 'jvm-debugger': from ui.panels.panel_java_explorer import JavaExplorerPanel self.java_explorer_panel = JavaExplorerPanel(self) self.main_tabs.addTab(self.java_explorer_panel, 'JVM debugger') self.main_tabs.tabBar().moveTab( self.main_tabs.indexOf(self.java_explorer_panel), 1) elem_wiget = self.java_explorer_panel elif elem == 'jvm-inspector': from ui.panels.panel_java_inspector import JavaInspector self.java_inspector_panel = JavaInspector(self) self.main_tabs.addTab(self.java_inspector_panel, 'JVM inspector') elem_wiget = self.java_inspector_panel elif elem == 'console': from ui.session_widgets.console import ConsoleWidget self.console_dock = QDockWidget('Console', self) self.console_panel = ConsoleWidget(self) if self.dwarf_args.script and len(self.dwarf_args.script) > 0 and os.path.exists(self.dwarf_args.script): with open(self.dwarf_args.script, 'r') as f: self.console_panel.get_js_console().script_file = self.dwarf_args.script self.console_panel.get_js_console().function_content = f.read() self.dwarf.onLogToConsole.connect(self._log_js_output) self.dwarf.onLogEvent.connect(self._log_event) self.console_dock.setWidget(self.console_panel) self.console_dock.setObjectName('ConsoleWidget') self.addDockWidget(Qt.BottomDockWidgetArea, self.console_dock) self.view_menu.addAction(self.console_dock.toggleViewAction()) elem_wiget = self.console_panel elif elem == 'backtrace': from ui.session_widgets.backtrace import BacktraceWidget self.backtrace_dock = QDockWidget('Backtrace', self) self.backtrace_panel = BacktraceWidget(self) self.backtrace_dock.setWidget(self.backtrace_panel) self.backtrace_dock.setObjectName('BacktraceWidget') self.backtrace_panel.onShowMemoryRequest.connect(self._on_showmemory_request) self.addDockWidget(Qt.RightDockWidgetArea, self.backtrace_dock) self.view_menu.addAction(self.backtrace_dock.toggleViewAction()) elem_wiget = self.backtrace_panel elif elem == 'threads': from ui.session_widgets.threads import ThreadsWidget self.threads_dock = QDockWidget('Threads', self) self.contexts_list_panel = ThreadsWidget(self) self.dwarf.onThreadResumed.connect( self.contexts_list_panel.resume_tid) self.contexts_list_panel.onItemDoubleClicked.connect( self._manually_apply_context) self.threads_dock.setWidget(self.contexts_list_panel) self.threads_dock.setObjectName('ThreadPanel') self.addDockWidget(Qt.RightDockWidgetArea, self.threads_dock) self.view_menu.addAction(self.threads_dock.toggleViewAction()) elem_wiget = self.contexts_list_panel elif elem == 'modules': from ui.panels.panel_modules import ModulesPanel self.modules_panel = ModulesPanel(self) self.modules_panel.onModuleSelected.connect( self._on_module_dblclicked) self.modules_panel.onModuleFuncSelected.connect( self._on_modulefunc_dblclicked) self.modules_panel.onAddHook.connect(self._on_addmodule_hook) self.modules_panel.onDumpBinary.connect(self._on_dumpmodule) self.main_tabs.addTab(self.modules_panel, 'Modules') elem_wiget = self.modules_panel elif elem == 'ranges': from ui.panels.panel_ranges import RangesPanel self.ranges_panel = RangesPanel(self) self.ranges_panel.onItemDoubleClicked.connect( self._range_dblclicked) self.ranges_panel.onDumpBinary.connect(self._on_dumpmodule) # connect to watcherpanel func self.ranges_panel.onAddWatcher.connect( self.watchers_panel.do_addwatcher_dlg) self.main_tabs.addTab(self.ranges_panel, 'Ranges') elem_wiget = self.ranges_panel elif elem == 'search': from ui.panels.panel_search import SearchPanel self.search_panel = SearchPanel(self) self.main_tabs.addTab(self.search_panel, 'Search') elem_wiget = self.search_panel elif elem == 'data': from ui.panels.panel_data import DataPanel self.data_panel = DataPanel(self) self.main_tabs.addTab(self.data_panel, 'Data') elem_wiget = self.data_panel elif elem == 'java-trace': from ui.panels.panel_java_trace import JavaTracePanel self.java_trace_panel = JavaTracePanel(self) self.main_tabs.addTab(self.java_trace_panel, 'JVM tracer') elem_wiget = self.java_trace_panel elif elem == 'smali': from ui.panels.panel_smali import SmaliPanel self.smali_panel = SmaliPanel() self.main_tabs.addTab(self.smali_panel, 'Smali') elem_wiget = self.smali_panel else: print('no handler for elem: ' + elem) # make tabs unclosable and sort self._handle_tab_change() if elem_wiget is not None: self.onSystemUIElementCreated.emit(elem, elem_wiget) # TODO: remove add @2x for item in self.findChildren(QDockWidget): if item: if 'darwin' in sys.platform: item.setStyleSheet( 'QDockWidget::title { padding-left:-30px; }' ) def set_status_text(self, txt): self.statusbar.showMessage(txt) # ************************************************************************ # **************************** Properties ******************************** # ************************************************************************ @property def disassembly(self): return self.asm_panel @property def backtrace(self): return self.backtrace_panel @property def console(self): return self.console_panel @property def context(self): return self.context_panel @property def threads(self): return self.contexts_list_panel @property def ftrace(self): return self.ftrace_panel @property def hooks(self): return self.hooks_panel @property def java_inspector(self): return self.java_inspector_panel @property def java_explorer(self): return self.java_explorer_panel @property def modules(self): return self.modules_panel @property def ranges(self): return self.ranges_panel @property def watchers(self): return self.watchers_panel @property def dwarf(self): if self.session_manager.session is not None: return self.session_manager.session.dwarf else: return None # ************************************************************************ # **************************** Handlers ********************************** # ************************************************************************ # session handlers def _start_session(self, session_type, session_data=None): if self.welcome_window is not None: self.welcome_window.close() self.session_manager.create_session( session_type, session_data=session_data) def _restore_session(self, session_data): if 'session' in session_data: session_type = session_data['session'] self.dwarf_args.package = session_data['package'] self.dwarf_args.spawn = True self._start_session(session_type, session_data=session_data) def session_created(self): # session init done create ui for it session = self.session_manager.session self._setup_main_menu() for ui_elem in session.session_ui_sections: ui_elem = ui_elem.join(ui_elem.split()).lower() self._create_ui_elem(ui_elem) self.dwarf.onProcessAttached.connect(self._on_attached) self.dwarf.onProcessDetached.connect(self._on_detached) self.dwarf.onScriptLoaded.connect(self._on_script_loaded) # hookup self.dwarf.onSetRanges.connect(self._on_setranges) self.dwarf.onSetModules.connect(self._on_setmodules) self.dwarf.onAddNativeHook.connect(self._on_add_hook) self.dwarf.onApplyContext.connect(self._apply_context) self.dwarf.onThreadResumed.connect(self.on_tid_resumed) self.dwarf.onSetData.connect(self._on_set_data) self.session_manager.start_session(self.dwarf_args) ui_state = self.q_settings.value('dwarf_ui_state') if ui_state: self.restoreGeometry(ui_state) window_state = self.q_settings.value('dwarf_ui_window', self.saveState()) if window_state: self.restoreState(window_state) self.showMaximized() def session_stopped(self): self.remove_tmp_dir() self.menu.clear() self.main_tabs.clear() # actually we need to kill this. needs a refactor if self.java_trace_panel is not None: self.java_trace_panel = None for elem in self._ui_elems: if elem == 'watchers': self.watchers_panel.clear_list() self.watchers_panel.close() self.watchers_panel = None self.removeDockWidget(self.watchers_dwidget) self.watchers_dwidget = None elif elem == 'hooks': self.hooks_panel.close() self.hooks_panel = None self.removeDockWidget(self.hooks_dwiget) self.hooks_dwiget = None elif elem == 'registers': self.context_panel.close() self.context_panel = None self.removeDockWidget(self.registers_dock) self.registers_dock = None elif elem == 'debug': self.debug_panel.close() self.debug_panel = None self.main_tabs.removeTab(0) # self.main_tabs elif elem == 'jvm-debugger': self.java_explorer_panel.close() self.java_explorer_panel = None self.removeDockWidget(self.watchers_dwidget) elif elem == 'console': self.console_panel.close() self.console_panel = None self.removeDockWidget(self.console_dock) self.console_dock = None elif elem == 'backtrace': self.backtrace_panel.close() self.backtrace_panel = None self.removeDockWidget(self.backtrace_dock) elif elem == 'threads': self.contexts_list_panel.close() self.contexts_list_panel = None self.removeDockWidget(self.threads_dock) self.threads_dock = None elif elem == 'bookmarks': self.bookmarks_panel.close() self.bookmarks_panel = None self.removeDockWidget(self.bookmarks_dwiget) self.bookmarks_dwiget = None self._initialize_ui_elements() def session_closed(self): self._initialize_ui_elements() self.hide() if self.welcome_window is not None: self.welcome_window.exec() # close if it was a commandline session if self.welcome_window is None: if self.dwarf_args.package: self.close() # ui handler def closeEvent(self, event): """ Window closed save stuff or whatever at exit detaches dwarf """ # save windowstuff self.q_settings.setValue('dwarf_ui_state', self.saveGeometry()) self.q_settings.setValue('dwarf_ui_window', self.saveState()) if self.dwarf: try: self.dwarf.detach() except: pass super().closeEvent(event) def _on_watcher_clicked(self, ptr): """ Address in Watcher/Hookpanel was clicked show Memory """ if '.' in ptr: # java_hook file_path = ptr.replace('.', os.path.sep) if os.path.exists('.tmp/smali/' + file_path + '.smali'): if self.smali_panel is None: self._create_ui_elem('smali') self.smali_panel.set_file('.tmp/smali/' + file_path + '.smali') self.show_main_tab('smali') else: self.jump_to_address(ptr) def _on_watcher_added(self, ptr): """ Watcher Entry was added """ try: # set highlight self.debug_panel.memory_panel.add_highlight( HighLight('watcher', ptr, self.dwarf.pointer_size)) except HighlightExistsError: pass def _on_watcher_removeditem(self, ptr): """ Watcher Entry was removed remove highlight too """ self.debug_panel.memory_panel.remove_highlight(ptr) def _on_module_dblclicked(self, data): """ Module in ModulePanel was doubleclicked """ addr, size = data addr = utils.parse_ptr(addr) self.jump_to_address(addr) def _on_modulefunc_dblclicked(self, ptr): """ Function in ModulePanel was doubleclicked """ ptr = utils.parse_ptr(ptr) self.jump_to_address(ptr) def _on_dumpmodule(self, data): """ DumpBinary MenuItem in ModulePanel was selected """ ptr, size = data ptr = utils.parse_ptr(ptr) size = int(size, 10) self.dwarf.dump_memory(ptr=ptr, length=size) def _disassemble_range(self, dwarf_range): """ Disassemble MenuItem in Hexview was selected """ if dwarf_range: if self.asm_panel is None: self._create_ui_elem('disassembly') self.asm_panel.disassemble(dwarf_range) self.show_main_tab('disassembly') def _range_dblclicked(self, ptr): """ Range in RangesPanel was doubleclicked """ ptr = utils.parse_ptr(ptr) self.jump_to_address(ptr) # dwarf handlers def _log_js_output(self, output): if self.console_panel is not None: time_prefix = True if len(output.split('\n')) > 1 or len(output.split('<br />')) > 1: time_prefix = False self.console_panel.get_js_console().log(output, time_prefix=time_prefix) def _log_event(self, output): if self.console_panel is not None: self.console_panel.get_events_console().log(output) def _on_setranges(self, ranges): """ Dwarf wants to set Ranges only hooked up to switch tab or create ui its connected in panel after creation """ if self.ranges_panel is None: self.show_main_tab('ranges') # forward only now to panel it connects after creation self.ranges_panel.set_ranges(ranges) def _on_setmodules(self, modules): """ Dwarf wants to set Modules only hooked up to switch tab or create ui its connected in panel after creation """ if self.modules_panel is None: self._create_ui_elem('modules') self.modules_panel.set_modules(modules) if self.modules_panel is not None: self.show_main_tab('modules') def _manually_apply_context(self, context): """ perform additional operation if the context has been manually applied from the context list """ self._apply_context(context, manual=True) def _apply_context(self, context, manual=False): # update current context tid # this should be on top as any further api from js needs to be executed on that thread reason = context['reason'] is_initial_setup = reason == -1 if manual or (self.dwarf.context_tid and not is_initial_setup): self.dwarf.context_tid = context['tid'] if is_initial_setup: self.debug_panel.on_context_setup() if 'context' in context: if not manual: self.threads.add_context(context) is_java = context['is_java'] if is_java: if self.java_explorer_panel is None: self._create_ui_elem('jvm-debugger') self.context_panel.set_context(context['ptr'], 1, context['context']) self.java_explorer_panel._set_handle_arg(-1) self.show_main_tab('jvm-debugger') else: self.context_panel.set_context(context['ptr'], 0, context['context']) if reason == 2: # native on load if self.debug_panel.memory_panel_range is None: base = context['moduleBase'] self.jump_to_address(base) else: if 'pc' in context['context']: if self.debug_panel.disassembly_panel_range is None or manual: self.jump_to_address(context['context']['pc']['value'], view=1) if 'backtrace' in context: self.backtrace_panel.set_backtrace(context['backtrace']) def _on_add_hook(self, hook): try: # set highlight ptr = hook.get_ptr() ptr = utils.parse_ptr(ptr) self.debug_panel.memory_panel.add_highlight( HighLight('hook', ptr, self.dwarf.pointer_size)) except HighlightExistsError: pass def _on_hook_removed(self, ptr): ptr = utils.parse_ptr(ptr) self.debug_panel.memory_panel.remove_highlight(ptr) def _on_addmodule_hook(self, data): ptr, name = data self.dwarf.hook_native(ptr, own_input=name) def on_tid_resumed(self, tid): if self.dwarf: if self.dwarf.context_tid == tid: # clear backtrace if 'backtrace' in self._ui_elems: if self.backtrace_panel is not None: self.backtrace_panel.clear() # remove thread if 'threads' in self._ui_elems: if self.contexts_list_panel is not None: self.contexts_list_panel.resume_tid(tid) # clear registers if 'registers' in self._ui_elems: if self.context_panel is not None: self.context_panel.clear() # clear jvm explorer if 'jvm-debugger' in self._ui_elems: if self.java_explorer_panel is not None: self.java_explorer_panel.clear_panel() # invalidate dwarf context tid self.dwarf.context_tid = 0 def _on_set_data(self, data): if not isinstance(data, list): return if self.data_panel is None: self.show_main_tab('data') if self.data_panel is not None: self.data_panel.append_data(data[0], data[1], data[2]) def show_progress(self, text): self.progressbar.setVisible(True) self.set_status_text(text) def hide_progress(self): self.progressbar.setVisible(False) self.set_status_text('') def _on_attached(self, data): self.setWindowTitle('Dwarf - Attached to %s (%s)' % (data[1], data[0])) def _on_detached(self, data): reason = data[1] if reason == 'application-requested': self.session_manager.session.stop() return 0 if self.dwarf is not None: ret = QDialogDetached.show_dialog(self.dwarf, data[0], data[1], data[2]) if ret == 0: self.dwarf.restart_proc() elif ret == 1: self.session_manager.session.stop() return 0 def _on_script_loaded(self): # restore the loaded session if any self.session_manager.restore_session() def on_add_bookmark(self, ptr): """ provide ptr as int """ if self.bookmarks_panel is not None: self.bookmarks_panel._create_bookmark(ptr=hex(ptr)) def _on_showmemory_request(self, ptr): # its simple ptr show in memorypanel if isinstance(ptr, str): ptr = utils.parse_ptr(ptr) self.jump_to_address(ptr, 0) elif isinstance(ptr, list): # TODO: extend caller, ptr = ptr ptr = utils.parse_ptr(ptr) if caller == 'backtrace' or caller == 'bt': # jumpto in disasm self.jump_to_address(ptr, 1)
def closeEvent(self, event): # save dialog geometry settings = QSettings() settings.setValue("/Qgis2threejs/propdlg/geometry", self.saveGeometry()) QDialog.closeEvent(self, event)
class ConverterFrame(Ui_Frame): def __init__(self): self.frame = None self.file_queue = Queue() self.conversion = None self.progress_dialog = None self.settings = QSettings() self.thread = QThread() self.converter = file_converter.ConverterController() def setupUi(self, frame): super().setupUi(frame) self.frame = frame # Configure table self.tableView.horizontalHeader().setSectionsClickable(False) self.tableView.setSelectionMode(QAbstractItemView.SingleSelection) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.tableView.horizontalHeader().setDefaultAlignment(Qt.AlignLeft) if QSysInfo.productType() == 'windows' and QSysInfo.productVersion() == '10': self.tableView.horizontalHeader().setStyleSheet( 'border-top: 0px; ' 'border-left: 0px; ' 'border-right: 0px; ' 'border-bottom: 1px solid gray;') # Define models self.data_file_container = table_model.DataFileContainer() self.dec_model = declination_model.Declination() self.tilt_model = TiltCurveModel( application_directory() / 'Calibration Tables') # Connect models self.tableView.setModel(self.data_file_container) self.tableView.resizeColumnsToContents() self.comboBox_tilt_tables.setModel(self.tilt_model) self.file_loader = file_loader.FileLoader(self.file_queue) self._connect_signals_to_slots() restore_last_session(self) def _connect_signals_to_slots(self): self.pushButton_add.clicked.connect(self.add_files) self.file_loader.file_loaded_signal.connect(self.file_loaded) self.file_loader.file_error_signal.connect(self.file_error) self.pushButton_remove.clicked.connect(self.delete_row) self.pushButton_clear.clicked.connect(self.data_file_container.clear) self.pushButton_convert.clicked.connect(self.convert_files) self.pushButton_browse.clicked.connect(self.choose_output_directory) self.pushButton_output_options.clicked.connect( lambda: OptionsDialog(self.frame).exec_()) self.buttonGroup.buttonToggled.connect( self.toggle_output_file_button_group) self.comboBox_output_type.currentIndexChanged.connect( self.change_output_type_slot) self.pushButton_help.clicked.connect(dialogs.about_declination) self.lineEdit_declination.textChanged.connect(self.declination_changed) self.dec_model.update_signal.connect(self.update_declination) self.data_file_container.rowsInserted.connect(self.enable_buttons) self.data_file_container.rowsRemoved.connect(self.enable_buttons) self.data_file_container.modelReset.connect(self.enable_buttons) def enable_buttons(self): state = True if len(self.data_file_container) > 0 else False buttons = [ self.pushButton_remove, self.pushButton_clear, self.pushButton_convert] for button in buttons: button.setEnabled(state) """ Methods for loading files """ # slot def add_files(self): directory = self.settings.value('last_directory', '', type=str) file_paths = dialogs.open_lid_file(directory) if not file_paths[0]: return directory = Path(file_paths[0][0]).parent self.settings.setValue('last_directory', str(directory)) self.file_queue.put(file_paths[0]) self.file_loader.run() # slot def delete_row(self): row_objects = self.tableView.selectionModel().selectedRows() for row in row_objects: self.data_file_container.delete(row.row()) # slot def file_loaded(self, file): if file.header_error: dialogs.header_error(file.filename, file.header_error) self.data_file_container.add_file(file) # slot def file_error(self, message): dialogs.error_message('Load Error', message) def _start_thread(self): self.file_loader.moveToThread(self.thread) self.file_loader.finished_signal.connect(self.thread.quit) self.thread.start() """ Convert files """ def convert_files(self): self.remove_error_files() parameters = self._read_output_options() terminate_conditions = [ lambda: self.check_error_states(), lambda: parameters['output_directory'] == 'error', lambda: len(self.data_file_container) == 0, lambda: (parameters['calibration'] is not None and not dialogs.confirm_custom_cal()), lambda: (self.data_file_container.unconverted() == 0 and not self.reset_converted()) ] if self.check_terminate_conditions(terminate_conditions): return save_session(self) self.converter.model = self.data_file_container self.converter.parameters = parameters self.converter.convert() def check_terminate_conditions(self, conditions): for condition in conditions: if condition(): return True return False def reset_converted(self): if self.data_file_container.convertable() > 0: if dialogs.prompt_mark_unconverted(): self.data_file_container.reset_converted() return True return False def remove_error_files(self): if self.data_file_container.errors(): answer = dialogs.ask_remove_error_files() if answer == 'Remove': self.data_file_container.remove_error_files() elif answer == 'Retry': self.data_file_container.reset_errors() def check_error_states(self): if self.dec_model.error_state: dialogs.error_message('Error', 'Please correct declination') return True return False # slot def change_output_type_slot(self): state = self.comboBox_output_type.currentText() == 'Current' self.comboBox_tilt_tables.setEnabled(state) disabled = ['Discrete Channels', 'Cable Attitude'] state = self.comboBox_output_type.currentText() in disabled self.dec_model.set_enabled(not state) def set_combobox(self, combobox, value): ind = combobox.findText(value) ind = 0 if ind == -1 else ind combobox.setCurrentIndex(ind) def choose_output_directory(self): directory = QFileDialog.getExistingDirectory( caption='Select output directory') self.lineEdit_output_folder.setText(directory) def toggle_output_file_button_group(self): state = False if self.radioButton_output_same.isChecked() else True self.lineEdit_output_folder.setEnabled(state) self.pushButton_browse.setEnabled(state) def _read_output_options(self): parameters = default_parameters() app_data = self.settings.value('output_options', {}, type=dict) parameters['output_directory'] = self._get_output_directory() parameters['time_format'] = app_data.get('time_format', 'iso8601') parameters['average'] = app_data.get('average_bursts', True) custom_cal_path = app_data.get('custom_cal', None) if custom_cal_path: try: custom_cal = make_from_calibration_file(custom_cal_path) parameters['calibration'] = custom_cal except: pass split_size = app_data.get('split', 'Do not split output files') if split_size != 'Do not split output files': parameters['split'] = int(split_size.split(' ')[0]) if self.comboBox_output_type.currentText() == 'Current': parameters['output_type'] = 'current' parameters['tilt_curve'] = \ self.comboBox_tilt_tables.currentData() else: output_type = OUTPUT_TYPE.get( self.comboBox_output_type.currentText(), 'discrete') parameters['output_type'] = output_type parameters['output_format'] = app_data.get('output_format', 'csv') parameters['declination'] = self.dec_model.declination_value() return parameters """ Methods for declination """ # slot def declination_changed(self): self.dec_model.declination = self.lineEdit_declination.text() # slot def update_declination(self): self.lineEdit_declination.setText(str(self.dec_model.declination)) show_error(self.lineEdit_declination, self.dec_model.error_state) self.lineEdit_declination.setEnabled(self.dec_model.enabled) def _get_output_directory(self): if self.radioButton_output_directory.isChecked(): directory = self.lineEdit_output_folder.text() if not os.path.isdir(directory): QMessageBox.warning( self.frame, 'Select Folder', 'You must select a valid output path') return 'error' return directory def confirm_quit(self): if len(self.data_file_container) == 0: return True status = [file.status for file in self.data_file_container] if any([True for s in status if s == 'unconverted']): return dialogs.confirm_quit() else: return True
def writeSettings(self): settings = QSettings("Trolltech", "Pamac installer") settings.setValue("pos", self.pos()) settings.setValue("size", self.size())
def setTranslation(self, index): path = self.cmbTranslation.currentData() # Save settings sttgs = QSettings(qApp.organizationName(), qApp.applicationName()) sttgs.setValue("applicationTranslation", path)
class MainWindow(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.settings = QSettings() self.is_visible = True self.is_expanded = True self.is_move_action = False self.should_confirm_close = False self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.Tool) self.setAttribute(Qt.WA_NoSystemBackground, True) self.setAttribute(Qt.WA_TranslucentBackground, True) self.setAttribute(Qt.WA_QuitOnClose) self.setWindowIcon(QIcon(join(config.ASSETS_DIR, "droptopus.png"))) self.setWindowTitle("Droptopus") self.miniwin = MiniWindow(self) self.frame = DropFrame(self) self.frame.show() self.readSettings() self.content = QStackedWidget() self.setCentralWidget(self.content) self.content.addWidget(self.frame) self.content.addWidget(self.miniwin) self.setAcceptDrops(True) self.setMouseTracking(True) self.collapse() def contextMenuEvent(self, event): menu = QMenu(self) label = ("Expand", "Collapse")[self.is_expanded] expand_action = menu.addAction(label) about_action = menu.addAction("About") menu.addSeparator() quit_action = menu.addAction("Quit") action = menu.exec_(self.mapToGlobal(event.pos())) if action == expand_action: if self.is_expanded: self.collapse() else: self.expand() elif action == about_action: self.showAbout() elif action == quit_action: self.should_confirm_close = True self.close() def expand(self): if self.is_expanded: return self.is_expanded = True self.setAcceptDrops(False) self.content.hide() expanded = self.frame.sizeHint() self.setMinimumSize(expanded) self.content.setCurrentWidget(self.frame) self.content.show() self.resize(expanded) # on OSX the window will not automatically stay inside the screen like on Linux # we have to do it manually screen_rect = QDesktopWidget().screenGeometry() window_rect = self.frameGeometry() intersection = window_rect & screen_rect dx = window_rect.width() - intersection.width() dy = window_rect.height() - intersection.height() unseen = window_rect & intersection if dx != 0 or dy != 0: if window_rect.left() > screen_rect.left(): dx = dx * -1 if window_rect.bottom() > screen_rect.bottom(): dy = dy * -1 self.move(window_rect.left() + dx, window_rect.top() + dy) def collapse(self): if not self.is_expanded: return self.is_expanded = False self.setAcceptDrops(True) self.content.hide() mini = self.miniwin.sizeHint() self.setMinimumSize(mini) self.move(self.anchor) self.content.setCurrentWidget(self.miniwin) self.content.show() self.resize(mini) def showAbout(self): about = AboutDialog(self) about.setModal(True) about.show() def mouseReleaseEvent(self, event): self.is_move_action = False def mousePressEvent(self, event): if not event.button() == Qt.LeftButton: return self.is_move_action = True self.offset = event.pos() def mouseMoveEvent(self, event): if not self.is_move_action: return x = event.globalX() y = event.globalY() x_w = self.offset.x() y_w = self.offset.y() self.move(x - x_w, y - y_w) if self.content.currentWidget() == self.miniwin: self.anchor = self.pos() def writeSettings(self): self.settings.beginGroup("MainWindow") self.settings.setValue("anchor", self.anchor) self.settings.endGroup() def readSettings(self): self.settings.beginGroup("MainWindow") saved_anchor = self.settings.value("anchor", None) if saved_anchor != None: self.anchor = saved_anchor else: rect = QDesktopWidget().screenGeometry() mini = self.miniwin.sizeHint() self.anchor = QPoint(rect.right() - mini.width(), rect.bottom() - mini.height()) self.settings.endGroup() def userReallyWantsToQuit(self): if not self.should_confirm_close: return True reply = QMessageBox.question( self, "Close Droptopus", "Are you sure you want to close the application?", QMessageBox.Yes, QMessageBox.No, ) return reply == QMessageBox.Yes def closeEvent(self, event): if self.userReallyWantsToQuit(): self.writeSettings() event.accept() else: event.ignore() # def dragMoveEvent(self, event): # super(MainWindow, self).dragMoveEvent(event) def dragEnterEvent(self, event): if not self.is_expanded: QTimer.singleShot(200, self.expand) else: super(MainWindow, self).dragEnterEvent(event) def mouseDoubleClickEvent(self, event): if self.is_expanded: self.collapse() else: self.expand() def event(self, evt): et = evt.type() if et == events.COLLAPSE_WINDOW: evt.accept() self.collapse() return True if evt.type() == events.RELOAD_WIDGETS: evt.accept() if self.is_expanded: self.resize(self.sizeHint()) if et == events.EXPAND_WINDOW: evt.accept() self.expand() return True elif et == events.CLOSE_WINDOW: evt.accept() self.should_confirm_close = True self.close() return True return super(MainWindow, self).event(evt)
def closeEvent(self, _): self.closeHelp() settings = QSettings() #save window geometry settings.setValue("autosaveGeometry", self.saveGeometry())
class AppSettings: def __init__(self): self.settings: QSettings = None self.app_name: str = None self.app_dir: Union[Path, Any] = None self.docs_location: Path = Path( QStandardPaths.writableLocation(QStandardPaths.DocumentsLocation)) self.data: LiteDataStore = None def init(self): self.app_name = qApp.applicationName().lower() self.app_dir = Path( QStandardPaths.writableLocation(QStandardPaths.AppConfigLocation)) self.app_dir.mkdir(exist_ok=True) settings_file = f"{self.app_name}.ini" self.settings = QSettings( self.app_dir.joinpath(settings_file).as_posix(), QSettings.IniFormat) self.settings.sync() self.data = LiteDataStore(self.app_dir) def init_logger(self): log_file = f"{self.app_name}.log" handlers = [ logging.handlers.RotatingFileHandler( self.app_dir.joinpath(log_file), maxBytes=1000000, backupCount=1), logging.StreamHandler(), ] logging.basicConfig( handlers=handlers, format="%(asctime)s - %(filename)s:%(lineno)d - %(message)s", datefmt="%Y-%m-%d %H:%M:%S", level=logging.DEBUG, ) logging.captureWarnings(capture=True) def save_window_state(self, geometry, window_state): self.settings.setValue("geometry", geometry) self.settings.setValue("windowState", window_state) self.settings.sync() def save_configuration(self, app_config: AppConfig): self.settings.setValue(AppConfig.ITEM_CHECK, app_config.item_checked) self.settings.sync() def load_configuration(self): app_config = AppConfig() app_config.item_checked = self.settings.value( AppConfig.ITEM_CHECK, app_config.item_checked, ) return app_config def geometry(self): return self.settings.value("geometry", None) def window_state(self): return self.settings.value("windowState", None)
class Backup: ''' A utility to store and restore settings for use in testing. Be careful not to lose data. ''' setname = 'settings.zst' def __init__(self, backuploc=None, theDate=None): ''' Store the directory settings in self. The initial strings for the DB are in settings. If initialize is called, they are gone. Likeise, restoration will depend on reinitializing settings ''' self.settings = QSettings('zero_substance', 'structjour') self.apisettings = QSettings('zero_substance/stockapi', 'structjour') self.chartsettings = QSettings('zero_substance/chart', 'structjour') if backuploc is None: if not os.path.exists(self.settings.value('journal')): msg = f"Journal location {self.settings.value('journal')} does not exist" logging.error(msg) raise ValueError(msg) self.rootdir = os.path.normpath( os.path.join(self.settings.value('journal'), 'backup')) else: self.rootdir = backuploc d = pd.Timestamp( theDate) if theDate is not None else pd.Timestamp.now() self.bdir = os.path.join(self.rootdir, d.strftime("backup_%Y%m%d_%H.%M.%S")) self.bu_settings = os.path.join(self.bdir, self.setname) self.dbtrade = self.settings.value('tradeDb') self.dbstructjour = self.settings.value('structjourDb') self.setkeys = [] self.setvals = [] self.apisetkeys = [] self.apisetvals = [] # print(self.bu_settings) def initializeSettings(self): ''' Remove all settings except zero_substance/structjour/journal ''' for key in self.settings.allKeys(): if key != 'journal': self.settings.remove(key) self.apisettings.clear() self.chartsettings.clear() self.settings.sync() self.apisettings.sync() self.chartsettings.sync() def createDir(self): try: if not os.path.exists(self.rootdir): os.mkdir(self.rootdir) if not os.path.exists(self.bdir): os.mkdir(self.bdir) except Exception as ex: logging.error(ex) logging.error('Failed to create backup directory. ' + str(ex)) raise ValueError(ex) pass def removePickle(self): if os.path.exists(self.bu_settings): os.remove(self.bu_settings) def initializeVars(self): self.setkeys = [] self.setvals = [] self.apisetkeys = [] self.apisetvals = [] self.chartkeys = [] self.chartvals = [] def backupDatabase(self, theDir=None): ''' Helper method for backup. ''' self.bdir = self.bdir if theDir is None else theDir if not os.path.exists(self.bdir): raise ValueError(f'Backup directory {self.bdir} does not exist') dbtrade2 = os.path.split(self.dbtrade)[1] dbstructjour2 = os.path.split(self.dbstructjour)[1] dbtrade2 = os.path.normpath(os.path.join(self.bdir, dbtrade2)) dbstructjour2 = os.path.normpath(os.path.join(self.bdir, dbstructjour2)) copyfile(self.dbtrade, dbtrade2) logging.info(f'Trade database has been backed up to {dbtrade2}') if dbtrade2 != dbstructjour2: copyfile(self.dbstructjour, dbstructjour2) logging.info( f'Structjour database has been backed up to {dbstructjour2}') def restoreDatabase(self, theDir=None): self.bdir = self.bdir if theDir is None else theDir if not os.path.exists(self.bdir): raise ValueError(f'Backup directory {self.bdir} does not exist.') dbtrade = self.settings.value('tradeDb') dbstructjour = self.settings.value('structjourDb') dbt = os.path.join(self.bdir, os.path.split(dbtrade)[1]) dbs = os.path.join(self.bdir, os.path.split(dbstructjour)[1]) if os.path.exists(dbt): copyfile(dbt, dbtrade) logging.info(f'Db restored {dbt}') else: logging.error(f'Backup file {dbt} does not exist.') if dbs != dbt: if os.path.exists(dbs): copyfile(dbs, dbstructjour) logging.info(f'Db restored {dbs}') else: logging.error(f'Backup file {dbt} does not exist.') def storeSettings(self, replacePickle=False): self.createDir() if os.path.exists(self.bu_settings): if not replacePickle: return self.initializeVars() self.setkeys = self.settings.allKeys() for k in self.setkeys: self.setvals.append(self.settings.value(k)) self.apisetkeys = self.apisettings.allKeys() for k in self.apisetkeys: self.apisetvals.append(self.apisettings.value(k)) self.chartkeys = self.chartsettings.allKeys() for k in self.chartkeys: self.chartvals.append(self.chartsettings.value(k)) setsnkeys = [ self.setkeys, self.setvals, self.apisetkeys, self.apisetvals, self.chartkeys, self.chartvals ] with open(self.bu_settings, "wb") as f: '''Cannot pickle qsettings objects- so we pickle a list''' pickle.dump((setsnkeys), f) logging.info( f'Settings have been backed up to file {self.bu_settings}') def restoreSettings(self, theDir=None): theDir = self.mostRecent() if theDir is None else theDir bu_settings = os.path.join(theDir, self.setname) if os.path.exists(bu_settings): with open(bu_settings, "rb") as f: setsnkeys = pickle.load(f) for k, v in zip(setsnkeys[0], setsnkeys[1]): self.settings.setValue(k, v) for k2, v2 in zip(setsnkeys[2], setsnkeys[3]): self.apisettings.setValue(k2, v2) for k2, v2 in zip(setsnkeys[4], setsnkeys[5]): self.chartsettings.setValue(k2, v2) logging.info(f'Settings backed up to file {bu_settings}') else: logging.error(f'No settings backup found at {bu_settings}') def backup(self): self.storeSettings() self.backupDatabase() def restore(self, theDir=None): self.bdir = self.mostRecent() if theDir is None else theDir self.bdir = os.path.normpath(self.bdir) if not os.path.exists(self.bdir): raise ValueError(f'Backup directory {self.bdir} does not exist') self.restoreSettings(self.bdir) self.restoreDatabase(self.bdir) def mostRecent(self): thedirs = os.listdir(self.rootdir) maxdate = '' maxdir = None for thedir in thedirs: if thedir.startswith('backup_2'): d = thedir[7:].replace('.', ':') if d > maxdate: maxdir = thedir return os.path.join(self.rootdir, maxdir) if maxdir is not None else '' def _clearJournalDir(self): '''For Testing ONLY. TODO implement a seperate backup/restore for this one string''' # jdir = self.settings('journal') self.settings.remove('journal') def _restoreJournalDir(self): '''For Testing''' pass
def saveSettings(self): s = QSettings() s.setValue("experimental-features", self.experimentalFeatures.isChecked())
class InitialPrompt(QDialog): databaseSelected = pyqtSignal() def __init__(self, parent=None): super(InitialPrompt, self).__init__(parent) self.init() def init(self): self._settings = QSettings("Raul Sangonzalo", "Musician Suite") os.chdir(os.path.dirname(os.path.abspath(__file__))) resourcesPath = os.getcwd() resourcesPath = os.path.join(resourcesPath, "resources") self.MAIN_ICON = QIcon(os.path.join(resourcesPath, "test.ico")) self.setWindowTitle("Musician Suite") self.setWindowIcon(self.MAIN_ICON) mainLayout = QVBoxLayout(self) label = QLabel( "<p>Welcome to <b>Musician Suite 0.1b</b>.</p></br> Select an existing database or create a new one." ) buttonLayout = QHBoxLayout(self) newButton = QPushButton("New") importButton = QPushButton("Import") newButton.clicked.connect(self.createDatabase) importButton.clicked.connect(self.importDatabase) buttonLayout.addWidget(newButton) buttonLayout.addStretch(1) buttonLayout.addWidget(importButton) mainLayout.addWidget(label) mainLayout.addLayout(buttonLayout) def closeEvent(self, event): sys.exit(1) def createDatabase( self ): # different handling, so make sure db is appended at the end try: fileDialog = QFileDialog(filter="SQLite music database (*.db)") fileDialog.setAcceptMode(QFileDialog.AcceptSave) fileDialog.setDefaultSuffix("db") fileDialog.setOptions(QFileDialog.DontUseNativeDialog) fileDialog.exec() dbName = fileDialog.selectedFiles() if dbName[0] != '': print(dbName) self._settings.setValue("currentDatabase", dbName[0]) createTables() print("yes!") self.databaseSelected.emit() except Exception as e: self._settings.setValue("currentDatabase", None) QMessageBox.warning(None, "Error", "%s" % e) def importDatabase(self): dbName = QFileDialog().getOpenFileName( self, filter="SQLite music database (*.db)", options=QFileDialog.DontUseNativeDialog) if dbName[0] != '': self._settings.setValue("currentDatabase", dbName[0]) self.databaseSelected.emit()
class MainWindow(QMainWindow): """Show the main window of SCCT.""" EXIT_CODE_REBOOT = -123 def __init__(self, controller, app, showChangelog): """Init the main window.""" try: super().__init__() self._save = True self.tlock = TriggerLock() self.controller = controller self.game_list = {} with self.tlock: self.createFormMatchDataBox() self.createTabs() self.createHorizontalGroupBox() self.createBackgroundTasksBox() self.createMenuBar() mainLayout = QVBoxLayout() mainLayout.addWidget(self.tabs, 0) mainLayout.addWidget(self.fromMatchDataBox, 1) mainLayout.addWidget(self.backgroundTasksBox, 0) mainLayout.addWidget(self.horizontalGroupBox, 0) self.setWindowTitle( "WarCraft III – Meta Plays Casting Tool v{}".format( hwctool.__version__)) self.window = QWidget() self.window.setLayout(mainLayout) self.setCentralWidget(self.window) # self.size self.statusBar() self.leds = dict() for scope in self.controller.websocketThread.get_primary_scopes(): self.leds[scope] = LedIndicator(self) for key, led in self.leds.items(): self.controller.toogleLEDs(0, key, self) self.statusBar().addPermanentWidget(led) self.app = app self.controller.setView(self) self.controller.refreshButtonStatus() self.processEvents() self.settings = QSettings(ClientConfig.APP_NAME, ClientConfig.COMPANY_NAME) self.restoreGeometry( self.settings.value("geometry", self.saveGeometry())) self.restoreState( self.settings.value("windowState", self.saveState())) self.mysubwindows = dict() self.show() self.raise_() if showChangelog: self.openChangelog() except Exception as e: module_logger.exception("message") # def showAbout(self): # """Show subwindow with about info.""" # html = markdown2.markdown_path( # hwctool.settings.getResFile("about.md")) # html = html.replace("%VERSION%", hwctool.__version__) # if(not hwctool.__new_version__): # new_version = _("Halo Wars Casting Tool is up to date.") # else: # new_version = _("The new version {} is available!").format( # hwctool.__latest_version__) # html = html.replace('%NEW_VERSION%', new_version) # # use self as parent here # QMessageBox.about( # self, _("Halo Wars Casting Tool - About"), html) def closeEvent(self, event): """Close and clean up window.""" try: try: for name, window in self.mysubwindows.items(): if (window and window.isVisible()): window.close() finally: self.settings.setValue("geometry", self.saveGeometry()) self.settings.setValue("windowState", self.saveState()) self.controller.cleanUp(self._save) QMainWindow.closeEvent(self, event) # event.accept() except Exception as e: module_logger.exception("message") def updateGame(self, title): """updates game played""" self.setWindowTitle("{} – Meta Plays Casting Tool v{}".format( title, hwctool.__version__)) #change title hwctool.settings.races = hwctool.settings.game_races[ title] #update races hwctool.settings.current_game = title #update current game #uncheck, check for item in self.game_list.keys(): self.game_list[item].setChecked(False) self.game_list[title].setChecked(True) #updates dropdown menu for players max_no_sets = hwctool.settings.max_no_sets for player_idx in range(max_no_sets): for team_idx in range(2): self.cb_race[team_idx][player_idx].clear() for race in hwctool.settings.races: self.cb_race[team_idx][player_idx].addItem(race) #update styles self.openStyleDialog() def createMenuBar(self): """Create the menu bar.""" try: menubar = self.menuBar() # BROWSER SOURCES self.createBrowserSrcMenu() #SETTINGS settingsMenu = menubar.addMenu(_('Settings')) # apiAct = QAction(QIcon(hwctool.settings.getResFile( # 'browser.png')), _('Browser Sources'), self) # apiAct.setToolTip( # _('Edit Settings for all Browser Sources')) # apiAct.triggered.connect(self.openBrowserSourcesDialog) # settingsMenu.addAction(apiAct) apiAct = QAction(QIcon(hwctool.settings.getResFile('twitch.png')), _('Twitch'), self) apiAct.setToolTip( _('Edit Intro-Settings and API-Settings' ' for Twitch')) apiAct.triggered.connect(self.openApiDialog) settingsMenu.addAction(apiAct) # styleAct = QAction(QIcon(hwctool.settings.getResFile( # 'pantone.png')), _('Styles'), self) # styleAct.setToolTip('') # styleAct.triggered.connect(self.openStyleDialog) # settingsMenu.addAction(styleAct) apiAct = QAction(QIcon(hwctool.settings.getResFile('browser.png')), _('Intro settings'), self) apiAct.setToolTip(_('Edit Settings for all Browser Sources')) apiAct.triggered.connect(self.openBrowserSourcesDialog) settingsMenu.addAction(apiAct) styleAct = QAction( QIcon(hwctool.settings.getResFile('pantone.png')), _('Source styles'), self) styleAct.setToolTip('') styleAct.triggered.connect(self.openStyleDialog) settingsMenu.addAction(styleAct) ProfileMenu(self, self.controller) infoMenu = menubar.addMenu(_('Info && Links')) myAct = QAction(QIcon(hwctool.settings.getResFile('folder.png')), _('Open log folder'), self) myAct.triggered.connect(lambda: os.startfile( hwctool.settings.getAbsPath(hwctool.settings.getLogDir()))) infoMenu.addAction(myAct) infoMenu.addSeparator() websiteAct = QAction( QIcon(hwctool.settings.getResFile('github.ico')), 'Github - Meta Plays Casting Tool', self) websiteAct.triggered.connect(lambda: self.controller.openURL( "https://github.com/FluffyMaguro/MetaPlaysCastingTool/")) infoMenu.addAction(websiteAct) ixAct = QAction(QIcon(hwctool.settings.getResFile('icon.png')), 'Meta Plays (website)', self) ixAct.triggered.connect( lambda: self.controller.openURL("https://meta-plays.com/")) infoMenu.addAction(ixAct) websiteAct = QAction( QIcon(hwctool.settings.getResFile('favicon.jpg')), 'Maguro.one (website)', self) websiteAct.triggered.connect( lambda: self.controller.openURL("https://www.maguro.one/")) infoMenu.addAction(websiteAct) infoMenu.addSeparator() websiteAct = QAction( QIcon(hwctool.settings.getResFile('hwct.ico')), 'StarCraft Casting Tool - Docs', self) websiteAct.triggered.connect(lambda: self.controller.openURL( "https://teampheenix.github.io/StarCraft-Casting-Tool/")) infoMenu.addAction(websiteAct) myAct = QAction(QIcon(hwctool.settings.getResFile('patreon.png')), _('StarCraft Casting Tool - Patreon'), self) myAct.triggered.connect(lambda: self.controller.openURL( "https://www.patreon.com/StarCraftCastingTool")) infoMenu.addAction(myAct) myAct = QAction(QIcon(hwctool.settings.getResFile('donate.ico')), _('StarCraft Casting Tool - PayPal'), self) myAct.triggered.connect(lambda: self.controller.openURL( "https://paypal.me/StarCraftCastingTool")) infoMenu.addAction(myAct) #Choose the game gameMenu = menubar.addMenu(_('Game')) icon_dict = { 'StarCraft II': 'SC2.png', 'WarCraft III': 'WC3.png', 'Age of Empires IV': 'AOEIV.png', 'Age of Empires Online': 'AOEO.png', 'Age of Mythology': 'AOM.png', 'Halo Wars 2': 'HW.png', 'SpellForce 3': 'SF3.png' } for game in hwctool.settings.game_races: if game in icon_dict: myAct = QAction(QIcon( hwctool.settings.getResFile(icon_dict[game])), _(game), self, checkable=True) else: myAct = QAction(QIcon( hwctool.settings.getResFile('loading.png')), _(game), self, checkable=True) myAct.triggered.connect(partial(self.updateGame, game)) gameMenu.addAction(myAct) self.game_list[game] = myAct except Exception as e: module_logger.exception("message") def createBrowserSrcMenu(self): menubar = self.menuBar() main_menu = menubar.addMenu(_('Browser Sources')) srcs = [] srcs.append({ 'name': _('Intro'), 'file': 'intro.html', 'settings': lambda: self.openBrowserSourcesDialog('intro') }) srcs.append({'name': _('Score'), 'file': 'score.html'}) act = QAction(QIcon(hwctool.settings.getResFile('folder.png')), _('Open Folder'), self) act.triggered.connect(lambda: os.startfile( hwctool.settings.getAbsPath(hwctool.settings.casting_html_dir))) main_menu.addAction(act) main_menu.addSeparator() for src in srcs: myMenu = QMenu(src['name'], self) sub = src.get('sub', False) if sub: for icon in sub: mySubMenu = QMenu(icon['name'], self) icon['file'] = os.path.join( hwctool.settings.casting_html_dir, icon['file']) act = QAction( QIcon(hwctool.settings.getResFile('html.png')), _('Open in Browser'), self) act.triggered.connect( lambda x, file=icon['file']: self.controller.openURL( hwctool.settings.getAbsPath(file))) mySubMenu.addAction(act) act = QAction( QIcon(hwctool.settings.getResFile('copy.png')), _('Copy URL to Clipboard'), self) act.triggered.connect( lambda x, file=icon['file']: QApplication.clipboard( ).setText(hwctool.settings.getAbsPath(file))) mySubMenu.addAction(act) if icon.get('settings', None) is not None: act = QAction( QIcon(hwctool.settings.getResFile('browser.png')), _('Settings'), self) act.triggered.connect(icon['settings']) mySubMenu.addAction(act) myMenu.addMenu(mySubMenu) else: src['file'] = os.path.join(hwctool.settings.casting_html_dir, src['file']) act = QAction(QIcon(hwctool.settings.getResFile('html.png')), _('Open in Browser'), self) act.triggered.connect( lambda x, file=src['file']: self.controller.openURL( hwctool.settings.getAbsPath(file))) myMenu.addAction(act) act = QAction(QIcon(hwctool.settings.getResFile('copy.png')), _('Copy URL to Clipboard'), self) act.triggered.connect( lambda x, file=src['file']: QApplication.clipboard( ).setText(hwctool.settings.getAbsPath(file))) myMenu.addAction(act) if src.get('settings', None) is not None: act = QAction( QIcon(hwctool.settings.getResFile('browser.png')), _('Settings'), self) act.triggered.connect(src['settings']) myMenu.addAction(act) main_menu.addMenu(myMenu) main_menu.addSeparator() # apiAct = QAction(QIcon(hwctool.settings.getResFile( # 'browser.png')), _('Settings'), self) # apiAct.setToolTip( # _('Edit Settings for all Browser Sources')) # apiAct.triggered.connect(self.openBrowserSourcesDialog) # main_menu.addAction(apiAct) # styleAct = QAction(QIcon(hwctool.settings.getResFile( # 'pantone.png')), _('Styles'), self) # styleAct.setToolTip('') # styleAct.triggered.connect(self.openStyleDialog) # main_menu.addAction(styleAct) def openApiDialog(self): """Open subwindow with connection settings.""" self.mysubwindows['connections'] = SubwindowConnections() self.mysubwindows['connections'].createWindow(self) self.mysubwindows['connections'].show() def openStyleDialog(self): """Open subwindow with style settings.""" self.mysubwindows['styles'] = SubwindowStyles() self.mysubwindows['styles'].createWindow(self) self.mysubwindows['styles'].show() def openBrowserSourcesDialog(self, tab=''): """Open subwindow with browser sources settings.""" self.mysubwindows['browser'] = SubwindowBrowserSources() self.mysubwindows['browser'].createWindow(self, tab) self.mysubwindows['browser'].show() def openReadme(self): """Open subwindow with readme viewer.""" self.mysubwindows['readme'] = SubwindowMarkdown() self.mysubwindows['readme'].createWindow( self, _("Readme"), hwctool.settings.getResFile('readme.ico'), hwctool.settings.getResFile("../README.md")) self.mysubwindows['readme'].show() def openChangelog(self): """Open subwindow with readme viewer.""" self.mysubwindows['changelog'] = SubwindowMarkdown() self.mysubwindows['changelog'].createWindow( self, "Halo Wars Casting Tool " + _("Changelog"), hwctool.settings.getResFile("changelog.png"), hwctool.settings.getResFile("../CHANGELOG.md")) self.mysubwindows['changelog'].show() def changeLanguage(self, language): """Change the language.""" hwctool.settings.config.parser.set("SCT", "language", language) self.restart() def createTabs(self): """Create tabs in main window.""" try: # Initialize tab screen self.tabs = QTabWidget() self.tab2 = QWidget() # self.tabs.resize(300,200) # Add tabs self.tabs.addTab(self.tab2, _("Custom Match")) # Create second tab self.tab2.layout = QVBoxLayout() container = QHBoxLayout() label = QLabel() label.setMinimumWidth(self.labelWidth) container.addWidget(label, 0) label = QLabel(_("Match Format:")) label.setMinimumWidth(80) container.addWidget(label, 0) container.addWidget(QLabel(_("Best of")), 0) self.cb_bestof = QComboBox() for idx in range(0, hwctool.settings.max_no_sets): self.cb_bestof.addItem(str(idx + 1)) self.cb_bestof.setCurrentIndex(3) string = _('"Best of 6/4": First, a Bo5/3 is played and the' ' ace map gets extended to a Bo3 if needed;' ' Best of 2: Bo3 with only two maps played.') self.cb_bestof.setToolTip(string) self.cb_bestof.setMaximumWidth(40) self.cb_bestof.currentIndexChanged.connect(self.changeBestOf) container.addWidget(self.cb_bestof, 0) container.addWidget(QLabel(_(" but at least")), 0) self.cb_minSets = QComboBox() self.cb_minSets.setToolTip( _('Minimum number of maps played (even if the match' ' is decided already)')) self.cb_minSets.setMaximumWidth(40) container.addWidget(self.cb_minSets, 0) container.addWidget(QLabel(" " + _("maps") + " "), 0) self.cb_minSets.currentIndexChanged.connect( lambda idx: self.highlightApplyCustom()) ###### APPLY BUTTON label = QLabel("") container.addWidget(label, 1) self.applycustom_is_highlighted = False self.pb_applycustom = QToolButton() action = QAction(_("Apply Format")) action.triggered.connect(self.applycustom_click) self.pb_applycustom.setDefaultAction(action) self.pb_applycustom.setFixedWidth(100) container.addWidget(self.pb_applycustom, 0) self.defaultButtonPalette = self.pb_applycustom.palette() self.tab2.layout.addLayout(container) ###### RESET BUTTON label = QLabel("") container.addWidget(label, 1) self.pb_resetdata = QPushButton(_("Reset Match Data")) self.pb_resetdata.setFixedWidth(100) self.pb_resetdata.clicked.connect(self.resetdata_click) container.addWidget(self.pb_resetdata, 0) self.tab2.layout.addLayout(container) self.tab2.setLayout(self.tab2.layout) ###### SPACING container.insertSpacing(-1, 100) ########## REMOVED CUSTOM URL # container = QHBoxLayout() # label = QLabel() # label.setMinimumWidth(self.labelWidth) # container.addWidget(label, 0) # label = QLabel(_("Match-URL:")) # label.setMinimumWidth(80) # container.addWidget(label, 0) self.le_url_custom = MonitoredLineEdit() # self.le_url_custom.setAlignment(Qt.AlignCenter) # self.le_url_custom.setToolTip( # _('Optionally specify the Match-URL,' # ' e.g., for Nightbot commands')) # self.le_url_custom.setPlaceholderText( # _("Specify the Match-URL of your Custom Match")) # completer = QCompleter( # ["http://"], self.le_url_custom) # completer.setCaseSensitivity(Qt.CaseInsensitive) # completer.setCompletionMode( # QCompleter.UnfilteredPopupCompletion) # completer.setWrapAround(True) # self.le_url_custom.setCompleter(completer) # self.le_url_custom.setMinimumWidth(360) # self.le_url_custom.textModified.connect(self.highlightApplyCustom) # container.addWidget(self.le_url_custom, 11) except Exception as e: module_logger.exception("message") def changeBestOf(self, bestof): """Change the minimum sets combo box on change of BoX.""" bestof = bestof + 1 self.cb_minSets.clear() self.highlightApplyCustom() for idx in range(0, bestof): self.cb_minSets.addItem(str(idx + 1)) if bestof == 2: self.cb_minSets.setCurrentIndex(1) else: self.cb_minSets.setCurrentIndex(int((bestof - 1) / 2)) def updatePlayerCompleters(self): """Refresh the completer for the player line edits.""" list = ["TBD"] + self.controller.historyManager.getPlayerList() for player_idx in range(self.max_no_sets): for team_idx in range(2): completer = QCompleter(list, self.le_player[team_idx][player_idx]) completer.setCaseSensitivity(Qt.CaseInsensitive) completer.setCompletionMode(QCompleter.InlineCompletion) completer.setWrapAround(True) self.le_player[team_idx][player_idx].setCompleter(completer) def createFormMatchDataBox(self): """Create the froms for the match data.""" try: self.max_no_sets = hwctool.settings.max_no_sets self.scoreWidth = 35 self.raceWidth = 100 self.labelWidth = 25 self.mimumLineEditWidth = 130 self.fromMatchDataBox = QGroupBox(_("Match Data")) layout2 = QVBoxLayout() self.le_league = MonitoredLineEdit() self.le_league.setText("League TBD") self.le_league.setAlignment(Qt.AlignCenter) self.le_league.setPlaceholderText("League TBD") self.le_league.textModified.connect(self.league_changed) policy = QSizePolicy() policy.setHorizontalStretch(3) policy.setHorizontalPolicy(QSizePolicy.Expanding) policy.setVerticalStretch(1) policy.setVerticalPolicy(QSizePolicy.Fixed) self.le_league.setSizePolicy(policy) self.le_player = [[ MonitoredLineEdit() for x in range(self.max_no_sets) ] for y in range(2)] self.cb_race = [[QComboBox() for x in range(self.max_no_sets)] for y in range(2)] self.sl_score = [ QSlider(Qt.Horizontal) for y in range(self.max_no_sets) ] self.label_set = [ QLabel('#{}'.format(y + 1), self) for y in range(self.max_no_sets) ] self.setContainer = [ QHBoxLayout() for y in range(self.max_no_sets) ] container = QGridLayout() button = QPushButton() pixmap = QIcon(hwctool.settings.getResFile('update.png')) button.setIcon(pixmap) button.clicked.connect(lambda: self.controller.swapTeams()) button.setFixedWidth(self.labelWidth) button.setToolTip(_("Swap players.")) container.addWidget(button, 0, 0, 1, 1) label = QLabel(_("League:")) label.setAlignment(Qt.AlignCenter) label.setFixedWidth(self.raceWidth) container.addWidget(label, 0, 1, 1, 1) container.addWidget(self.le_league, 0, 2, 1, 3) label = QLabel("") label.setFixedWidth(self.raceWidth) container.addWidget(label, 0, 5, 1, 1) layout2.addLayout(container) for player_idx in range(self.max_no_sets): for team_idx in range(2): self.cb_race[team_idx][player_idx].\ currentIndexChanged.connect( lambda idx, t=team_idx, p=player_idx: self.race_changed(t, p)) self.le_player[team_idx][player_idx].textModified.connect( lambda t=team_idx, p=player_idx: self.player_changed( t, p)) self.le_player[team_idx][player_idx].setText("TBD") self.le_player[team_idx][player_idx].setAlignment( Qt.AlignCenter) self.le_player[team_idx][player_idx].setPlaceholderText( _("Player {} of team {}").format( player_idx + 1, team_idx + 1)) self.le_player[team_idx][player_idx].setMinimumWidth( self.mimumLineEditWidth) for race in hwctool.settings.races: self.cb_race[team_idx][player_idx].addItem(race) self.cb_race[team_idx][player_idx].setFixedWidth( self.raceWidth) self.sl_score[player_idx].setMinimum(-1) self.sl_score[player_idx].setMaximum(1) self.sl_score[player_idx].setValue(0) self.sl_score[player_idx].setTickPosition( QSlider.TicksBothSides) self.sl_score[player_idx].setTickInterval(1) self.sl_score[player_idx].setTracking(False) self.sl_score[player_idx].valueChanged.connect( lambda x, player_idx=player_idx: self.sl_changed( player_idx, x)) self.sl_score[player_idx].setToolTip(_('Set the score')) self.sl_score[player_idx].setFixedWidth(self.scoreWidth) self.setContainer[player_idx] = QHBoxLayout() # self.label_set[player_idx].setText("#" + str(player_idx + 1)) self.label_set[player_idx].setAlignment(Qt.AlignCenter) self.label_set[player_idx].setFixedWidth(self.labelWidth) self.setContainer[player_idx].addWidget( self.label_set[player_idx], 0) self.setContainer[player_idx].addWidget( self.cb_race[0][player_idx], 0) self.setContainer[player_idx].addWidget( self.le_player[0][player_idx], 4) self.setContainer[player_idx].addWidget( self.sl_score[player_idx], 0) self.setContainer[player_idx].addWidget( self.le_player[1][player_idx], 4) self.setContainer[player_idx].addWidget( self.cb_race[1][player_idx], 0) layout2.addLayout(self.setContainer[player_idx]) layout2.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.fromMatchDataBox.setLayout(layout2) self.updatePlayerCompleters() except Exception as e: module_logger.exception("message") def createHorizontalGroupBox(self): """Create horizontal group box for tasks.""" try: self.horizontalGroupBox = QGroupBox(_("Tasks")) layout = QHBoxLayout() self.pb_twitchupdate = QPushButton(_("Update Twitch Title")) self.pb_twitchupdate.clicked.connect(self.updatetwitch_click) # self.pb_nightbotupdate = QPushButton( # _("Update Nightbot")) # self.pb_nightbotupdate.clicked.connect(self.updatenightbot_click) self.pb_resetscore = QPushButton(_("Reset Score")) self.pb_resetscore.clicked.connect(self.resetscore_click) layout.addWidget(self.pb_twitchupdate) # layout.addWidget(self.pb_nightbotupdate) layout.addWidget(self.pb_resetscore) self.horizontalGroupBox.setLayout(layout) except Exception as e: module_logger.exception("message") def createBackgroundTasksBox(self): """Create group box for background tasks.""" try: self.backgroundTasksBox = QGroupBox(_("Background Tasks")) self.cb_autoTwitch = QCheckBox(_("Auto Twitch Update")) self.cb_autoTwitch.setChecked(False) self.cb_autoTwitch.stateChanged.connect(self.autoTwitch_change) # self.cb_autoNightbot = QCheckBox( # _("Auto Nightbot Update")) # self.cb_autoNightbot.setChecked(False) # self.cb_autoNightbot.stateChanged.connect( # self.autoNightbot_change) layout = QGridLayout() layout.addWidget(self.cb_autoTwitch, 0, 0) # layout.addWidget(self.cb_autoNightbot, 0, 1) self.backgroundTasksBox.setLayout(layout) except Exception as e: module_logger.exception("message") def autoTwitch_change(self): """Handle change of auto twitch check box.""" try: if (self.cb_autoTwitch.isChecked()): self.controller.autoRequestsThread.activateTask('twitch') else: self.controller.autoRequestsThread.deactivateTask('twitch') except Exception as e: module_logger.exception("message") # def autoNightbot_change(self): # """Handle change of auto twitch check box.""" # try: # if(self.cb_autoNightbot.isChecked()): # self.controller.autoRequestsThread.activateTask('nightbot') # else: # self.controller.autoRequestsThread.deactivateTask('nightbot') # except Exception as e: # module_logger.exception("message") def autoUpdate_change(self): """Handle change of auto score update check box.""" try: if (self.cb_autoUpdate.isChecked()): self.controller.runSC2ApiThread("updateScore") else: self.controller.stopSC2ApiThread("updateScore") except Exception as e: module_logger.exception("message") def autoToggleScore_change(self): """Handle change of toggle score check box.""" try: if (self.cb_autoToggleScore.isChecked()): self.controller.runSC2ApiThread("toggleScore") else: self.controller.stopSC2ApiThread("toggleScore") except Exception as e: module_logger.exception("message") def autoToggleProduction_change(self): """Handle change of toggle production tab check box.""" try: if (self.cb_autoToggleProduction.isChecked()): self.controller.runSC2ApiThread("toggleProduction") else: self.controller.stopSC2ApiThread("toggleProduction") except Exception as e: module_logger.exception("message") def applyCustomFormat(self, format): """Handle click to apply custom format.""" QApplication.setOverrideCursor(Qt.WaitCursor) try: with self.tlock: self.controller.matchData.applyCustomFormat(format) self.controller.updateForms() self.resizeWindow() self.highlightApplyCustom(False) except Exception as e: module_logger.exception("message") finally: QApplication.restoreOverrideCursor() def applycustom_click(self): """Handle click to apply custom match.""" QApplication.setOverrideCursor(Qt.WaitCursor) try: with self.tlock: self.statusBar().showMessage(_('Applying Custom Match...')) msg = self.controller.applyCustom( int(self.cb_bestof.currentText()), False, True, int(self.cb_minSets.currentText()), self.le_url_custom.text().strip()) self.statusBar().showMessage(msg) self.highlightApplyCustom(False) except Exception as e: module_logger.exception("message") finally: QApplication.restoreOverrideCursor() def resetdata_click(self): """Handle click to reset the data.""" QApplication.setOverrideCursor(Qt.WaitCursor) try: with self.tlock: msg = self.controller.resetData() self.statusBar().showMessage(msg) except Exception as e: module_logger.exception("message") finally: QApplication.restoreOverrideCursor() def openBrowser_click(self): """Handle request to open URL in browser.""" try: url = self.le_url.text() self.controller.openURL(url) except Exception as e: module_logger.exception("message") # def updatenightbot_click(self): # """Handle click to change nightbot command.""" # try: # self.statusBar().showMessage(_('Updating Nightbot Command...')) # msg = self.controller.updateNightbotCommand() # self.statusBar().showMessage(msg) # except Exception as e: # module_logger.exception("message") def updatetwitch_click(self): """Handle click to change twitch title.""" try: self.statusBar().showMessage(_('Updating Twitch Title...')) msg = self.controller.updateTwitchTitle() self.statusBar().showMessage(msg) except Exception as e: module_logger.exception("message") def resetscore_click(self, myteam=False): """Handle click to reset the score.""" try: self.statusBar().showMessage(_('Resetting Score...')) with self.tlock: for set_idx in range(self.max_no_sets): self.sl_score[set_idx].setValue(0) self.controller.matchData.setMapScore(set_idx, 0, overwrite=True) if myteam: self.sl_team.setValue(0) self.controller.matchData.setMyTeam(0) if not self.controller.resetWarning(): self.statusBar().showMessage('') except Exception as e: module_logger.exception("message") def setScore(self, idx, score, allkill=True): """Handle change of the score.""" try: if (self.sl_score[idx].value() == 0): self.statusBar().showMessage(_('Updating Score...')) with self.tlock: self.sl_score[idx].setValue(score) self.controller.matchData.setMapScore(idx, score, True) if not self.controller.resetWarning(): self.statusBar().showMessage('') return True else: return False except Exception as e: module_logger.exception("message") def league_changed(self): if not self.tlock.trigger(): return self.controller.matchData.setLeague(self.le_league.text()) def sl_changed(self, set_idx, value): """Handle a new score value.""" try: if self.tlock.trigger(): if set_idx == -1: self.controller.matchData.setMyTeam(value) else: self.controller.matchData.setMapScore(set_idx, value, True) except Exception as e: module_logger.exception("message") def player_changed(self, team_idx, player_idx): """Handle a change of player names.""" if not self.tlock.trigger(): return try: player = self.le_player[team_idx][player_idx].text().strip() race = self.cb_race[team_idx][player_idx].currentText() if (player_idx == 0 and self.controller.matchData.getSolo()): for p_idx in range(1, self.max_no_sets): self.le_player[team_idx][p_idx].setText(player) self.player_changed(team_idx, p_idx) self.controller.historyManager.insertPlayer(player, race) self.controller.matchData.setPlayer( team_idx, player_idx, self.le_player[team_idx][player_idx].text()) if race == "Random": new_race = self.controller.historyManager.getRace(player) if new_race != "Random": index = self.cb_race[team_idx][player_idx].findText( new_race, Qt.MatchFixedString) if index >= 0: self.cb_race[team_idx][player_idx].setCurrentIndex( index) elif player.lower() == "tbd": self.cb_race[team_idx][player_idx].setCurrentIndex(0) self.updatePlayerCompleters() except Exception as e: module_logger.exception("message") def race_changed(self, team_idx, player_idx): """Handle a change of player names.""" if not self.tlock.trigger(): return player = self.le_player[team_idx][player_idx].text().strip() race = self.cb_race[team_idx][player_idx].currentText() self.controller.historyManager.insertPlayer(player, race) self.controller.matchData.setRace( team_idx, player_idx, self.cb_race[team_idx][player_idx].currentText()) try: if (player_idx == 0 and self.controller.matchData.getSolo()): race = self.cb_race[team_idx][0].currentText() for player_idx in range(1, self.max_no_sets): index = self.cb_race[team_idx][player_idx].findText( race, Qt.MatchFixedString) if index >= 0: self.cb_race[team_idx][player_idx].setCurrentIndex( index) except Exception as e: module_logger.exception("message") def highlightApplyCustom(self, highlight=True, force=False): if not force and not self.tlock.trigger(): return try: if self.applycustom_is_highlighted == highlight: return highlight except AttributeError: return False if highlight: myPalette = self.pb_applycustom.palette() myPalette.setColor(QPalette.Background, Qt.darkRed) myPalette.setColor(QPalette.ButtonText, Qt.darkRed) self.pb_applycustom.setPalette(myPalette) else: self.pb_applycustom.setPalette(self.defaultButtonPalette) self.applycustom_is_highlighted = highlight return highlight def resizeWindow(self): """Resize the window height to size hint.""" if (not self.isMaximized()): self.processEvents() self.resize(self.width(), self.sizeHint().height()) def processEvents(self): """Process ten PyQt5 events.""" for i in range(0, 10): self.app.processEvents() def restart(self, save=True): """Restart the main window.""" self._save = save self.close() self.app.exit(self.EXIT_CODE_REBOOT)