def _newMdiSubWindow(self, filterOrService, windowTitle): res = NexxTMdiSubWindow(None) res.setAttribute(Qt.WA_DeleteOnClose, False) self.mdi.addSubWindow(res) self._registerWindow(res, res.windowTitleChanged) if isinstance(filterOrService, Filter): propColl = filterOrService.guiState() res.setWindowTitle( propColl.objectName() if windowTitle is None else windowTitle) else: app = Application.activeApplication.getApplication() propColl = app.guiState("services/MainWindow") res.setWindowTitle( "<unnamed>" if windowTitle is None else windowTitle) prefix = re.sub(r'[^A-Za-z_0-9]', '_', "MainWindow_MDI_" + res.windowTitle()) i = dict(window=res, propColl=propColl, prefix=prefix) self.managedMdiWindows.append(i) window = i["window"] propColl = i["propColl"] prefix = i["prefix"] propColl.defineProperty(prefix + "_geom", "", "Geometry of MDI window") b = QByteArray.fromBase64( bytes(propColl.getProperty(prefix + "_geom"), "ascii")) window.restoreGeometry(b) logger.debug("restored geometry %s:%s (%s)", prefix, window.geometry(), b) propColl.defineProperty(prefix + "_visible", 1, "Visibility of MDI window") if propColl.getProperty(prefix + "_visible"): window.show() else: window.hide() self.mdiSubWindowCreated.emit(res) return res
def get_pixmap(self): base64data = b'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' byte_array = QByteArray.fromBase64(base64data) pixmap = QPixmap() pixmap.loadFromData(byte_array) return pixmap
def load_1_0_0(self, data=dict): ''' Load v1.0.0 of .pii version file. Parameters ---------- data: (dict) Dictionary of date from .pii file. ''' if data[PII.BACKGROUND]: # Import Image Data newPix = QPixmap() newPix.loadFromData( QByteArray.fromBase64(data[PII.BACKGROUND].encode('ascii')), "PNG") self._backgroundNode.setPixmap(newPix) for each in data[PII.NODES]: if each["type"] == PIINode.PICK: self.create_node(text=each[PIIPick.TEXT], size=each[PIIPick.SIZE], textColor=QColor(*each[PIIPick.COLOR]), bgColor=QColor(*each[PIIPick.BACKGROUND]), position=QPointF(*each[PIIPick.POSITION]), items=each[PIIPick.SELECTION], shape=each[PIIPick.SHAPE]) elif each["type"] == PIINode.BUTTON: self.create_button(position=QPointF(*each[PIIButton.POSITION]), text=each[PIIButton.TEXT], size=each[PIIButton.SIZE], textColor=QColor(*each[PIIButton.COLOR]), bgColor=QColor(*each[PIIButton.BACKGROUND]), cmd=each[PIIButton.COMMAND], cmdType=each[PIIButton.COMMANDTYPE])
def _restore_state_from_settings(self, ) -> None: if not self._settings.contains('main_state'): return state = QByteArray.fromBase64( cast(QByteArray, self._settings.value('main_state'))) if state: self.restoreState(state, __UI_VERSION__)
def _restore_geometry_from_settings(self, ) -> None: if not self._settings.contains('main_geometry'): return geometry = QByteArray.fromBase64( cast(QByteArray, self._settings.value('main_geometry'))) if geometry: self.restoreGeometry(geometry)
def runReport(self, pid, method, par): self.boolDirect = True self.mtypeCall = "report" self.mpid = pid self.mmethod = method self.mparams = par # bparams = self.prepareParams() request = self.prepareRequest() # reply = self.data_request(request, bparams) data = reply.readAll() parseError = QJsonParseError() resultObject = {} resultObject["data"] = "error" document = QJsonDocument.fromJson(data, parseError) if parseError.error == True: resultObject["data"] = "error" else: if document.isObject(): jv = document.object() if jv.__contains__( "result") == True and jv["result"].__class__() == []: #tryton 4.0 #'result': ['pdf', {'base64':wwwwww, '__class__':'bytes'}, False,'Printis'] jre = jv["result"] namesecs = "tryton_" + self.mpid + str( QDateTime.currentMSecsSinceEpoch()) + "." + jre[0] mdir = QDir(self.mDir + QDir.separator() + "tempReports") if mdir.exists() == False: s = QDir(self.mDir) s.mkdir("tempReports") filename = self.mDir + QDir.separator( ) + "tempReports" + QDir.separator() + namesecs file = QFile(filename) if file.open(QIODevice.WriteOnly) == False: #error self.signalResponse.emit(self.mpid, 7, {}) print("error", filename, file.errorString()) else: bafile = QByteArray.fromBase64( jre[1]["base64"].encode()) file.write(bafile) file.close() QDesktopServices.openUrl(QUrl(filename)) else: if document.isArray() == True: self.signalResponse.emit(self.mpid, 7, {}) self.processingData(data, reply)
def decode_image(text: str) -> QImage: encoded_bytes = QByteArray(text.encode('utf8')) image_bytes = QByteArray.fromBase64(encoded_bytes) image = QImage.fromData(image_bytes) return image
def rechargeNet(self, preferences, username): #version 1.1 up thesamodule data = self.m_qjsonnetwork.callDirect( "version internal", "model.thesamodule.config.search_read", [[], 0, 1, [], ["internal_version"], preferences]) if not data["data"] == "error": self.internal_version = data["data"]["result"][0][ "internal_version"] if float(self.internal_version) > 1.0: data = self.m_qjsonnetwork.callDirect( "cachedel", "model.thesamodule.config.search_read", [[], 0, 1, [], ["deletecache"], preferences]) if not data["data"] == "error": if data["data"]["result"][0]["deletecache"] == True: self.actionCache_ = "deleteOnCompleted" else: self.actionCache_ = "notDelete" sysdir = QDir(self.mDir + QDir.separator() + _dirSystem) DIR_QML_SYS = sysdir.path() DIR_QML_SYS_LOST = DIR_QML_SYS + QDir.separator() + "lost" sysdirlost = QDir(DIR_QML_SYS_LOST) #revisar folder systemnet if sysdir.exists() == False: s = QDir(self.mDir) s.mkdir(_dirSystem) #revisar folder systemnet lost if sysdirlost.exists() == False: sl = QDir(DIR_QML_SYS) sl.mkdir("lost") #find all files en folder net listSysFiles = os.listdir(DIR_QML_SYS) if "lost" in listSysFiles: listSysFiles.remove("lost") # data = {} data["data"] = "error" if float(self.internal_version) > 1.1: data = self.m_qjsonnetwork.callDirect( "findforuser", "model.thesamodule.usersfolder.search_read", [[ "AND", ["users.user.name", "=", username], ["activefolder", "=", True] ], 0, 1, [], ["qmlfiles"], preferences]) if not data["data"] == "error": result = data["data"]["result"] if len(result) > 0: idfiles = result[0]["qmlfiles"] data = self.m_qjsonnetwork.callDirect( "rechargeNetStep1", "model.thesamodule.thesamodule.read", [idfiles, [ "checksum", "filename", ], preferences]) if len(idfiles) == 0: self.m_qjsonnetwork.signalResponse.emit( "systemnet", 15, {"noqmlfiles": ""}) else: #buscar default data = self.m_qjsonnetwork.callDirect( "findforuser", "model.thesamodule.usersfolder.search_read", [[ "AND", ["type", "=", "default"], ["activefolder", "=", True] ], 0, 1, [], ["qmlfiles"], preferences]) if not data["data"] == "error": result = data["data"]["result"] if len(result) > 0: idfiles = result[0]["qmlfiles"] data = self.m_qjsonnetwork.callDirect( "rechargeNetStep1", "model.thesamodule.thesamodule.read", [ idfiles, [ "checksum", "filename", ], preferences ]) if len(idfiles) == 0: self.m_qjsonnetwork.signalResponse.emit( "systemnet", 15, {"noqmlfiles": ""}) else: self.m_qjsonnetwork.signalResponse.emit( "systemnet", 12, {"noqmlfiles": ""}) else: self.m_qjsonnetwork.signalResponse.emit( "systemnet", 13, {"error": ""}) else: self.m_qjsonnetwork.signalResponse.emit( "systemnet", 13, {"error": ""}) else: data = self.m_qjsonnetwork.callDirect( "rechargeNetStep1", "model.thesamodule.thesamodule.search_read", [[], 0, 1000, [], ["checksum", "filename"], preferences]) if not data["data"] == "error": resultnet = data["data"]["result"] mapnet = {} mapids = {} listNetFiles = [] for file in resultnet: mapnet[file["filename"]] = file["checksum"] mapids[file["filename"]] = file["id"] listNetFiles.append(file["filename"]) #buscar faltantes en system y los updates #buscar los que ya no deben estar mapsysnet = {} listToUpdate = set() #new or update listToErase = [] for file in listSysFiles: try: with open(DIR_QML_SYS + QDir.separator() + file, "rb") as binary_file: data = binary_file.read() chek = hashlib.md5(data).hexdigest() mapsysnet[file] = chek except: listToUpdate.add(file) for file in listNetFiles: if file in listSysFiles: if mapnet[file] != mapsysnet[file]: listToUpdate.add(file) # update else: listToUpdate.add(file) # new for file in listSysFiles: if not file in listNetFiles: listToErase.append(file) # erase listToUpdate = list(listToUpdate) ids = [] for file in listToUpdate: ids.append(mapids[file]) data = self.m_qjsonnetwork.callDirect( "rechargeNetStep2", "model.thesamodule.thesamodule.read", [ids, [ "filebinary", "filename", ], preferences]) errors = [] if not data["data"] == "error": resultnet = data["data"]["result"] for file in resultnet: filename = DIR_QML_SYS + QDir.separator( ) + file["filename"] qfile = QFile(filename) if qfile.open(QIODevice.WriteOnly) == False: errors.append(filename) print("error", filename, qfile.errorString()) else: print("update", file["filename"]) bafile = QByteArray.fromBase64( file["filebinary"]["base64"].encode()) qfile.write(bafile) qfile.close() if len(errors) > 0: self.m_qjsonnetwork.signalResponse.emit( "systemnet", 33, {"error": errors}) return False #erase for file in listToErase: print("moviendo", file) shutil.move(DIR_QML_SYS + QDir.separator() + file, DIR_QML_SYS_LOST + QDir.separator() + file) return True else: #erase all files, no conexion con thesa module for file in listSysFiles: print("moviendo", file) shutil.move(DIR_QML_SYS + QDir.separator() + file, DIR_QML_SYS_LOST + QDir.separator() + file) self.m_qjsonnetwork.signalResponse.emit("systemnet", 34, {"error": ""}) return False
def __init__(self, parent=None, post_stats: bool = True): # instantiation super().__init__(parent, post_stats) self.ui.p1_layout = QVBoxLayout(self.ui.page_1) self.ui.p1_layout.setContentsMargins(0, 0, 0, 0) self.ui.p1_description = QLabel( 'This app calculates the mean flame height in accordance with ' '"PD 7974-1:2019 Application of fire safety engineering principles to the design of buildings. Part 1: ' 'Initiation and development of fire within the enclosure of origin (Sub-system 1)".' ) self.ui.p1_description.setFixedWidth(350) self.ui.p1_description.setWordWrap(True) self.ui.p1_layout.addWidget(self.ui.p1_description) self.ui.p1_figure = QLabel() self.ui.p1_figure.setPixmap(join(fsetoolsGUI.__root_dir__, 'gui', 'images', f'{self.app_id}-1.png')) self.ui.p1_layout.addWidget(self.ui.p1_figure) self.ui.p2_layout = QGridLayout(self.ui.page_2) self.ui.p2_layout.setVerticalSpacing(5), self.ui.p2_layout.setHorizontalSpacing(5) self.ui.p2_layout.addWidget(QLabel('<b>Inputs</b>'), 0, 0, 1, 3) self.add_lineedit_set_to_grid(self.ui.p2_layout, 1, 'p2_in_Q_dot_or_Q_dot_l', 'Total HRR', 'kW') self.add_lineedit_set_to_grid(self.ui.p2_layout, 2, 'p2_in_L_A_or_D', 'Fire diameter', 'm') self.add_lineedit_set_to_grid(self.ui.p2_layout, 3, 'p2_in_L_B', 'Fire shorter dimension', 'm') self.add_lineedit_set_to_grid(self.ui.p2_layout, 4, 'p2_in_rho_0', 'Air density', 'kg/m<sup>3</sup>') self.add_lineedit_set_to_grid(self.ui.p2_layout, 5, 'p2_in_c_p_0', 'Air heat capacity', 'kJ/kg/K') self.add_lineedit_set_to_grid(self.ui.p2_layout, 6, 'p2_in_T_0', 'Air temperature', 'K') self.add_lineedit_set_to_grid(self.ui.p2_layout, 7, 'p2_in_g', 'Gravity', 'm/s<sup>2</sup>') self.ui.p2_in_fire_shape = QComboBox() self.ui.p2_in_fire_shape.addItems(['Circular fire', 'Rectangular fire', 'Line fire']) self.ui.p2_layout.addWidget(self.ui.p2_in_fire_shape, 8, 0, 1, 3) self.ui.p2_in_fuel_type = QComboBox() self.ui.p2_in_fuel_type.addItems(['Natural gas (Zukoski)', 'Wood cribs', 'Gas, liquids and solids (Heskestad)']) self.ui.p2_layout.addWidget(self.ui.p2_in_fuel_type, 9, 0, 1, 3) self.ui.p2_layout.addWidget(QLabel('<b>Outputs</b>'), 10, 0, 1, 3) self.add_lineedit_set_to_grid(self.ui.p2_layout, 11, 'p2_out_Q_dot_star', 'Dimensionless HRR', '') self.ui.p2_out_Q_dot_star.setReadOnly(True) self.add_lineedit_set_to_grid(self.ui.p2_layout, 12, 'p2_out_Z_f', 'Flame height', 'm') self.ui.p2_out_Z_f.setReadOnly(True) # ============== # instantiate ui # ============== self.ui.p2_in_Q_dot_or_Q_dot_l.setToolTip( 'Total fire heat release rate (per unit length for line fire shape)') self.ui.p2_in_L_A_or_D.setToolTip('Fire longer dimension (diameter for circular fire shape)') self.ui.p2_in_L_B.setToolTip('Fire shorter dimension (only for rectangular fire shape)') self.ui.p2_out_Q_dot_star.setToolTip('Solved dimensionless heat release rate, double click to select') self.ui.p2_out_Z_f.setToolTip('Solved mean flame height, double click to select') # construct pixmaps that are used in this app self.dict_images_pixmap = dict(image_context=image_context, image_figure=image_figure, ) for k, v in self.dict_images_pixmap.items(): ba = QByteArray.fromBase64(v) self.dict_images_pixmap[k] = QtGui.QPixmap() self.dict_images_pixmap[k].loadFromData(ba) # set default values # todo self.change_fire_shape() # signal and slots self.ui.p2_in_fire_shape.currentIndexChanged.connect(self.change_fire_shape)
class MainWindow(QMainWindow): # pylint: disable=R0902 """Main window of application""" log = False trayIconMessageSignal = Signal(str, str, object) def __init__(self, parent=None, palette=None): super(MainWindow, self).__init__(parent) self.defaultPalette = palette self.parent = parent # Language Setup self.setLanguageInWidgets = SetLanguage() self.uiSetLanguage = UiSetLanguage(self) configLanguage(self) # initialize the gazillion variables self._initVars() # Widow Title self.appDirectory on _initVars() self.setWindowTitle(config.APPNAME + ": " + config.DESCRIPTION) self.setWindowIcon(QIcon(QPixmap(":/images/Itsue256x256.png"))) # Setup User Interface self._initMenu() self._initControls() self._initUI() self._initHelper() # Restore configuration elements self.configuration(action=config.Action.Restore) # self.setLanguage() # tray icon self.trayIcon = QSystemTrayIconWidget(self, self.windowIcon()) self.trayIcon.show() # for taskbar icon to work show must be called in __init__ self.show() # Must init after show call self.progressBar.initTaskbarButton() # tray Icon message self.trayIconMessageSignal.connect(self.trayIcon.showMessage) def _initVars(self): # # Where am I running from # # if getattr(sys, "frozen", False): if sys.pyside_uses_embedding: # Running in a pyinstaller bundle self.appDirectory = Path(os.path.dirname(__file__)) else: self.appDirectory = Path(os.path.realpath(__file__)) self.controlQueue = deque() self.jobsQueue = JobQueue(self, controlQueue=self.controlQueue) # Progress information setup self.progressBar = DualProgressBar(self, align=Qt.Horizontal) self.jobsLabel = QFormatLabel( Text.txt0085, init=[0, 0, 0, 0, 0], ) self.progress = Progress(self, self.progressBar, self.jobsLabel) self.jobsQueue.progress = self.progress self.progressSpin = QProgressIndicator(self) # Model view headers = tableHeaders() self.tableData = TableData(headerList=headers, dataList=[]) self.model = JobsTableModel(self.tableData, self.jobsQueue) self.proxyModel = TableProxyModel(self.model) self.jobsQueue.proxyModel = self.proxyModel # Preferences menu self.setPreferences = PreferencesDialogWidget(self) self.fileMenu = None self.helpMenu = None self.menuItems = None def _initMenu(self): # pylint: disable=too-many-statements menuBar = QMenuBar() self.menuItems = [] # File SubMenu self.fileMenu = QMenuWidget(Text.txt0020) exitIcon = self.style().standardIcon(QStyle.SP_DialogCloseButton) # Preferences actPreferences = QActionWidget( Text.txt0050, self, shortcut=Text.txt0026, statusTip=Text.txt0051, ) actPreferences.triggered.connect(self.setPreferences.getPreferences) # Exit application actExit = QActionWidget( exitIcon, Text.txt0021, self, shortcut=Text.txt0022, statusTip=Text.txt0023, ) actExit.triggered.connect(self.close) # Abort actAbort = QActionWidget(Text.txt0024, self, statusTip=Text.txt0025) actAbort.triggered.connect(abort) # Add actions to SubMenu self.fileMenu.addAction(actPreferences) self.fileMenu.addSeparator() self.fileMenu.addAction(actExit) self.fileMenu.addSeparator() self.fileMenu.addAction(actAbort) menuBar.addMenu(self.fileMenu) self.menuItems.append(self.fileMenu) self.menuItems.append(actPreferences) self.menuItems.append(actExit) self.menuItems.append(actAbort) # Help Menu actHelpContents = QActionWidget(Text.txt0061, self, textSuffix="...") actHelpContents.triggered.connect(lambda: _help(self.appDirectory, 0)) actHelpUsing = QActionWidget(Text.txt0062, self) actHelpUsing.triggered.connect(lambda: _help(self.appDirectory, 1)) actAbout = QActionWidget(Text.txt0063, self) actAbout.triggered.connect(self.about) actAboutQt = QActionWidget(Text.txt0064, self) actAboutQt.triggered.connect(self.aboutQt) self.helpMenu = QMenuWidget(Text.txt0060) self.helpMenu.addAction(actHelpContents) self.helpMenu.addAction(actHelpUsing) self.helpMenu.addSeparator() self.helpMenu.addAction(actAbout) self.helpMenu.addAction(actAboutQt) menuBar.addMenu(self.helpMenu) self.menuItems.append(self.helpMenu) self.menuItems.append(actHelpContents) self.menuItems.append(actHelpUsing) self.menuItems.append(actAbout) self.menuItems.append(actAboutQt) # Init status var statusBar = QStatusBar() statusBar.addPermanentWidget(VerticalLine()) statusBar.addPermanentWidget(self.jobsLabel) statusBar.addPermanentWidget(VerticalLine()) statusBar.addPermanentWidget(self.progressBar) statusBar.addPermanentWidget(self.progressSpin) self.setMenuBar(menuBar) self.setStatusBar(statusBar) def _initControls(self): """ Here the variables for widgets are declared and the setup for them is done """ # Widgets for tabs self.tableViewWidget = JobsTableViewWidget(self, self.proxyModel, self.controlQueue, _(Text.txt0130)) self.tableViewWidget.tableView.sortByColumn(0, Qt.AscendingOrder) self.renameWidget = RenameWidget(self) self.commandWidget = CommandWidget(self, self.proxyModel) self.jobsOutputWidget = JobsOutputWidget(self) self.errorOutputWidget = JobsOutputErrorsWidget(self) # historyWidget and logViewerWidget cannot have parent declared # They don't always display and create artifacts when not shown self.historyWidget = JobsHistoryViewWidget(self, groupTitle=_(Text.txt0130)) self.historyWidget.tableView.sortByColumn(0, Qt.DescendingOrder) self.logViewerWidget = LogViewerWidget() # Setup tabs for TabWidget self.tabs = TabWidget(self) tabsList = [] tabsList.append([ self.commandWidget, _(Text.txt0133), _(Text.txt0148), ]) tabsList.append([ self.tableViewWidget, _(Text.txt0140), _(Text.txt0144), ]) tabsList.append([ self.jobsOutputWidget, _(Text.txt0141), _(Text.txt0145), ]) tabsList.append([ self.errorOutputWidget, _(Text.txt0142), _(Text.txt0146), ]) tabsList.append([ self.renameWidget, _(Text.txt0143), _(Text.txt0147), ]) if config.data.get(config.ConfigKey.LogViewer): tabsList.append([ self.logViewerWidget, _(Text.txt0149), _(Text.txt0151), ]) else: self.logViewerWidget.tab = -1 self.logViewerWidget.tabWidget = self.tabs self.logViewerWidget.title = _(Text.txt0149) if config.data.get(config.ConfigKey.JobHistory): tabsList.append( [self.historyWidget, _(Text.txt0241), _(Text.txt0168)]) else: self.historyWidget.tab = -1 self.historyWidget.tabWidget = self.tabs self.historyWidget.title = _(Text.txt0241) self.tabs.addTabs(tabsList) def _initHelper(self): """ _initHelper setup signals, do any late binds and misc configuration """ # work in progress spin self.progressSpin.displayedWhenStopped = True self.progressSpin.color = checkColor( QColor(42, 130, 218), config.data.get(config.ConfigKey.DarkMode)) self.progressSpin.delay = 60 # Set output to contain output windows objects self.output = OutputWindows( self.commandWidget.outputWindow, self.jobsOutputWidget, self.errorOutputWidget, ) self.commandWidget.output = self.output self.tableViewWidget.output = self.output self.jobsQueue.output = self.output self.commandWidget.outputWindow.setReadOnly(True) self.jobsOutputWidget.setReadOnly(True) self.errorOutputWidget.setReadOnly(True) self.historyWidget.output.setReadOnly(True) self.jobsOutputWidget.textChanged.connect( self.commandWidget.resetButtonState) # Give commandWidget access to renameWidget self.commandWidget.rename = self.renameWidget # setup widgets setLanguage to SetLanguage change signal self.setLanguageInWidgets.addSlot(self.tableViewWidget.setLanguage) self.setLanguageInWidgets.addSlot(self.commandWidget.setLanguage) self.setLanguageInWidgets.addSlot(self.tabs.setLanguage) self.setLanguageInWidgets.addSlot(self.renameWidget.setLanguage) self.setLanguageInWidgets.addSlot(self.historyWidget.setLanguage) self.setLanguageInWidgets.addSlot(self.setPreferences.retranslateUi) # connect to tabs widget tab change Signal self.tabs.currentChanged.connect(tabChange) # connect to runJobs Start/Stop SigNal self.jobsQueue.runJobs.startSignal.connect( self.progressSpin.startAnimation) self.jobsQueue.runJobs.finishedSignal.connect( self.progressSpin.stopAnimation) # connect log viewer config.logViewer.connect(self.logViewerWidget.logMessage) # connect JobHistory and commandWidget self.historyWidget.pasteCommandSignal.connect( self.commandWidget.updateCommand) self.historyWidget.updateAlgorithmSignal.connect( self.commandWidget.updateAlgorithm) def _initUI(self): # Create Widgets widget = QWidget() layout = QVBoxLayout(widget) layout.addWidget(self.tabs) widget.setLayout(layout) self.setCentralWidget(widget) # # Events override # def closeEvent(self, event): """ Override QMainWindow.closeEvent Save configuration state before exit """ language = config.data.get(config.ConfigKey.Language) bAnswer = False title = _(Text.txt0080) leadQuestionMark = "¿" if language == "es" else "" if threading.activeCount() > 1: msg = _(Text.txt0089) + ". " + leadQuestionMark + _( Text.txt0090) + "?" else: msg = leadQuestionMark + _(Text.txt0081) + "?" bAnswer = yesNoDialog(self, msg, title) if bAnswer: self.configuration(action=config.Action.Save) event.accept() else: event.ignore() def moveEvent(self, event): # Update geometry includes position base64Geometry = self.saveGeometry().toBase64() b = base64Geometry.data() # b is a bytes string config.data.set(config.ConfigKey.Geometry, b) event.ignore() def resizeEvent(self, event): # Update geometry includes position base64Geometry = self.saveGeometry().toBase64() b = base64Geometry.data() # b is a bytes string config.data.set(config.ConfigKey.Geometry, b) event.ignore() def setVisible(self, visible): """ Override setVisible """ self.trayIcon.setMenuEnabled(visible) super().setVisible(visible) # @Slot(str) # def iconActivated(self, reason): # """Systray Icon""" # print("main is icon activated") # if reason == QSystemTrayIcon.Trigger: # pass # if reason == QSystemTrayIcon.DoubleClick: # pass # if reason == QSystemTrayIcon.MiddleClick: # pass # # Events override End # def configuration(self, action=None): """ Read and write configuration """ defaultFont = QFont() defaultFont.fromString(config.data.get(config.ConfigKey.SystemFont)) defaultFont.setPointSize(14) bLogging = False if action == config.Action.Reset: # Font self.setFont(defaultFont) self.setAppFont(defaultFont) # Logging self.enableLogging(bLogging) # Geometry self.setGeometry(0, 0, 1280, 720) centerWidget(self) elif action == config.Action.Restore: # Font if strFont := config.data.get(config.ConfigKey.Font): restoreFont = QFont() restoreFont.fromString(strFont) self.setFont(restoreFont) self.setAppFont(restoreFont) else: self.setFont(defaultFont) self.setAppFont(defaultFont) # Logging if bLogging := config.data.get(config.ConfigKey.Logging): self.enableLogging(bLogging) # Geometry if byteGeometry := config.data.get(config.ConfigKey.Geometry): self.restoreGeometry( QByteArray.fromBase64(QByteArray(byteGeometry)))
def icon(base64=None, icon=None): if not icon: icon = QPixmap() base64 = bytes(base64, encoding='utf-8') icon.loadFromData(QByteArray.fromBase64(base64)) return QIcon(icon)