class DownloadWindow(QDialog): def __init__(self, parent: Optional[QWidget] = None, url: str = '') -> None: super().__init__(parent, ) if parent: self.setWindowTitle('Download Mod') else: self.setWindowTitle(getTitleString('Download Mod')) self.setAttribute(Qt.WA_DeleteOnClose) mainLayout = QVBoxLayout(self) self.signals = DownloadWindowEvents(self) # URL input gbUrl = QGroupBox('Mod URL') gbUrlLayout = QVBoxLayout() gbUrl.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.url = QLineEdit() self.url.setPlaceholderText( 'https://www.nexusmods.com/witcher3/mods/...') self.url.setText(url) self.url.textChanged.connect(lambda: self.validateUrl(self.url.text())) gbUrlLayout.addWidget(self.url) self.urlInfo = QLabel('🌐') self.urlInfo.setContentsMargins(4, 4, 4, 4) self.urlInfo.setMinimumHeight(36) self.urlInfo.setWordWrap(True) gbUrlLayout.addWidget(self.urlInfo) gbUrl.setLayout(gbUrlLayout) mainLayout.addWidget(gbUrl) # File selection gbFiles = QGroupBox('Mod Files') gbFilesLayout = QVBoxLayout() gbFiles.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.files = QTableWidget(0, 4) self.files.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel) self.files.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) self.files.setContextMenuPolicy(Qt.CustomContextMenu) self.files.setSelectionMode(QAbstractItemView.ExtendedSelection) self.files.setSelectionBehavior(QAbstractItemView.SelectRows) self.files.setWordWrap(False) self.files.setSortingEnabled(True) self.files.setFocusPolicy(Qt.StrongFocus) self.files.verticalHeader().hide() self.files.setSortingEnabled(True) self.files.sortByColumn(2, Qt.DescendingOrder) self.files.verticalHeader().setVisible(False) self.files.verticalHeader().setDefaultSectionSize(25) self.files.horizontalHeader().setHighlightSections(False) self.files.horizontalHeader().setStretchLastSection(True) self.files.setHorizontalHeaderLabels( ['File Name', 'Version', 'Upload Date', 'Description']) self.files.setEditTriggers(QAbstractItemView.NoEditTriggers) self.files.verticalScrollBar().valueChanged.connect( lambda: self.files.clearFocus()) self.files.itemSelectionChanged.connect(lambda: self.validateFiles()) self.files.setDisabled(True) self.files.setStyleSheet(''' QTableView { gridline-color: rgba(255,255,255,1); } QTableView::item { padding: 5px; margin: 1px 0; } QTableView::item:!selected:hover { background-color: rgb(217, 235, 249); padding: 0; } ''') gbFilesLayout.addWidget(self.files) _mouseMoveEvent = self.files.mouseMoveEvent self.files.hoverIndexRow = -1 def mouseMoveEvent(event: QMouseEvent) -> None: self.files.hoverIndexRow = self.files.indexAt(event.pos()).row() _mouseMoveEvent(event) self.files.mouseMoveEvent = mouseMoveEvent # type: ignore self.files.setItemDelegate(ModListItemDelegate(self.files)) self.files.setMouseTracking(True) gbFiles.setLayout(gbFilesLayout) mainLayout.addWidget(gbFiles) # Actions actionsLayout = QHBoxLayout() actionsLayout.setAlignment(Qt.AlignRight) self.download = QPushButton('Download', self) self.download.clicked.connect(lambda: self.downloadEvent()) self.download.setAutoDefault(True) self.download.setDefault(True) self.download.setDisabled(True) actionsLayout.addWidget(self.download) cancel = QPushButton('Cancel', self) cancel.clicked.connect(self.cancelEvent) actionsLayout.addWidget(cancel) mainLayout.addLayout(actionsLayout) # Setup self.setMinimumSize(QSize(420, 420)) self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.resize(QSize(720, 420)) self.finished.connect( lambda: self.validateUrl.cancel()) # type: ignore self.finished.connect( lambda: self.downloadEvent.cancel()) # type: ignore self.modId = 0 self.validateUrl(self.url.text()) def cancelEvent(self) -> None: self.close() @debounce(200, cancel_running=True) async def validateUrl(self, url: str) -> bool: self.download.setDisabled(True) self.files.setDisabled(True) self.files.clearSelection() self.files.clearFocus() self.files.clearContents() self.files.setRowCount(0) self.files.setSortingEnabled(False) self.url.setStyleSheet('') self.modId = 0 if not url: self.urlInfo.setText(''' <font color="#888">Please enter a valid mod url.</font> ''') return False modId = getModId(url) if not modId: self.files.setDisabled(True) self.url.setStyleSheet(''' *{ border: 1px solid #B22222; padding: 1px 0px; } ''') self.urlInfo.setText(''' <font color="#888">Please enter a valid mod url.</font> ''') return False self.urlInfo.setText('🌐') try: filesResponse = await getModFiles(modId) except (RequestError, ResponseError, Exception) as e: self.url.setStyleSheet(''' *{ border: 1px solid #B22222; padding: 1px 0px; } ''') self.urlInfo.setText(f''' <font color="#888">Could not get mod files: {e}.</font> ''') return False try: files = filesResponse['files'] if not len(files): self.urlInfo.setText(f''' <font color="#888">Mod "{modId}" has no files!</font> ''') return False self.files.setRowCount(len(files)) for i in range(len(files)): file = files[i] fileid = int(file['file_id']) name = str(file['name']) version = str(file['version']) _uploadtime = dateparser.parse(file['uploaded_time']) uploadtime = _uploadtime.astimezone(tz=None).strftime( '%Y-%m-%d %H:%M:%S') if _uploadtime else '?' description = html.unescape(str(file['description'])) nameItem = QTableWidgetItem(name) nameItem.setToolTip(name) nameItem.setData(Qt.UserRole, fileid) self.files.setItem(i, 0, nameItem) versionItem = QTableWidgetItem(version) versionItem.setToolTip(version) self.files.setItem(i, 1, versionItem) uploadtimeItem = QTableWidgetItem(uploadtime) uploadtimeItem.setToolTip(uploadtime) self.files.setItem(i, 2, uploadtimeItem) descriptionItem = QTableWidgetItem(description) descriptionItem.setToolTip(description) self.files.setItem(i, 3, descriptionItem) except KeyError as e: logger.exception( f'Could not find key "{str(e)}" in mod files response') self.urlInfo.setText(f''' <font color="#888">Could not find key "{str(e)}" in mod files response.</font> ''') return False self.urlInfo.setText(f''' <font color="#888">Found {len(files)} available files.</font> ''') self.files.resizeColumnsToContents() self.files.setDisabled(False) self.files.setSortingEnabled(True) self.modId = modId return True def validateFiles(self) -> bool: selection = self.files.selectionModel().selectedRows() if len(selection) > 0: self.download.setText(f'Download {len(selection)} mods') self.download.setDisabled(False) return True return False @debounce(25, cancel_running=True) async def downloadEvent(self) -> None: self.download.setDisabled(True) self.url.setDisabled(True) selection = self.files.selectionModel().selectedRows() files = [ self.files.item(index.row(), 0).data(Qt.UserRole) for index in selection ] self.files.setDisabled(True) try: urls = await asyncio.gather( *[getModFileUrls(self.modId, file) for file in files], loop=asyncio.get_running_loop()) except (RequestError, ResponseError, Exception) as e: self.url.setStyleSheet(''' *{ border: 1px solid #B22222; padding: 1px 0px; } ''') self.urlInfo.setText(f''' <font color="#888">Could not download mod files: {e}.</font> ''') return try: self.signals.download.emit([url[0]['URI'] for url in urls]) except KeyError as e: logger.exception( f'Could not find key "{str(e)}" in file download response') self.urlInfo.setText(f''' <font color="#888">Could not find key "{str(e)}" in file download response.</font> ''') return self.close()
class TableWidget(QWidget): @property def columns(self): return self._columns @columns.setter def columns(self, columns): self._columns = columns self.table.setHorizontalHeaderLabels(columns) self.table.resizeColumnsToContents() def __init__(self, columns, parent=None, callback=None): super().__init__(parent) self.callback = callback self.table = QTableWidget(0, len(columns), self) self.columns = columns self.table.setMinimumSize(400, 300) self.table.setShowGrid(True) self.hh = self.table.horizontalHeader() self.hh.setStretchLastSection(False) self.vh = self.table.verticalHeader() layout = QBoxLayout( QBoxLayout.Direction(QBoxLayout.LeftToRight | QBoxLayout.TopToBottom), self) layout.addWidget(self.table) self.setLayout(layout) # self.setSizePolicy(QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum, QSizePolicy.DefaultType)) self.callback = callback if self.callback: #self.table.cellEntered.connect(self.enterProcessor) #self.vh.activated.connect(self.enterProcessor) #self.vh.selected.connect(self.enterProcessor) #self.table.clicked.connect(self.enterProcessor) self.table.itemSelectionChanged.connect(self.enterProcessor) def removeRow(self, rowNo): for i in range(len(self.systemColumnsDefs)): try: self.table.cellWidget(rowNo, i).disconnect() except Exception as ex: print("DAMN!", ex) self.table.removeCellWidget(rowNo, i) self.table.removeRow(rowNo) def appendRow(self, i, row, isN=False): newRowNo = i + 1 self.table.insertRow(newRowNo) for j, cell in enumerate(row): w = QLabel() w.setText(str(cell)) self.table.setCellWidget(newRowNo, j, w) def clear(self): self.table.clearSelection() # self.table.disconnect() self.table.clearContents() self.table.setRowCount(0) def enterProcessor(self): #rowNo = idx.row() rowNo = self.table.currentIndex().row() self.callback(self, rowNo)
class NGL_HKLViewer(QWidget): def __init__(self, parent=None): super(NGL_HKLViewer, self).__init__(parent) self.verbose = 0 self.UseOSbrowser = False self.jscriptfname = "" self.devmode = False for e in sys.argv: if "verbose" in e: self.verbose = e.split("verbose=")[1] if "UseOSbrowser" in e: self.UseOSbrowser = e.split("UseOSbrowser=")[1] if "jscriptfname" in e: self.jscriptfname = e.split("jscriptfname=")[1] if "devmode" in e: self.devmode = True self.zmq_context = None self.bufsize = 20000 self.originalPalette = QApplication.palette() self.openFileNameButton = QPushButton("Load reflection file") self.openFileNameButton.setDefault(True) self.openFileNameButton.clicked.connect(self.OpenReflectionsFile) self.debugbutton = QPushButton("Debug") self.debugbutton.clicked.connect(self.DebugInteractively) self.settingsbtn = QPushButton("Settings") self.settingsbtn.clicked.connect(self.SettingsDialog) self.mousemoveslider = QSlider(Qt.Horizontal) self.mousemoveslider.setMinimum(0) self.mousemoveslider.setMaximum(300) self.mousemoveslider.setValue(0) self.mousemoveslider.sliderReleased.connect( self.onFinalMouseSensitivity) self.mousemoveslider.valueChanged.connect(self.onMouseSensitivity) self.mousesensitxtbox = QLineEdit('') self.mousesensitxtbox.setReadOnly(True) self.fontspinBox = QDoubleSpinBox() self.fontspinBox.setSingleStep(1) self.fontspinBox.setRange(4, 50) self.font = QFont() self.font.setFamily(self.font.defaultFamily()) self.fontspinBox.setValue(self.font.pointSize()) #self.fontspinBox.setValue(self.font.pixelSize()) self.fontspinBox.valueChanged.connect(self.onFontsizeChanged) self.Fontsize_labeltxt = QLabel() self.Fontsize_labeltxt.setText("Font size:") self.cameraPerspectCheckBox = QCheckBox() self.cameraPerspectCheckBox.setText("Perspective camera") self.cameraPerspectCheckBox.clicked.connect(self.onCameraPerspect) self.cameraPerspectCheckBox.setCheckState(Qt.Unchecked) self.settingsform = SettingsForm(self) self.MillerComboBox = QComboBox() self.MillerComboBox.activated.connect(self.onMillerComboSelchange) #self.MillerComboBox.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.MillerLabel = QLabel() self.MillerLabel.setText("Selected HKL Scene") self.HKLnameedit = QLineEdit('') self.HKLnameedit.setReadOnly(True) self.textInfo = QTextEdit() self.textInfo.setLineWrapMode(QTextEdit.NoWrap) self.textInfo.setReadOnly(True) labels = [ "Label", "Type", "no. of HKLs", "Span of HKLs", "Min Max data", "Min Max sigmas", "d_min, d_max", "Symmetry unique", "Anomalous" ] self.millertable = QTableWidget(0, len(labels)) self.millertable.setHorizontalHeaderLabels(labels) self.millertable.horizontalHeader().setDefaultAlignment(Qt.AlignLeft) # don't allow editing this table self.millertable.setEditTriggers(QTableWidget.NoEditTriggers) self.createExpansionBox() self.createFileInfoBox() self.CreateSliceTabs() self.createRadiiScaleGroupBox() self.createBinsBox() self.CreateFunctionTabs() mainLayout = QGridLayout() mainLayout.addWidget(self.FileInfoBox, 0, 0) mainLayout.addWidget(self.MillerLabel, 1, 0) mainLayout.addWidget(self.MillerComboBox, 2, 0) mainLayout.addWidget(self.functionTabWidget, 3, 0) mainLayout.addWidget(self.settingsbtn, 4, 0, 1, 1) #import code, traceback; code.interact(local=locals(), banner="".join( traceback.format_stack(limit=10) ) ) if self.UseOSbrowser == False: self.BrowserBox = QWebEngineView() mainLayout.addWidget(self.BrowserBox, 0, 1, 5, 3) self.BrowserBox.setUrl("https://cctbx.github.io/") #self.BrowserBox.setUrl("https://webglreport.com/") #self.BrowserBox.loadFinished.connect(self.onLoadFinished) mainLayout.setColumnStretch(2, 1) mainLayout.setRowStretch(0, 1) mainLayout.setRowStretch(1, 0) mainLayout.setRowStretch(2, 1) mainLayout.setRowStretch(3, 1) mainLayout.setColumnStretch(4, 0) self.setLayout(mainLayout) self.setWindowTitle("HKL-Viewer") self.cctbxproc = None self.LaunchCCTBXPython() self.out = None self.err = None self.comboviewwidth = 0 self.hklscenes_arrays = [] self.array_infotpls = [] self.matching_arrays = [] self.bin_infotpls = None self.bin_opacities = None self.html_url = "" self.spacegroups = [] self.info = [] self.infostr = "" self.fileisvalid = False self.NewFileLoaded = False self.NewHKLscenes = False self.updatingNbins = False self.binstableitemchanges = False self.show() def SettingsDialog(self): self.settingsform.show() def update(self): if self.cctbxproc: if self.cctbxproc.stdout: print(self.cctbxproc.stdout.read().decode("utf-8")) if self.cctbxproc.stderr: print(self.cctbxproc.stderr.read().decode("utf-8")) if self.out: print(self.out.decode("utf-8")) if self.err: print(self.err.decode("utf-8")) if self.zmq_context: try: msg = self.socket.recv( flags=zmq.NOBLOCK ) #To empty the socket from previous messages msgstr = msg.decode() self.infodict = eval(msgstr) #print("received from cctbx: " + str(self.infodict)) if self.infodict: if self.infodict.get("hklscenes_arrays"): self.hklscenes_arrays = self.infodict.get( "hklscenes_arrays", []) if self.infodict.get("array_infotpls"): self.array_infotpls = self.infodict.get( "array_infotpls", []) if self.infodict.get("bin_data_label"): self.BinDataComboBox.setCurrentText( self.infodict["bin_data_label"]) if self.infodict.get("bin_infotpls"): self.bin_infotpls = self.infodict["bin_infotpls"] self.nbins = len(self.bin_infotpls) self.updatingNbins = True self.Nbins_spinBox.setValue(self.nbins) self.updatingNbins = False self.binstable.clearContents() self.binstable.setRowCount(self.nbins) for row, bin_infotpl in enumerate(self.bin_infotpls): for col, elm in enumerate(bin_infotpl): # only allow changing the last column with opacity values if col != 3: item = QTableWidgetItem(str(elm)) else: item = QTableWidgetItem() item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) item.setCheckState(Qt.Checked) item.setFlags(item.flags() ^ Qt.ItemIsEditable) self.binstable.setItem(row, col, item) if self.bin_opacities: self.update_table_opacities() if self.infodict.get("bin_opacities"): self.bin_opacities = self.infodict["bin_opacities"] if self.binstable.rowCount() > 0: self.update_table_opacities() if self.infodict.get("html_url"): self.html_url = self.infodict["html_url"] if self.UseOSbrowser == False: self.BrowserBox.setUrl(self.html_url) # workaround for background colour bug in chromium # https://bugreports.qt.io/browse/QTBUG-41960 self.BrowserBox.page().setBackgroundColor( QColor(100, 100, 100, 1.0)) if self.infodict.get("spacegroups"): self.spacegroups = self.infodict.get("spacegroups", []) self.SpaceGroupComboBox.clear() self.SpaceGroupComboBox.addItems(self.spacegroups) if self.infodict.get("merge_data"): self.mergedata = self.infodict["merge_data"] currentinfostr = "" if self.infodict.get("info"): currentinfostr = self.infodict.get("info", []) if self.infodict.get("NewFileLoaded"): self.NewFileLoaded = self.infodict.get( "NewFileLoaded", False) if self.infodict.get("NewHKLscenes"): self.NewHKLscenes = self.infodict.get( "NewHKLscenes", False) self.fileisvalid = True #print("ngl_hkl_infodict: " + str(ngl_hkl_infodict)) if currentinfostr: #print(currentinfostr) self.infostr += currentinfostr + "\n" # display no more than self.bufsize bytes of text self.infostr = self.infostr[-self.bufsize:] self.textInfo.setPlainText(self.infostr) self.textInfo.verticalScrollBar().setValue( self.textInfo.verticalScrollBar().maximum()) if self.NewFileLoaded and self.NewHKLscenes: #if self.mergedata == True : val = Qt.CheckState.Checked #if self.mergedata == None : val = Qt.CheckState.PartiallyChecked #if self.mergedata == False : val = Qt.CheckState.Unchecked #self.mergecheckbox.setCheckState(val ) #print("got hklscenes: " + str(self.hklscenes_arrays)) self.MillerComboBox.clear() self.MillerComboBox.addItems( [e[3] for e in self.hklscenes_arrays]) self.MillerComboBox.setCurrentIndex( -1) # unselect the first item in the list self.comboviewwidth = 0 for e in self.hklscenes_arrays: self.comboviewwidth = max( self.comboviewwidth, self.MillerComboBox.fontMetrics().width(e[3])) self.MillerComboBox.view().setMinimumWidth( self.comboviewwidth) self.millertable.clearContents() self.millertable.setRowCount(len( self.hklscenes_arrays)) for n, millarr in enumerate(self.array_infotpls): for m, elm in enumerate(millarr): self.millertable.setItem( n, m, QTableWidgetItem(str(elm))) self.functionTabWidget.setDisabled(True) self.NewFileLoaded = False if self.NewHKLscenes: self.BinDataComboBox.clear() self.BinDataComboBox.addItems( ["Resolution"] + [e[3] for e in self.hklscenes_arrays]) self.BinDataComboBox.view().setMinimumWidth( self.comboviewwidth) #self.BinDataComboBox.setCurrentIndex(-1) # unselect the first item in the list self.NewHKLscenes = False except Exception as e: errmsg = str(e) if "Resource temporarily unavailable" not in errmsg: print(errmsg + traceback.format_exc(limit=10)) pass def onFinalMouseSensitivity(self): val = self.mousemoveslider.value() / 100.0 self.NGL_HKL_command( 'NGL_HKLviewer.viewer.NGL.mouse_sensitivity = %f' % val) def onMouseSensitivity(self): val = self.mousemoveslider.value() / 100.0 self.mousesensitxtbox.setText("%2.2f" % val) def onFontsizeChanged(self, val): font = app.font() font.setPointSize(val) app.setFont(font) self.settingsform.setFixedSize(self.settingsform.sizeHint()) def onCameraPerspect(self, val): if self.cameraPerspectCheckBox.isChecked(): self.NGL_HKL_command("NGL_HKLviewer.camera_type = perspective") else: self.NGL_HKL_command("NGL_HKLviewer.camera_type = orthographic") def MergeData(self): if self.mergecheckbox.checkState() == Qt.CheckState.Checked: self.NGL_HKL_command('NGL_HKLviewer.mergedata = True') if self.mergecheckbox.checkState() == Qt.CheckState.PartiallyChecked: self.NGL_HKL_command('NGL_HKLviewer.mergedata = None') if self.mergecheckbox.checkState() == Qt.CheckState.Unchecked: self.NGL_HKL_command('NGL_HKLviewer.mergedata = False') def ExpandToP1(self): if self.expandP1checkbox.isChecked(): self.NGL_HKL_command('NGL_HKLviewer.viewer.expand_to_p1 = True') else: self.NGL_HKL_command('NGL_HKLviewer.viewer.expand_to_p1 = False') def ExpandAnomalous(self): if self.expandAnomalouscheckbox.isChecked(): self.NGL_HKL_command( 'NGL_HKLviewer.viewer.expand_anomalous = True') else: self.NGL_HKL_command( 'NGL_HKLviewer.viewer.expand_anomalous = False') def showSysAbsent(self): if self.sysabsentcheckbox.isChecked(): self.NGL_HKL_command( 'NGL_HKLviewer.viewer.show_systematic_absences = True') else: self.NGL_HKL_command( 'NGL_HKLviewer.viewer.show_systematic_absences = False') def showMissing(self): if self.missingcheckbox.isChecked(): self.NGL_HKL_command('NGL_HKLviewer.viewer.show_missing = True') else: self.NGL_HKL_command('NGL_HKLviewer.viewer.show_missing = False') def showOnlyMissing(self): if self.onlymissingcheckbox.isChecked(): self.NGL_HKL_command( 'NGL_HKLviewer.viewer.show_only_missing = True') else: self.NGL_HKL_command( 'NGL_HKLviewer.viewer.show_only_missing = False') def showSlice(self): if self.showslicecheckbox.isChecked(): self.NGL_HKL_command('NGL_HKLviewer.viewer.slice_mode = True') if self.expandP1checkbox.isChecked(): self.NGL_HKL_command("""NGL_HKLviewer.viewer { expand_to_p1 = True inbrowser = False } """) if self.expandAnomalouscheckbox.isChecked(): self.NGL_HKL_command("""NGL_HKLviewer.viewer { expand_anomalous = True inbrowser = False } """) else: self.NGL_HKL_command("""NGL_HKLviewer.viewer { slice_mode = False inbrowser = True } """) def onSliceComboSelchange(self, i): rmin = self.array_infotpls[self.MillerComboBox.currentIndex()][3][0][i] rmax = self.array_infotpls[self.MillerComboBox.currentIndex()][3][1][i] self.sliceindexspinBox.setRange(rmin, rmax) self.NGL_HKL_command("NGL_HKLviewer.viewer.slice_axis = %s" % self.sliceaxis[i]) def onSliceIndexChanged(self, val): self.sliceindex = val self.NGL_HKL_command("NGL_HKLviewer.viewer.slice_index = %d" % self.sliceindex) def onBindataComboSelchange(self, i): if self.BinDataComboBox.currentText(): if self.BinDataComboBox.currentIndex() > 0: bin_scene_label = str(self.BinDataComboBox.currentIndex() - 1) else: bin_scene_label = "Resolution" self.NGL_HKL_command("NGL_HKLviewer.bin_scene_label = %s" % bin_scene_label) def update_table_opacities(self, allalpha=None): bin_opacitieslst = eval(self.bin_opacities) self.binstable_isready = False for binopacity in bin_opacitieslst: if not allalpha: alpha = float(binopacity.split(",")[0]) else: alpha = allalpha bin = int(binopacity.split(",")[1]) item = QTableWidgetItem() item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) if alpha < 0.5: item.setCheckState(Qt.Unchecked) else: item.setCheckState(Qt.Checked) item.setFlags(item.flags() ^ Qt.ItemIsEditable) self.binstable.setItem(bin, 3, item) self.binstable_isready = True def SetOpaqueAll(self): if self.binstableitemchanges: return bin_opacitieslst = eval(self.bin_opacities) nbins = len(bin_opacitieslst) sum = 0 for binopacity in bin_opacitieslst: sum += float(binopacity.split(",")[0]) if sum >= nbins: self.OpaqueAllCheckbox.setCheckState(Qt.Checked) if sum == 0: self.OpaqueAllCheckbox.setCheckState(Qt.Unchecked) if sum > 0.0 and sum < nbins: self.OpaqueAllCheckbox.setCheckState(Qt.PartiallyChecked) def onBinsTableItemChanged(self, item): row = item.row() column = item.column() try: if item.checkState() == Qt.Unchecked: newval = 0 else: newval = 1.0 if column == 3 and self.binstable_isready: # changing opacity assert (newval <= 1.0 and newval >= 0.0) bin_opacitieslst = eval(self.bin_opacities) bin_opacitieslst[row] = str(newval) + ', ' + str(row) self.bin_opacities = str(bin_opacitieslst) self.SetOpaqueAll() self.NGL_HKL_command( 'NGL_HKLviewer.viewer.NGL.bin_opacities = "%s"' % self.bin_opacities) except Exception as e: print(str(e)) #self.binstable.currentItem().setText( self.currentSelectedBinsTableVal) def onBinsTableItemSelectionChanged(self): row = self.binstable.currentItem().row() column = self.binstable.currentItem().column() self.currentSelectedBinsTableVal = self.binstable.currentItem().text() #print( "in itemSelectionChanged " + self.currentSelectedBinsTableVal) def onOpaqueAll(self): self.binstableitemchanges = True bin_opacitieslst = eval(self.bin_opacities) nbins = len(bin_opacitieslst) bin_opacitieslst = [] self.binstable_isready = False if self.OpaqueAllCheckbox.isChecked(): for i in range(nbins): bin_opacitieslst.append("1.0, %d" % i) else: for i in range(nbins): bin_opacitieslst.append("0.0, %d" % i) self.bin_opacities = str(bin_opacitieslst) self.NGL_HKL_command('NGL_HKLviewer.viewer.NGL.bin_opacities = "%s"' % self.bin_opacities) self.binstableitemchanges = False self.binstable_isready = True """ def onLoadFinished(self, val): pass #print("web page finished loading now") def onBinsTableitemActivated(self, item): row = item.row() column = item.column() currentval = item.text() #print( "in itemActivated " + currentval) def onBinsTableCellentered(self, row, col): pass #print( "in Cellentered " + self.binstable.currentItem().text() ) def onBinsTableCellPressed(self, row, col): pass #print( "in CellPressed " + self.binstable.currentItem().text() ) """ def onNbinsChanged(self, val): self.nbins = val if not self.updatingNbins: # avoid possible endless loop to cctbx self.NGL_HKL_command("NGL_HKLviewer.nbins = %d" % self.nbins) def onRadiiScaleChanged(self, val): self.radii_scale = val self.NGL_HKL_command(""" NGL_HKLviewer.viewer { nth_power_scale_radii = %f scale = %f } """ % (self.nth_power_scale, self.radii_scale)) def onPowerScaleChanged(self, val): self.nth_power_scale = val self.NGL_HKL_command(""" NGL_HKLviewer.viewer { nth_power_scale_radii = %f scale = %f } """ % (self.nth_power_scale, self.radii_scale)) def onManualPowerScale(self): if self.ManualPowerScalecheckbox.isChecked(): self.NGL_HKL_command( 'NGL_HKLviewer.viewer.nth_power_scale_radii = %f' % self.nth_power_scale) self.power_scale_spinBox.setEnabled(True) else: self.NGL_HKL_command( 'NGL_HKLviewer.viewer.nth_power_scale_radii = -1.0') self.power_scale_spinBox.setEnabled(False) self.nth_power_scale = -1.0 def OpenReflectionsFile(self): options = QFileDialog.Options() fileName, filtr = QFileDialog.getOpenFileName( self, "Load reflections file", "", "All Files (*);;MTZ Files (*.mtz);;CIF (*.cif)", "", options) if fileName: self.HKLnameedit.setText(fileName) #self.infostr = "" self.textInfo.setPlainText("") self.fileisvalid = False self.NGL_HKL_command('NGL_HKLviewer.filename = "%s"' % fileName) self.MillerComboBox.clear() self.BinDataComboBox.clear() def createExpansionBox(self): self.SpaceGroupComboBox = QComboBox() self.SpaceGroupComboBox.activated.connect(self.SpacegroupSelchange) self.SpacegroupLabel = QLabel() self.SpacegroupLabel.setText("Space Subgroups") self.mergecheckbox = QCheckBox() self.mergecheckbox.setText("Merge data") #self.mergecheckbox.setTristate (True) self.mergecheckbox.clicked.connect(self.MergeData) self.expandP1checkbox = QCheckBox() self.expandP1checkbox.setText("Expand to P1") self.expandP1checkbox.clicked.connect(self.ExpandToP1) self.expandAnomalouscheckbox = QCheckBox() self.expandAnomalouscheckbox.setText("Show Friedel pairs") self.expandAnomalouscheckbox.clicked.connect(self.ExpandAnomalous) self.sysabsentcheckbox = QCheckBox() self.sysabsentcheckbox.setText("Show Systematic Absences") self.sysabsentcheckbox.clicked.connect(self.showSysAbsent) self.missingcheckbox = QCheckBox() self.missingcheckbox.setText("Show Missing") self.missingcheckbox.clicked.connect(self.showMissing) self.onlymissingcheckbox = QCheckBox() self.onlymissingcheckbox.setText("Only Show Missing") self.onlymissingcheckbox.clicked.connect(self.showOnlyMissing) self.ExpansionBox = QGroupBox("Expansions") layout = QGridLayout() layout.addWidget(self.SpacegroupLabel, 0, 0) layout.addWidget(self.SpaceGroupComboBox, 0, 1) #layout.addWidget(self.mergecheckbox, 1, 0) layout.addWidget(self.expandP1checkbox, 1, 0) layout.addWidget(self.expandAnomalouscheckbox, 1, 1) layout.addWidget(self.sysabsentcheckbox, 2, 0) layout.addWidget(self.missingcheckbox, 3, 0) layout.addWidget(self.onlymissingcheckbox, 3, 1) layout.setRowStretch(0, 0) layout.setRowStretch(1, 0) layout.setRowStretch(2, 0) layout.setRowStretch(3, 1) self.ExpansionBox.setLayout(layout) def CreateSliceTabs(self): self.showslicecheckbox = QCheckBox() self.showslicecheckbox.setText("Show Slice") self.showslicecheckbox.clicked.connect(self.showSlice) self.sliceindexspinBox = QDoubleSpinBox() self.sliceindex = 0 self.sliceindexspinBox.setValue(self.sliceindex) self.sliceindexspinBox.setDecimals(0) self.sliceindexspinBox.setSingleStep(1) self.sliceindexspinBox.setRange(0, 20) self.sliceindexspinBox.valueChanged.connect(self.onSliceIndexChanged) self.SliceLabelComboBox = QComboBox() self.SliceLabelComboBox.activated.connect(self.onSliceComboSelchange) self.sliceaxis = ["h", "k", "l"] self.SliceLabelComboBox.addItems(self.sliceaxis) self.sliceTabWidget = QTabWidget() tab1 = QWidget() layout1 = QGridLayout() layout1.addWidget(self.showslicecheckbox, 0, 0, 1, 1) layout1.addWidget(self.SliceLabelComboBox, 0, 1, 1, 1) layout1.addWidget(self.sliceindexspinBox, 0, 2, 1, 1) tab1.setLayout(layout1) tab2 = QWidget() layout2 = QGridLayout() self.hvec_spinBox = QDoubleSpinBox(self.sliceTabWidget) self.hvecval = 2.0 self.hvec_spinBox.setValue(self.hvecval) self.hvec_spinBox.setDecimals(2) self.hvec_spinBox.setSingleStep(0.5) self.hvec_spinBox.setRange(-100.0, 10.0) self.hvec_spinBox.valueChanged.connect(self.onHvecChanged) self.hvec_Label = QLabel() self.hvec_Label.setText("H") layout2.addWidget(self.hvec_Label, 0, 0, 1, 1) layout2.addWidget(self.hvec_spinBox, 0, 1, 1, 1) self.kvec_spinBox = QDoubleSpinBox(self.sliceTabWidget) self.kvecval = 0.0 self.kvec_spinBox.setValue(self.kvecval) self.kvec_spinBox.setDecimals(2) self.kvec_spinBox.setSingleStep(0.5) self.kvec_spinBox.setRange(-100.0, 100.0) self.kvec_spinBox.valueChanged.connect(self.onKvecChanged) self.kvec_Label = QLabel() self.kvec_Label.setText("K") layout2.addWidget(self.kvec_Label, 1, 0, 1, 1) layout2.addWidget(self.kvec_spinBox, 1, 1, 1, 1) self.lvec_spinBox = QDoubleSpinBox(self.sliceTabWidget) self.lvecval = 0.0 self.lvec_spinBox.setValue(self.lvecval) self.lvec_spinBox.setDecimals(2) self.lvec_spinBox.setSingleStep(0.5) self.lvec_spinBox.setRange(-100.0, 100.0) self.lvec_spinBox.valueChanged.connect(self.onLvecChanged) self.lvec_Label = QLabel() self.lvec_Label.setText("L") layout2.addWidget(self.lvec_Label, 2, 0, 1, 1) layout2.addWidget(self.lvec_spinBox, 2, 1, 1, 1) self.hkldist_spinBox = QDoubleSpinBox(self.sliceTabWidget) self.hkldistval = 0.0 self.hkldist_spinBox.setValue(self.hkldistval) self.hkldist_spinBox.setDecimals(2) self.hkldist_spinBox.setSingleStep(0.5) self.hkldist_spinBox.setRange(-100.0, 100.0) self.hkldist_spinBox.valueChanged.connect(self.onHKLdistChanged) self.hkldist_Label = QLabel() self.hkldist_Label.setText("Distance from Origin") layout2.addWidget(self.hkldist_Label, 3, 0, 1, 1) layout2.addWidget(self.hkldist_spinBox, 3, 1, 1, 1) self.clipwidth_spinBox = QDoubleSpinBox(self.sliceTabWidget) self.clipwidthval = 0.5 self.clipwidth_spinBox.setValue(self.clipwidthval) self.clipwidth_spinBox.setDecimals(2) self.clipwidth_spinBox.setSingleStep(0.05) self.clipwidth_spinBox.setRange(0.0, 100.0) self.clipwidth_spinBox.valueChanged.connect(self.onClipwidthChanged) self.clipwidth_Label = QLabel() self.clipwidth_Label.setText("Clip Plane Width") layout2.addWidget(self.clipwidth_Label, 4, 0, 1, 1) layout2.addWidget(self.clipwidth_spinBox, 4, 1, 1, 1) self.ClipBox = QGroupBox("Normal Vector to Clip Plane") self.ClipBox.setLayout(layout2) layout3 = QGridLayout() self.ClipPlaneChkBox = QCheckBox(self.sliceTabWidget) self.ClipPlaneChkBox.setText( "Use clip plane normal to HKL vector pointing out") self.ClipPlaneChkBox.clicked.connect(self.onClipPlaneChkBox) layout3.addWidget(self.ClipPlaneChkBox, 0, 0) layout3.addWidget(self.ClipBox, 1, 0) tab2.setLayout(layout3) self.sliceTabWidget.addTab(tab1, "Explicit Slicing") self.sliceTabWidget.addTab(tab2, "Clip Plane Slicing") self.ClipBox.setDisabled(True) def onClipPlaneChkBox(self): if self.ClipPlaneChkBox.isChecked(): self.ClipBox.setDisabled(False) philstr = """NGL_HKLviewer.normal_clip_plane { h = %s k = %s l = %s hkldist = %s clipwidth = %s } NGL_HKLviewer.viewer.NGL.fixorientation = %s """ %(self.hvecval, self.kvecval, self.lvecval, self.hkldistval, self.clipwidthval, \ str(self.fixedorientcheckbox.isChecked()) ) self.NGL_HKL_command(philstr) else: self.ClipBox.setDisabled(True) self.NGL_HKL_command( "NGL_HKLviewer.normal_clip_plane.clipwidth = None") def onClipwidthChanged(self, val): self.clipwidthval = val self.NGL_HKL_command("NGL_HKLviewer.normal_clip_plane.clipwidth = %f" % self.clipwidthval) def onHKLdistChanged(self, val): self.hkldistval = val self.NGL_HKL_command("NGL_HKLviewer.normal_clip_plane.hkldist = %f" % self.hkldistval) def onHvecChanged(self, val): self.hvecval = val self.NGL_HKL_command("NGL_HKLviewer.normal_clip_plane.h = %f" % self.hvecval) def onKvecChanged(self, val): self.kvecval = val self.NGL_HKL_command("NGL_HKLviewer.normal_clip_plane.k = %f" % self.kvecval) def onLvecChanged(self, val): self.lvecval = val self.NGL_HKL_command("NGL_HKLviewer.normal_clip_plane.l = %f" % self.lvecval) def onFixedorient(self): self.NGL_HKL_command('NGL_HKLviewer.viewer.NGL.fixorientation = %s' \ %str(self.fixedorientcheckbox.isChecked())) def onMillerComboSelchange(self, i): self.NGL_HKL_command("NGL_HKLviewer.scene_id = %d" % i) #self.MillerComboBox.setCurrentIndex(i) if self.MillerComboBox.currentText(): self.functionTabWidget.setEnabled(True) self.expandAnomalouscheckbox.setEnabled(True) # don' allow anomalous expansion for data that's already anomalous for arrayinfo in self.array_infotpls: isanomalous = arrayinfo[-1] label = arrayinfo[0] if isanomalous and label == self.MillerComboBox.currentText( )[:len(label)]: self.expandAnomalouscheckbox.setDisabled(True) else: self.functionTabWidget.setDisabled(True) self.SpaceGroupComboBox.clear() self.SpaceGroupComboBox.addItems(self.spacegroups) # need to supply issymunique flag in infotuple #if self.hklscenes_arrays[ i ][6] == 0: # self.mergecheckbox.setEnabled(True) #else: # self.mergecheckbox.setEnabled(False) def createFileInfoBox(self): self.FileInfoBox = QGroupBox("Reflection File Information") layout = QGridLayout() layout.addWidget(self.openFileNameButton, 0, 0, 1, 2) if self.devmode: layout.addWidget(self.debugbutton, 0, 2, 1, 1) layout.addWidget(self.HKLnameedit, 1, 0, 1, 3) layout.addWidget(self.millertable, 2, 0, 1, 3) layout.addWidget(self.textInfo, 3, 0, 1, 3) #layout.setColumnStretch(1, 2) self.FileInfoBox.setLayout(layout) def createRadiiScaleGroupBox(self): self.RadiiScaleGroupBox = QGroupBox("Radii Size of HKL Spheres") self.ManualPowerScalecheckbox = QCheckBox() self.ManualPowerScalecheckbox.setText( "Manual Power Scaling of Sphere Radii") self.ManualPowerScalecheckbox.clicked.connect(self.onManualPowerScale) self.power_scale_spinBox = QDoubleSpinBox(self.RadiiScaleGroupBox) self.nth_power_scale = 0.5 self.power_scale_spinBox.setValue(self.nth_power_scale) self.power_scale_spinBox.setDecimals(2) self.power_scale_spinBox.setSingleStep(0.05) self.power_scale_spinBox.setRange(0.0, 1.0) self.power_scale_spinBox.valueChanged.connect(self.onPowerScaleChanged) self.power_scale_spinBox.setEnabled(False) self.powerscaleLabel = QLabel() self.powerscaleLabel.setText("Power scale Factor") self.radii_scale_spinBox = QDoubleSpinBox(self.RadiiScaleGroupBox) self.radii_scale = 1.0 self.radii_scale_spinBox.setValue(self.radii_scale) self.radii_scale_spinBox.setDecimals(1) self.radii_scale_spinBox.setSingleStep(0.1) self.radii_scale_spinBox.setRange(0.2, 2.0) self.radii_scale_spinBox.valueChanged.connect(self.onRadiiScaleChanged) self.radiiscaleLabel = QLabel() self.radiiscaleLabel.setText("Linear Scale Factor") layout = QGridLayout() layout.addWidget(self.ManualPowerScalecheckbox, 1, 0, 1, 2) layout.addWidget(self.powerscaleLabel, 2, 0, 1, 2) layout.addWidget(self.power_scale_spinBox, 2, 1, 1, 2) layout.addWidget(self.radiiscaleLabel, 3, 0, 1, 2) layout.addWidget(self.radii_scale_spinBox, 3, 1, 1, 2) layout.setColumnStretch(0, 1) layout.setColumnStretch(1, 0) self.RadiiScaleGroupBox.setLayout(layout) def createBinsBox(self): self.binstable = QTableWidget(0, 4) self.binstable_isready = False labels = [ "no. of HKLs", "lower bin value", "upper bin value", "opacity" ] self.binstable.setHorizontalHeaderLabels(labels) self.binstable.horizontalHeader().setDefaultAlignment(Qt.AlignLeft) self.bindata_labeltxt = QLabel() self.bindata_labeltxt.setText("Data binned:") self.Nbins_spinBox = QSpinBox() self.Nbins_spinBox.setSingleStep(1) self.Nbins_spinBox.setRange(1, 40) self.Nbins_spinBox.valueChanged.connect(self.onNbinsChanged) self.Nbins_labeltxt = QLabel() self.Nbins_labeltxt.setText("Number of bins:") self.OpaqueAllCheckbox = QCheckBox() #self.OpaqueAllCheckbox.setTristate() self.OpaqueAllCheckbox.setText("Show all data in bins") self.OpaqueAllCheckbox.clicked.connect(self.onOpaqueAll) self.binstable.itemChanged.connect(self.onBinsTableItemChanged) self.binstable.itemSelectionChanged.connect( self.onBinsTableItemSelectionChanged) self.BinDataComboBox = QComboBox() self.BinDataComboBox.activated.connect(self.onBindataComboSelchange) self.BinsGroupBox = QGroupBox("Bins") layout = QGridLayout() layout.addWidget(self.bindata_labeltxt, 0, 0) layout.addWidget(self.BinDataComboBox, 0, 1) layout.addWidget(self.Nbins_labeltxt, 0, 2) layout.addWidget(self.Nbins_spinBox, 0, 3) layout.addWidget(self.OpaqueAllCheckbox, 1, 2) layout.addWidget(self.binstable, 2, 0, 1, 4) layout.setColumnStretch(0, 0) layout.setColumnStretch(1, 2) layout.setColumnStretch(3, 1) self.BinsGroupBox.setLayout(layout) def DebugInteractively(self): import code, traceback code.interact(local=locals(), banner="".join(traceback.format_stack(limit=10))) def CreateFunctionTabs(self): self.functionTabWidget = QTabWidget() tab1 = QWidget() layout1 = QGridLayout() layout1.addWidget(self.ExpansionBox, 0, 0) layout1.setRowStretch(0, 0) tab1.setLayout(layout1) tab2 = QWidget() layout2 = QGridLayout() self.fixedorientcheckbox = QCheckBox(self.sliceTabWidget) self.fixedorientcheckbox.setText( "Fix orientation but allow zoom and translation") self.fixedorientcheckbox.clicked.connect(self.onFixedorient) layout2.addWidget(self.fixedorientcheckbox, 0, 0) layout2.addWidget(self.sliceTabWidget, 1, 0) tab2.setLayout(layout2) tab3 = QWidget() layout3 = QGridLayout() layout3.addWidget(self.RadiiScaleGroupBox, 0, 0) tab3.setLayout(layout3) tab4 = QWidget() layout4 = QGridLayout() layout4.addWidget(self.BinsGroupBox, 0, 0) tab4.setLayout(layout4) self.functionTabWidget.addTab(tab1, "Expand") self.functionTabWidget.addTab(tab2, "Slice") self.functionTabWidget.addTab(tab3, "Size") self.functionTabWidget.addTab(tab4, "Bins") self.functionTabWidget.setDisabled(True) def SpacegroupSelchange(self, i): self.NGL_HKL_command("NGL_HKLviewer.spacegroup_choice = %d" % i) def find_free_port(self): import socket s = socket.socket() s.bind(('', 0)) # Bind to a free port provided by the host. port = s.getsockname()[1] s.close() return port def LaunchCCTBXPython(self): self.sockport = self.find_free_port() self.zmq_context = zmq.Context() self.socket = self.zmq_context.socket(zmq.PAIR) self.socket.bind("tcp://127.0.0.1:%s" % self.sockport) try: msg = self.socket.recv( flags=zmq.NOBLOCK) #To empty the socket from previous messages except Exception as e: pass cmdargs = 'cctbx.python.bat -i -c "from crys3d.hklview import cmdlineframes;' \ + ' myHKLview = cmdlineframes.HKLViewFrame(useGuiSocket=%s, high_quality=True,' %self.sockport \ + ' jscriptfname = \'%s\', ' %self.jscriptfname \ + ' verbose=%s, UseOSBrowser= %s )"\n' %(self.verbose, str(self.UseOSbrowser)) self.cctbxproc = subprocess.Popen(cmdargs, shell=True, stdin=subprocess.PIPE, stdout=sys.stdout, stderr=sys.stderr) #time.sleep(1) def NGL_HKL_command(self, cmdstr): #print("sending:\n" + cmdstr) self.socket.send(bytes(cmdstr, "utf-8"))
class ServerBrowser(QWidget): def __init__(self): QWidget.__init__(self) # create table self.table_widget = QTableWidget(0, 7) self.table_widget.setHorizontalHeaderLabels( ["ID", "Name", "Level", "Difficulty", "Mode", "Players", "IP"]) self.table_widget.verticalHeader().setVisible(False) self.table_widget.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table_widget.setSelectionBehavior(QAbstractItemView.SelectRows) self.table_widget.setSortingEnabled(True) # adjust width of IP column self.table_widget.setColumnWidth(6, 170) # password field self.search_label = QLabel("Password:"******"Refresh") self.search_button.clicked.connect(self.search) # search form self.search_form = QHBoxLayout() self.search_form.addWidget(self.search_label) self.search_form.addWidget(self.search_edit) # create main layout self.main_layout = QGridLayout() self.main_layout.addWidget(self.table_widget, 0, 0) self.main_layout.addLayout(self.search_form, 1, 0) self.main_layout.addWidget(self.search_button, 2, 0) self.setLayout(self.main_layout) # should connect to trine server here but the conection is pretty short lived # TODO: unless we continuously send heartbeats #self.tr2_connection = Trine2Connection.Trine2Connection() @Slot() def search(self): self.search_button.setEnabled(False) self.tr2_connection = Trine2Connection.Trine2Connection() password = self.search_edit.text() games = self.tr2_connection.search(password) self.update(games) self.search_button.setEnabled(True) def update(self, games): ''' Populates table widget with data from a list of games ''' # clean up self.table_widget.clearContents() # disable sorting while inserting is necessary self.table_widget.setSortingEnabled(False) # build data array # elements are rows input_data = [] for game in games: # build row array # elements are fields game_line = [ game["id"], game["name"], str(game["level"]), game["difficulty"], game["mode"], "%d/%d" % (game["num_players"], game["max_players"]), game["ip"] ] input_data.append(game_line) self.table_widget.setRowCount(len(input_data)) if len(games) > 0: self.table_widget.setColumnCount(len(input_data[0])) # write data array to table # first iterate over rows for i in range(len(input_data)): # then over fields in row for j in range(len(input_data[i])): self.table_widget.setItem(i, j, QTableWidgetItem(input_data[i][j])) # re-enable sorting once we're done inserting items self.table_widget.setSortingEnabled(True)
class QPOIViewer(QWidget): """ POI Viewer QWidget """ TAG_SPACING = 50 LEGEND_X = -50 LEGEND_Y = 0 LEGEND_WIDTH = 10 TRACE_FUNC_X = 0 TRACE_FUNC_Y = 0 TRACE_FUNC_WIDTH = 50 TRACE_FUNC_MINHEIGHT = 1000 TAB_HEADER_SIZE = 40 MAX_WINDOW_SIZE = 500 MARK_X = LEGEND_X MARK_WIDTH = TRACE_FUNC_X - LEGEND_X + TRACE_FUNC_WIDTH MARK_HEIGHT = 1 POIID_COLUMN = 0 CRASH_COLUMN = 1 CATEGORY_COLUMN = 2 DIAGNOSE_COLUMN = 3 COLUMN_FIELD = ['id', 'bbl', 'category', 'diagnose'] def __init__(self, workspace, parent=None, diagnose_handler=None): super().__init__(parent=parent) self.workspace = workspace self._diagnose_handler = diagnose_handler self.mark = None self.legend = None self.legend_height = 0 self.legend_img = None self.trace_func_unit_height = 0 self.trace_func = None self.trace_id = None self.tabView = None self.traceView = None self.traceScene = None self.POITraceTab = None self.multiPOITab : QWidget = None self.multiPOIList : QTableWidget = None self.mark = None self.curr_position = 0 self._use_precise_position = False self._selected_traces = [] self._selected_poi = None self._init_widgets() self.selected_ins.am_subscribe(self._subscribe_select_ins) self.poi_trace.am_subscribe(self._subscribe_set_trace) self.multi_poi.am_subscribe(self._subscribe_add_poi) self.multiPOIList.cellDoubleClicked.connect(self._on_cell_double_click) self.multiPOIList.itemChanged.connect(self._on_diagnose_change) # # Forwarding properties # @property def disasm_view(self): """ Get the current disassembly view (if there is one), or create a new one as needed. """ view = self.workspace.view_manager.current_view_in_category("disassembly") if view is None: view = self.workspace._get_or_create_disassembly_view() return view @property def poi_trace(self): return self.workspace.instance.poi_trace @property def multi_poi(self): return self.workspace.instance.multi_poi @property def selected_ins(self): return self.disasm_view.infodock.selected_insns def _init_widgets(self): _l.debug("QPOI Viewer Initiating") self.tabView = QTabWidget() # QGraphicsView() self.tabView.setContentsMargins(0, 0, 0, 0) # # POI trace Tab # self.POITraceTab = QWidget() self.POITraceTab.setContentsMargins(0, 0, 0, 0) singleLayout = QVBoxLayout() singleLayout.setSpacing(0) singleLayout.setContentsMargins(0, 0, 0, 0) self.traceView = QGraphicsView() self.traceScene = QGraphicsScene() self.traceView.setScene(self.traceScene) singleLayout.addWidget(self.traceView) self.POITraceTab.setLayout(singleLayout) # # multiPOI Tab # self.multiPOITab = QMultiPOITab(self) # self.multiPOITab = QWidget() multiLayout = QVBoxLayout() multiLayout.setSpacing(0) multiLayout.setContentsMargins(0, 0, 0, 0) self.multiPOIList = QTableWidget(0, 4) # row, col self.multiPOIList.setHorizontalHeaderItem(0, QTableWidgetItem("ID")) self.multiPOIList.setHorizontalHeaderItem(1, QTableWidgetItem("Crash Point")) self.multiPOIList.setHorizontalHeaderItem(2, QTableWidgetItem("Tag")) self.multiPOIList.setHorizontalHeaderItem(3, QTableWidgetItem("Diagnose")) self.multiPOIList.horizontalHeader().setStretchLastSection(True) self.multiPOIList.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) self.multiPOIList.setSelectionBehavior(QAbstractItemView.SelectRows) multiLayout.addWidget(self.multiPOIList) self.multiPOITab.setLayout(multiLayout) self.tabView.addTab(self.multiPOITab, "POI List") self.tabView.addTab(self.POITraceTab, "POI Trace") self.POI_TRACE = 1 self.MULTI_POI = 0 layout = QVBoxLayout() layout.addWidget(self.tabView) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.show() def _reset(self): self.traceScene.clear() #clear items self.mark = None self.legend = None self.legend_height = 0 self.trace_func = QGraphicsItemGroup() self.trace_id = QGraphicsItemGroup() self.traceScene.addItem(self.trace_func) self.hide() # # Event # def _on_cell_double_click(self, row, _): _l.debug("row %d is double clicked", row) first_cell = self.multiPOIList.item(row, 0) if first_cell is None: return poi_id = first_cell.text() poi = self.multi_poi.am_obj.get_poi_by_id(poi_id) if poi is None: return # sanity checks if not isinstance(poi, dict): return if 'output' not in poi or not isinstance(poi['output'], dict): return if 'bbl_history' not in poi['output']: return trace = poi['output']['bbl_history'] if self._selected_poi != poi_id and trace is not None: # render the trace self.poi_trace.am_obj = TraceStatistics(self.workspace, trace, trace_id=poi_id) # show the trace statistic in POI trace self.poi_trace.am_event() # show covered basic blocks and functions self.multi_poi.am_obj.reload_heatmap(poi_id) # redraw function view view = self.workspace.view_manager.first_view_in_category('functions') if view is not None: view.refresh() # redraw disassembly view view = self.workspace.view_manager.first_view_in_category('disassembly') if view is not None: view.redraw_current_graph() if trace is not None: # switch to POI trace tab self.tabView.setCurrentIndex(self.POI_TRACE) self._selected_poi = poi_id second_cell = self.multiPOIList.item(row, 1) crash_addr = None if second_cell is not None: try: crash_addr = int(second_cell.text(), 16) except ValueError: pass if crash_addr is not None: # show the crashing address view = self.workspace.view_manager.first_view_in_category('disassembly') if view is not None: crash_func = self._get_func_from_addr(crash_addr) if crash_func is not None: self.workspace.on_function_selected(crash_func) self.selected_ins.clear() self.selected_ins.update([crash_addr]) self.selected_ins.am_event() view.current_graph.show_instruction(crash_addr) def _on_diagnose_change(self, item: QTableWidgetItem): column = item.column() row = item.row() poi_id = self.multiPOIList.item(row, self.POIID_COLUMN).text() content = item.text() original_content = self.multi_poi.am_obj.get_content_by_id_column(poi_id, column) _l.debug('updaing %s, content: %s, original: %s', poi_id, content, original_content) if not self._is_identical(content, original_content): updated_poi = self.multi_poi.update_poi(poi_id, column, content) self._diagnose_handler.submit_updated_poi(poi_id, updated_poi) def _subscribe_add_poi(self): _l.debug('add a poi to multi poi list') if self.multi_poi.am_none: self.multi_poi.am_obj = MultiPOI(self.workspace) poi_ids = self.multi_poi.am_obj.get_all_poi_ids() self.multiPOIList.clearContents() self._populate_poi_table(self.multiPOIList, poi_ids) self.show() def _subscribe_set_trace(self): _l.debug('on set trace in poi trace viewer') self._reset() if self.poi_trace.am_none: return _l.debug('minheight: %d, count: %d', self.TRACE_FUNC_MINHEIGHT, self.poi_trace.count) if self.poi_trace.count <= 0: _l.warning("No valid addresses found in trace to show. Check base address offsets?") self.poi_trace.am_obj = None self.poi_trace.am_event() return if self.TRACE_FUNC_MINHEIGHT < self.poi_trace.count * 15: self.trace_func_unit_height = 15 show_func_tag = True else: self.trace_func_unit_height = self.TRACE_FUNC_MINHEIGHT / self.poi_trace.count show_func_tag = True self.legend_height = int(self.poi_trace.count * self.trace_func_unit_height) self._show_trace_func(show_func_tag) self._show_legend() self._set_mark_color() self._refresh_multi_list() # boundingSize = self.traceScene.itemsBoundingRect().width() # windowSize = boundingSize # if boundingSize > self.MAX_WINDOW_SIZE: # windowSize = self.MAX_WINDOW_SIZE # self.traceScene.setSceneRect(self.traceScene.itemsBoundingRect()) #resize # if windowSize > self.width(): # self.setMinimumWidth(windowSize) self.show() def _subscribe_select_ins(self, **kwargs): # pylint: disable=unused-argument if self.poi_trace.am_none: return if self.mark is not None: for i in self.mark.childItems(): self.mark.removeFromGroup(i) self.traceScene.removeItem(i) self.traceScene.removeItem(self.mark) self.mark = QGraphicsItemGroup() self.traceScene.addItem(self.mark) if self.selected_ins: addr = next(iter(self.selected_ins)) positions = self.poi_trace.get_positions(addr) if positions: #if addr is in list of positions # handle case where insn was selected from disas view if not self._use_precise_position: self.curr_position = positions[0] - self.poi_trace.count for p in positions: color = self._get_mark_color(p, self.poi_trace.count) y = self._get_mark_y(p) if p == self.poi_trace.count + self.curr_position: #add thicker line for 'current' mark self.mark.addToGroup(self.traceScene.addRect(self.MARK_X, y, self.MARK_WIDTH, self.MARK_HEIGHT*4, QPen(QColor('black')), QBrush(color))) else: self.mark.addToGroup(self.traceScene.addRect(self.MARK_X, y, self.MARK_WIDTH, self.MARK_HEIGHT, QPen(color), QBrush(color))) self.traceScene.update() #force redraw of the traceScene self.scroll_to_position(self.curr_position) def _get_func_from_addr(self, addr): if self.workspace.instance.cfg.am_none: return None bbl = self.workspace.instance.cfg.get_any_node(addr, anyaddr=True) function_addr = bbl.function_address return self.workspace.instance.project.kb.functions.get(function_addr) def _populate_poi_table(self, view, poi_ids): view.clearContents() view.setRowCount(len(poi_ids)) row = 0 #start after label row for poi_id in poi_ids: poi = self.multi_poi.am_obj.get_poi_by_id(poi_id) _l.debug('populating poi: %s', poi) category = poi['category'] output = poi['output'] crash_addr = output['bbl'] if crash_addr is not None: crash = hex(crash_addr) else: crash = None diagnose = output.get('diagnose') _l.debug('poi_ids: %s', poi_ids) _l.debug('current poi id: %s', poi_id) self._set_item(view, row, self.POIID_COLUMN, poi_id, editable=False) self._set_item(view, row, self.CRASH_COLUMN, crash, editable=True) self._set_item(view, row, self.CATEGORY_COLUMN, category, editable=True) self._set_item(view, row, self.DIAGNOSE_COLUMN, diagnose, editable=True) row += 1 _l.debug('poi_ids: %s', poi_ids) @staticmethod def _set_item(view, row, column, text, editable=True): if not text: text = "" item = QTableWidgetItem(text) if not editable: item.setFlags(item.flags() ^ Qt.ItemIsEditable) view.setItem(row, column, item) def _refresh_multi_list(self): multiPOI = self.multi_poi.am_obj trace_ids = multiPOI.get_all_poi_ids() self.multiPOIList.clearContents() self._populate_poi_table(self.multiPOIList, trace_ids) if self._selected_traces and self.multiPOIList.rowCount() > 0: self.multiPOIList.item(0, 0).setSelected(True) self.multiPOIList.item(0, 1).setSelected(True) else: for row in range(self.multiPOIList.rowCount()): item = self.multiPOIList.item(row, 0) inputItem = self.multiPOIList.item(row, 1) if item.text() in self._selected_traces: item.setSelected(True) inputItem.setSelected(True) self.multi_poi.am_event() def _on_tab_change(self): multiPOI = self.multi_poi.am_obj if self.tabView.currentIndex() == self.MULTI_POI: multiPOI.is_active_tab = True self._refresh_multi_list() elif self.tabView.currentIndex() == self.POI_TRACE: multiPOI = self.multi_poi.am_obj multiPOI.is_active_tab = False # self._show_trace_ids() def scroll_to_position(self, position): relative_pos = self.poi_trace.count + position y_offset = self._get_mark_y(relative_pos) scrollValue = 0 if y_offset > 0.5 * self.traceView.size().height(): scrollValue = y_offset - 0.5 * self.traceView.size().height() scrollValue = min(scrollValue, self.traceView.verticalScrollBar().maximum()) self.traceView.verticalScrollBar().setValue(scrollValue) self._use_precise_position = False def jump_next_insn(self): # for some reason indexing is done backwards if self.curr_position + self.poi_trace.count < self.poi_trace.count - 1: self.curr_position += 1 self._use_precise_position = True bbl_addr = self.poi_trace.get_bbl_from_position(self.curr_position) func = self.poi_trace.get_func_from_position(self.curr_position) self._jump_bbl(func, bbl_addr) def jump_prev_insn(self): if self.curr_position + self.poi_trace.count > 0: self.curr_position -= 1 self._use_precise_position = True bbl_addr = self.poi_trace.get_bbl_from_position(self.curr_position) func = self.poi_trace.get_func_from_position(self.curr_position) self._jump_bbl(func, bbl_addr) def mousePressEvent(self, event): button = event.button() pos = self._to_logical_pos(event.pos()) if button == Qt.LeftButton and self.tabView.currentIndex() == self.POI_TRACE and self._at_legend(pos): func = self._get_func_from_y(pos.y()) bbl_addr = self._get_bbl_from_y(pos.y()) self._use_precise_position = True self.curr_position = self._get_position(pos.y()) self._jump_bbl(func, bbl_addr) def _jump_bbl(self, func, bbl_addr): disasm_view = self.disasm_view if disasm_view is not None: all_insn_addrs = self.workspace.instance.project.factory.block(bbl_addr).instruction_addrs # TODO: replace this with am_events perhaps? self.workspace.on_function_selected(func) self.selected_ins.clear() self.selected_ins.update(all_insn_addrs) self.selected_ins.am_event() # TODO: this ought to happen automatically as a result of the am_event disasm_view.current_graph.show_instruction(bbl_addr) def _get_mark_color(self, i, total): relative_gradient_pos = i * 1000 // total return self.legend_img.pixelColor(self.LEGEND_WIDTH // 2, relative_gradient_pos) def _get_mark_y(self, i): return self.TRACE_FUNC_Y + self.trace_func_unit_height * i def _show_trace_func(self, show_func_tag=True): x = self.TRACE_FUNC_X y = self.TRACE_FUNC_Y prev_name = None for position in self.poi_trace.trace_func: func_name = position.func_name color = self.poi_trace.get_func_color(func_name) self.trace_func.addToGroup(self.traceScene.addRect(x, y, self.TRACE_FUNC_WIDTH, self.trace_func_unit_height, QPen(color), QBrush(color))) if show_func_tag is True and func_name != prev_name: tag = self.traceScene.addText(func_name, QFont("Source Code Pro", 7)) tag.setPos(x + self.TRACE_FUNC_WIDTH + self.TAG_SPACING, y - tag.boundingRect().height() // 2) self.trace_func.addToGroup(tag) anchor = self.traceScene.addLine( self.TRACE_FUNC_X + self.TRACE_FUNC_WIDTH, y, x + self.TRACE_FUNC_WIDTH + self.TAG_SPACING, y) self.trace_func.addToGroup(anchor) prev_name = func_name y += self.trace_func_unit_height @staticmethod def _make_legend_gradient(x1, y1, x2, y2): gradient = QLinearGradient(x1, y1, x2, y2) gradient.setColorAt(0.0, Qt.red) gradient.setColorAt(0.4, Qt.yellow) gradient.setColorAt(0.6, Qt.green) gradient.setColorAt(0.8, Qt.blue) gradient.setColorAt(1.0, Qt.darkBlue) return gradient def _show_legend(self): pen = QPen(Qt.transparent) gradient = self._make_legend_gradient(self.LEGEND_X, self.LEGEND_Y, self.LEGEND_X, self.LEGEND_Y + self.legend_height) brush = QBrush(gradient) self.legend = self.traceScene.addRect(self.LEGEND_X, self.LEGEND_Y, self.LEGEND_WIDTH, self.legend_height, pen, brush) reference_gradient = self._make_legend_gradient(0, 0, self.LEGEND_WIDTH, 1000) base_img = QImage(self.LEGEND_WIDTH, 1000, QImage.Format.Format_ARGB32) p = QPainter(base_img) p.fillRect(base_img.rect(),reference_gradient) self.legend_img = base_img #reference shade def _set_mark_color(self): _l.debug('trace count: %d', self.poi_trace.count) for p in range(self.poi_trace.count): color = self._get_mark_color(p, self.poi_trace.count) self.poi_trace.set_mark_color(p, color) def _at_legend(self, pos): x = pos.x() y = pos.y() return self.TRACE_FUNC_X + self.LEGEND_X < x < self.traceView.width() and \ self.TRACE_FUNC_Y < y < self.TRACE_FUNC_Y + self.legend_height def _to_logical_pos(self, pos): x_offset = self.traceView.horizontalScrollBar().value() y_offset = self.traceView.verticalScrollBar().value() return QPoint(pos.x() + x_offset, pos.y() + y_offset) def _get_position(self, y): y_relative = y - self.legend_height - self.TAB_HEADER_SIZE return int(y_relative // self.trace_func_unit_height) def _get_bbl_from_y(self, y): position = self._get_position(y) return self.poi_trace.get_bbl_from_position(position) def _get_func_from_y(self, y): position = self._get_position(y) func = self.poi_trace.get_func_from_position(position) return func # # Context Menu # def menu_add_empty_poi(self): _l.debug('adding a new empty poi item') if self._diagnose_handler.get_image_id() is None: QMessageBox.warning(self.workspace.main_window, "No CHESS target available", "No angr project is loaded, or you did not associate the current project with a CHESS " "target. Please load a binary and associate it with a CHESS target before creating " "POIs.") return poi_id = str(uuid4()) if self.multi_poi.am_none: self.multi_poi.am_obj = MultiPOI(self.workspace) empty_poi = deepcopy(EMPTY_POI) self.multi_poi.add_poi(poi_id, empty_poi) self.multi_poi.am_event() self._diagnose_handler.submit_updated_poi(poi_id, empty_poi) def menu_remove_poi(self): items = self.multiPOIList.selectedItems() row = items.pop().row() poi_id = self.multiPOIList.item(row, 0).text() _l.debug('removing ID %s', poi_id) self.multi_poi.remove_poi(poi_id) self.multi_poi.am_event() @staticmethod def _is_identical(content, original_content): if content == original_content: return True if content == '' and original_content is None: return True try: if int(content, 16) == int(original_content): return True except (TypeError, ValueError): return False return False
class AcquistoForm(QDialog): ''' Widget per l'inserimento di un acquisto immediato. ''' def __init__(self, conn): ''' Parameters: conn : connection Connection to the database. ''' super().__init__() self.setWindowTitle('Aggiungi Acquisto') self.setWindowFlag(QtCore.Qt.WindowContextHelpButtonHint, False) self.conn = conn self.cursor = conn.cursor() self.books = dict() self.books_qt = dict() self.gen_layout = QVBoxLayout() self.form_layout = QFormLayout() self.form_layout.setRowWrapPolicy(QFormLayout.WrapLongRows) # Widgets self.client_field = QLineEdit() self.form_layout.addRow('Numero Cliente (facoltativo): ', self.client_field) self.dip_field = QLineEdit() self.form_layout.addRow('Dipendente (CF): ', self.dip_field) self.date_picker = QDateEdit(QDate.currentDate()) self.date_picker.setDisplayFormat("MM/dd/yyyy") self.date_picker.setCalendarPopup(True) self.form_layout.addRow('Data (mm/gg/aaaa): ', self.date_picker) self.importo_field = QDoubleSpinBox() self.importo_field.setMaximum(999999999.99) self.form_layout.addRow('Importo: ', self.importo_field) self.ins_layout = QHBoxLayout() self.libro_field = QLineEdit() self.quantita_field = QSpinBox() self.quantita_field.setMinimum(1) self.libro_button = QPushButton('Aggiungi') self.libro_button.clicked.connect(self.aggiungi_libro) self.ins_layout.addWidget(QLabel('Libro (ISBN): ')) self.ins_layout.addWidget(self.libro_field) self.ins_layout.addWidget(QLabel('Quantità: ')) self.ins_layout.addWidget(self.quantita_field) self.ins_layout.addWidget(self.libro_button) self.labels = ['ISBN', 'Quantità', ''] self.table = QTableWidget(0, 3) self.table.setHorizontalHeaderLabels(self.labels) self.table.horizontalHeader().setSectionResizeMode( 0, QHeaderView.Stretch) self.table.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Stretch) self.table.horizontalHeader().setSectionResizeMode( 2, QHeaderView.ResizeToContents) self.confirm_button = QPushButton('Conferma') self.confirm_button.clicked.connect(self.post_acquisto) self.gen_layout.addLayout(self.form_layout) self.gen_layout.addLayout(self.ins_layout) self.gen_layout.addWidget(self.table) self.gen_layout.addWidget(self.confirm_button) self.setLayout(self.gen_layout) def aggiungi_libro(self): self.books[self.libro_field.text()] = self.quantita_field.value() self.update_table() def remove_libro(self, book): self.books.pop(book, None) self.update_table() def update_table(self): self.table.clearContents() while self.table.rowCount() > 0: self.table.removeRow(0) for book in self.books.keys(): row = self.table.rowCount() button = QPushButton('Rimuovi') button.clicked.connect(lambda: self.remove_libro(book)) self.table.insertRow(row) self.table.setItem(row, 0, QTableWidgetItem(book)) self.table.setItem(row, 1, QTableWidgetItem(str(self.books[book]))) self.table.setCellWidget(row, 2, button) def verif_qty(self): ''' Shows error messages based on the validity of inserted books, and returns False, or returns True if all the books are ok to sell right now. ''' if len(self.books.items()) == 0: self._show_error('Non ci sono libri nell\'acquisto') return 1 for book, qty in self.books.items(): self.cursor.execute(FIND_QUANTITA, (book, )) result = self.cursor.fetchall() if not result: self._show_error('\'{}\' non è un libro valido.'.format(book)) return 2 stored = result[0][0] if stored < qty: return self.__show_are_you_sure( 'L\'acquisto richiede {} libri {}, ma ne sono presenti solo {}.\nNon sarà possibile sottrarre i libri acquistati.\nVuoi proseguire ugualmente?' .format(qty, book, stored)) return 0 def verif_client_dip(self): ''' Returns false and displays and error message if cliente and dipendente are not valid tuples in the database, returns true if they are ok ''' cliente = self.client_field.text() if cliente: if not cliente.isdigit(): self._show_error('Il codice del Cliente deve essere numerico.') return 1 self.cursor.execute(FIND_CLIENTE, (cliente, )) result = self.cursor.fetchall() if not result or not result[0][0]: self._show_error('Cliente {} non esiste.'.format(cliente)) return 2 dipendente = self.dip_field.text() if not dipendente: self._show_error('Il Dipendente non può essere vuoto.') return 3 self.cursor.execute(FIND_DIPENDENTE, (dipendente, )) result = self.cursor.fetchall() if not result or not result[0][0]: self._show_error('Dipendente {} non esiste.'.format(dipendente)) return 4 return 0 def post_acquisto(self): if self.verif_client_dip(): return should_show = self.verif_qty() if should_show > 0: return cliente = self.client_field.text().strip() if self.client_field.text( ).strip() else None importo = self.importo_field.value() self.cursor.execute( INSERT_ACQUISTO, (self.date_picker.date().toString('MM/dd/yyyy'), self.importo_field.value(), self.dip_field.text())) new_id = self.cursor.fetchall()[0][0] self.cursor.execute(INSERT_IMMEDIATO, (new_id, cliente)) for book in self.books.keys(): self.cursor.execute(INSERT_COMPRENDE, (new_id, book, self.books[book])) self.conn.commit() if should_show == 0: self._show_confirm() self.accept() def __show_are_you_sure(self, msg=''): dialog = _AreYouSureDialog(msg) dialog.setWindowTitle('ATTENZIONE') result = dialog.exec_() return -1 if result == QDialog.Accepted else 3 def _show_confirm(self): dialog = _ScalaAcquistiDialog(self.books, self.conn) dialog.setWindowTitle('Rimozione libri') dialog.exec_() def _show_error(self, msg=''): dialog = QMessageBox() dialog.setWindowTitle('ERRORE') dialog.setText(msg) dialog.exec_()
class PrenotazioneForm(QDialog): ''' Widget per l'inserimento di un acquisto immediato. ''' def __init__(self, conn): ''' Parameters: conn : connection Connection to the database. ''' super().__init__() self.setWindowTitle('Aggiungi Prenotazione') self.setWindowFlag(QtCore.Qt.WindowContextHelpButtonHint, False) self.conn = conn self.cursor = conn.cursor() self.books = dict() self.books_qt = dict() self.gen_layout = QVBoxLayout() self.form_layout = QFormLayout() self.form_layout.setRowWrapPolicy(QFormLayout.WrapLongRows) # Widgets self.client_field = QLineEdit() self.form_layout.addRow('Numero Cliente: ', self.client_field) self.dip_field = QLineEdit() self.form_layout.addRow('Dipendente (CF): ', self.dip_field) self.date_picker = QDateEdit(QDate.currentDate()) self.date_picker.setDisplayFormat("MM/dd/yyyy") self.date_picker.setCalendarPopup(True) self.form_layout.addRow('Data (mm/gg/aaaa): ', self.date_picker) self.importo_field = QDoubleSpinBox() self.importo_field.setMaximum(999999999.99) self.form_layout.addRow('Importo: ', self.importo_field) self.ins_layout = QHBoxLayout() self.libro_field = QLineEdit() self.quantita_field = QSpinBox() self.quantita_field.setMinimum(1) self.libro_button = QPushButton('Aggiungi') self.libro_button.clicked.connect(self.aggiungi_libro) self.ins_layout.addWidget(QLabel('Libro (ISBN): ')) self.ins_layout.addWidget(self.libro_field) self.ins_layout.addWidget(QLabel('Quantità: ')) self.ins_layout.addWidget(self.quantita_field) self.ins_layout.addWidget(self.libro_button) self.labels = ['ISBN', 'Quantità', ''] self.table = QTableWidget(0, 3) self.table.setHorizontalHeaderLabels(self.labels) self.table.horizontalHeader().setSectionResizeMode( 0, QHeaderView.Stretch) self.table.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Stretch) self.table.horizontalHeader().setSectionResizeMode( 2, QHeaderView.ResizeToContents) self.info_label = QLabel( 'Le prenotazioni non riducono i libri disponibili.') self.confirm_button = QPushButton('Conferma') self.confirm_button.clicked.connect(self.post_prenotazione) self.gen_layout.addLayout(self.form_layout) self.gen_layout.addLayout(self.ins_layout) self.gen_layout.addWidget(self.table) self.gen_layout.addWidget(self.info_label) self.gen_layout.addWidget(self.confirm_button) self.setLayout(self.gen_layout) def aggiungi_libro(self): self.books[self.libro_field.text()] = self.quantita_field.value() self.update_table() def remove_libro(self, book): self.books.pop(book, None) self.update_table() def update_table(self): self.table.clearContents() while self.table.rowCount() > 0: self.table.removeRow(0) for book in self.books.keys(): row = self.table.rowCount() button = QPushButton('Rimuovi') button.clicked.connect(lambda: self.remove_libro(book)) self.table.insertRow(row) self.table.setItem(row, 0, QTableWidgetItem(book)) self.table.setItem(row, 1, QTableWidgetItem(str(self.books[book]))) self.table.setCellWidget(row, 2, button) def verif_libri(self): ''' Shows error messages based on the validity of inserted books, and returns False, or returns True if all the books are ok to sell right now. ''' if len(self.books.items()) == 0: self._show_error('Non ci sono libri nell\'acquisto') return False for book in self.books.keys(): self.cursor.execute('SELECT * FROM libro WHERE isbn = %s', (book, )) result = self.cursor.fetchall() if not result: self._show_error('\'{}\' non è un libro valido.'.format(book)) return False return True def verif_client_dip(self): ''' Returns false and displays and error message if cliente and dipendente are not valid tuples in the database, returns true if they are ok ''' cliente = self.client_field.text() if not cliente: self._show_error('Il Cliente è necessario per una Prenotazione.') return False if cliente: if not cliente.isdigit(): self._show_error('Il codice del Cliente deve essere numerico.') return False self.cursor.execute(FIND_CLIENTE, (cliente, )) result = self.cursor.fetchall() if not result or not result[0][0]: self._show_error('Cliente {} non esiste.'.format(cliente)) return False dipendente = self.dip_field.text() if not dipendente: self._show_error('Il Dipendente non può essere vuoto.') return False self.cursor.execute(FIND_DIPENDENTE, (dipendente, )) result = self.cursor.fetchall() if not result or not result[0][0]: self._show_error('Dipendente {} non esiste.'.format(dipendente)) return False return True def post_prenotazione(self): if not self.verif_libri(): return if not self.verif_client_dip(): return cliente = self.client_field.text().strip() if self.client_field.text( ).strip() else None importo = self.importo_field.value() self.cursor.execute( INSERT_ACQUISTO, (self.date_picker.date().toString('MM/dd/yyyy'), self.importo_field.value(), self.dip_field.text())) new_id = self.cursor.fetchall()[0][0] self.cursor.execute(INSERT_PRENOTAZIONE, (new_id, cliente)) for book in self.books.keys(): self.cursor.execute(INSERT_COMPRENDE, (new_id, book, self.books[book])) self.conn.commit() self._show_confirm() self.accept() def _show_confirm(self): dialog = QMessageBox() dialog.setWindowTitle('Conferma Prenotazione') msg = 'Registrato prenotazione per i seguenti libri:\n{}' dialog.setText( msg.format('\n'.join( ['{} x {}'.format(k, v) for k, v in self.books.items()]))) dialog.exec_() def _show_error(self, msg=''): dialog = QMessageBox() dialog.setWindowTitle('ERRORE') dialog.setText(msg) dialog.exec_()
class App(QWidget): def __init__(self): super().__init__() self.setWindowIcon(QIcon('icon.ico')) QApplication.setFont( QFont("Helvetica", 9, QFont.Normal, italic=False)) self.title = 'DanielPaskalev' self.left, self.top = 0, 0 self.width, self.height = 900, 920 self.current_tests = process(get_filename()) self.original_tests = process(get_filename()) self.search = "" self.initUI() def initUI(self): # self.is_button_clicked = False self.setWindowTitle(self.title) self.setWindowState(Qt.WindowMaximized) self.createLabel() self.createLe() self.createTable() self.createButton() self.createCopyButton() self.createRefreshButton() self.createMergeButton() self.createMenuBox() # Create vertical box layout and horizontal box layout, # add label, button, to hbox, # add hbox to vbox, # and add table to vbox. self.layout = QVBoxLayout() self.layout.setContentsMargins(0, 5, 0, 0) # self.layout.setSpacing(0) self.hbox = QHBoxLayout() self.hbox.addWidget(self.menuBar) self.hbox.addWidget(self.label) self.hbox.addWidget(self.le) self.hbox.addWidget(self.button) self.hbox.addWidget(self.copyButton) self.hbox.addWidget(self.refreshButton) self.hbox.addWidget(self.mergeButton) self.layout.addLayout(self.hbox) self.layout.addWidget(self.tableWidget) self.setLayout(self.layout) # Show widget self.show() def createLe(self): # Create user input box for filter. self.le = QLineEdit() self.le.setObjectName("Filter") self.le.setPlaceholderText("Filter") self.le.setToolTip('Enter text to filter the pending list') self.le.setMaximumWidth(200) self.le.returnPressed.connect( self.filter_accessions) # Enter pressed def createButton(self): # Create "Filter Accessions" button. self.button = QPushButton('Filter', self) self.button.setToolTip('Filters the accessions by text matches.') self.button.setMaximumWidth(60) self.button.clicked.connect(self.filter_accessions) def createCopyButton(self): # Create Copy accessions button. self.copyButton = QPushButton('Copy', self) self.copyButton.setToolTip( 'Copy all unique accessions to clipboard.') self.copyButton.setMaximumWidth(60) self.copyButton.clicked.connect(self.on_copyButton_click) def createRefreshButton(self): # Re-acquire the ref pending list. self.refreshButton = QPushButton('Refresh', self) self.refreshButton.setToolTip( 'Refresh table with new pending list.') self.refreshButton.setMaximumWidth(60) self.refreshButton.clicked.connect(self.on_refresh) def createMergeButton(self): # Merge the currently showing accessions. self.mergeButton = QPushButton('Merge', self) self.mergeButton.setToolTip( 'Merges tests for duplicate accessions') self.mergeButton.setMaximumWidth(60) self.mergeButton.clicked.connect(self.on_merge) def createLabel(self): # label with general information. self.label = QLabel() self.label.setTextFormat(Qt.PlainText) text = ("Double click entry to copy | Order count: " + str(len(self.current_tests))) self.label.setText(text) self.label.setAlignment(Qt.AlignCenter) def createTable(self): # Initialize table with proper attributes. Then populateTable. self.tableWidget = QTableWidget() self.tableWidget.clicked.connect( self.on_click) # If cell is clicked, copy. self.tableWidget.setEditTriggers( QAbstractItemView.NoEditTriggers) # no edit self.tableWidget.setWordWrap(True) self.tableWidget.setColumnCount(5) self.tableWidget.setHorizontalHeaderLabels( ["Accession", "Name", "DOC", "Worklist(s)", "Pending Tests"]) self.tableWidget.horizontalHeader().setStretchLastSection(True) self.tableWidget.horizontalHeaderItem(4).setTextAlignment( Qt.AlignLeft) self.populateTable(self.current_tests) # Populate table with data self.tableWidget.resizeColumnsToContents( ) # Resize columns only once. self.tableWidget.resizeRowsToContents( ) # Resize height to fit tests. def populateTable(self, orderList): # Re-populate table with argument 'orderList' self.tableWidget.setSortingEnabled(False) self.tableWidget.clearContents() self.tableWidget.setRowCount(len(orderList)) for i in range(len(orderList)): self.tableWidget.setItem(i, 0, QTableWidgetItem(orderList[i][1])) self.tableWidget.setItem(i, 1, QTableWidgetItem(orderList[i][4])) self.tableWidget.setItem(i, 2, QTableWidgetItem(orderList[i][3])) self.tableWidget.setItem(i, 3, QTableWidgetItem(orderList[i][0])) self.tableWidget.setItem(i, 4, QTableWidgetItem(orderList[i][2])) self.tableWidget.resizeRowsToContents( ) # Resize height to fit tests # self.tableWidget.resizeColumnsToContents() self.label.setText("Double click entry to copy | Order count: " + str(len(orderList))) self.tableWidget.setSortingEnabled(True) def createMenuBox(self): # Menu bar at the top of the window. self.menuBar = QMenuBar() self.fileMenu = self.menuBar.addMenu('File') self.open_action = QAction('Open', self) self.exit_action = QAction('Exit', self) self.open_action.triggered.connect(self.open) self.exit_action.triggered.connect(app.quit()) # just quit self.fileMenu.addAction(self.open_action) self.fileMenu.addAction(self.exit_action) @Slot() def open(self): fname = QFileDialog.getOpenFileName( self, 'Open File', os.path.expanduser('~/Documents'), 'Text Files (*.txt)') if fname[0]: self.original_tests = process(fname[0]) self.filter_accessions() @Slot() def on_click(self): # Double click to put selected item into clipboard qApp.clipboard().setText( self.tableWidget.selectedItems()[0].text()) @Slot() def on_refresh(self): # Refresh button clicked to re-create table with new pending list. self.original_tests = process(get_filename()) self.filter_accessions() @Slot() def on_copyButton_click(self): # Click to copy all accessions into clipboard self.cp = [i[1] for i in self.current_tests] qApp.clipboard().setText( self.search + ''.join(['\n' + a for a in filter_dups(self.cp)])) @Slot() def on_merge(self): # Merge current accessions to remove situation where multiple tests for # the same patient are on multiple worklists. self.tableWidget.setSortingEnabled(False) # Aglorithm to merge duplicate accessions. temp_tests = deepcopy(self.current_tests) # DEEEEPcopy temp_tests.sort(key=lambda x: x[1]) # Sort by accession number result = [] i = 0 # Compare the current accession to the next to see if duplicate. length = len(temp_tests) - 1 while i < length: if temp_tests[i][1] == temp_tests[i + 1][1]: # If duplicates, add worklist and tests to first accesion. temp_tests[i][0] += ', ' + temp_tests[i + 1][0] temp_tests[i][2] += ' ||| ' + temp_tests[i + 1][2] del temp_tests[i + 1] # Delete second accession. length -= 1 else: # If current and next accession numbers don't match result.append(temp_tests[i]) i += 1 result.append( temp_tests[-1]) # add the last accession that we missed. # Re-create table with 'result' self.populateTable(result) self.mergeButton.setDown(True) # Click down merge button @Slot() def filter_accessions(self): # Button / Return pressed to filter the orders. self.tableWidget.setSortingEnabled(False) self.mergeButton.setDown(False) # Unclick merge button self.search = self.le.text().upper() self.current_tests = [ a for a in self.original_tests if self.search in a[0] or self.search in a[1] or self.search in a[2] or self.search in a[3] or self.search in a[4] ] self.populateTable(self.current_tests)
class QTraceViewer(QWidget): """ Load a basic block trace through json and visualize it in the disassembly Ref: https://github.com/angr/angr-management/pull/122 """ TAG_SPACING = 50 LEGEND_X = -50 LEGEND_Y = 0 LEGEND_WIDTH = 10 TRACE_FUNC_X = 0 TRACE_FUNC_Y = 0 TRACE_FUNC_WIDTH = 50 TRACE_FUNC_MINHEIGHT = 1000 TAB_HEADER_SIZE = 40 MAX_WINDOW_SIZE = 500 MARK_X = LEGEND_X MARK_WIDTH = TRACE_FUNC_X - LEGEND_X + TRACE_FUNC_WIDTH MARK_HEIGHT = 1 def __init__(self, workspace, disasm_view, parent=None): super().__init__(parent=parent) self.workspace = workspace self.disasm_view = disasm_view self.mark = None self.legend = None self.legend_height = 0 self.legend_img = None self.trace_func_unit_height = 0 self.trace_func = None self.trace_id = None self.view = None self.traceView = None self.traceTab = None self.traceScene = None self.multiView = None self.listView = None self.mark = None self.curr_position = 0 self._use_precise_position = False self._selected_traces = [] self._init_widgets() self.trace.am_subscribe(self._on_set_trace) self.selected_ins.am_subscribe(self._on_select_ins) self.traceTab.installEventFilter(self) # # Forwarding properties # @property def trace(self): return self.workspace.instance.trace @property def multi_trace(self): return self.workspace.instance.multi_trace @property def selected_ins(self): return self.disasm_view.infodock.selected_insns def _init_widgets(self): self.view = QTabWidget() # QGraphicsView() self.traceTab = QWidget() tracelayout = QVBoxLayout() self.traceView = QGraphicsView() self.traceScene = QGraphicsScene() self.traceView.setScene(self.traceScene) self.listView = QTableWidget(0, 2) # row, col self.listView.setHorizontalHeaderItem(0, QTableWidgetItem("Trace ID")) self.listView.setHorizontalHeaderItem(1, QTableWidgetItem("Input ID")) self.listView.setSelectionMode(QAbstractItemView.SingleSelection) self.listView.setSelectionBehavior(QAbstractItemView.SelectRows) # self.listView.horizontalHeader().setStretchLastSection(True) # self.listView.horizontalHeader().setSectionResizeModel(0, QHeaderView.Stretch) self.listView.cellClicked.connect(self._switch_current_trace) self.traceSeedButton = QPushButton("View Input Seed") self.traceSeedButton.clicked.connect(self._view_input_seed) tracelayout.addWidget(self.traceView) tracelayout.addWidget(self.listView) tracelayout.addWidget(self.traceSeedButton) self.traceTab.setLayout(tracelayout) self.multiView = QWidget() multiLayout = QVBoxLayout() self.multiTraceList = QTableWidget(0, 2) # row, col self.multiTraceList.setSelectionMode(QAbstractItemView.MultiSelection) self.multiTraceList.setSelectionBehavior(QAbstractItemView.SelectRows) self.multiTraceList.setHorizontalScrollMode( self.multiTraceList.ScrollPerPixel) self.multiTraceList.setHorizontalHeaderItem( 0, QTableWidgetItem("Trace ID")) self.multiTraceList.setHorizontalHeaderItem( 1, QTableWidgetItem("Input ID")) self.selectMultiTrace = QPushButton("Refresh Heatmap") self.selectMultiTrace.clicked.connect(self._refresh_heatmap) multiLayout.addWidget(self.multiTraceList) multiLayout.addWidget(self.selectMultiTrace) self.multiView.setLayout(multiLayout) self.view.addTab(self.traceTab, "SingleTrace") self.view.addTab(self.multiView, "MultiTrace HeatMap") self.SINGLE_TRACE = 0 self.MULTI_TRACE = 1 self.view.currentChanged.connect(self._on_tab_change) self._reset() layout = QVBoxLayout() layout.addWidget(self.view) layout.setContentsMargins(0, 0, 0, 0) layout.setAlignment(self.view, Qt.AlignLeft) self.setLayout(layout) def _reset(self): self.traceScene.clear() #clear items self.listView.clearContents() self.multiTraceList.clearContents() self.mark = None self.legend = None self.legend_height = 0 self.trace_func = QGraphicsItemGroup() self.trace_id = QGraphicsItemGroup() self.traceScene.addItem(self.trace_func) self.hide() def _view_input_seed(self): current_trace_stats = self.trace.am_obj input_id = current_trace_stats.input_id inputSeed = self.multi_trace.am_obj.get_input_seed_for_id(input_id) msgText = "%s" % inputSeed msgDetails = "Input for [%s]" % current_trace_stats.id msgbox = QMessageBox() msgbox.setWindowTitle("Seed Input") msgbox.setDetailedText(msgDetails) msgbox.setText(msgText) msgbox.setStandardButtons(QMessageBox.Ok) msgbox.exec() def _switch_current_trace(self, row): if self.listView.rowCount() <= 0: return current_trace = self.trace.am_obj.id new_trace = self.multiTraceList.item(row, 0).text() if current_trace == new_trace: return trace_stats = self.multi_trace.am_obj.get_trace_with_id(new_trace) if trace_stats: self.trace.am_obj = trace_stats self._on_set_trace() def _on_set_trace(self): self._reset() if self.trace.am_none or self.trace.count is None: return l.debug('minheight: %d, count: %d', self.TRACE_FUNC_MINHEIGHT, self.trace.count) if self.trace.count <= 0: l.warning( "No valid addresses found in trace to show. Check base address offsets?" ) self.trace.am_obj = None self.trace.am_event() return if self.TRACE_FUNC_MINHEIGHT < self.trace.count * 15: self.trace_func_unit_height = 15 show_func_tag = True else: self.trace_func_unit_height = self.TRACE_FUNC_MINHEIGHT / self.trace.count show_func_tag = True self.legend_height = int(self.trace.count * self.trace_func_unit_height) self._show_trace_func(show_func_tag) self._show_legend() self._show_trace_ids() self._set_mark_color() self._refresh_multi_list() boundingSize = self.traceScene.itemsBoundingRect().width() windowSize = boundingSize if boundingSize > self.MAX_WINDOW_SIZE: windowSize = self.MAX_WINDOW_SIZE self.traceScene.setSceneRect( self.traceScene.itemsBoundingRect()) #resize self.setFixedWidth(windowSize) # self.listScene.setSceneRect(self.listScene.itemsBoundingRect()) #resize self.multiView.setFixedWidth(windowSize) cellWidth = windowSize // 2 self.listView.setColumnWidth(0, cellWidth) self.listView.setColumnWidth(1, cellWidth) self.listView.setFixedHeight(self.multiView.height() // 4) self.multiTraceList.setColumnWidth(0, cellWidth) self.multiTraceList.setColumnWidth(1, cellWidth) self.view.setFixedWidth(windowSize) self.show() def _populate_trace_table(self, view, trace_ids): numIDs = len(trace_ids) view.clearContents() view.setRowCount(numIDs) row = 0 #start after label row for traceID in trace_ids: inputID = self.multi_trace.am_obj.get_input_id_for_trace_id( traceID) if inputID is None: self.workspace.log("No inputID found for trace %s" % traceID) view.setItem(row, 0, QTableWidgetItem(traceID)) view.setItem(row, 1, QTableWidgetItem(inputID)) row += 1 def _refresh_heatmap(self): multiTrace = self.multi_trace.am_obj multiTrace.clear_heatmap() multiTrace.is_active_tab = True selected_items = self.multiTraceList.selectedItems() self._selected_traces.clear() for row in range(self.multiTraceList.rowCount()): item = self.multiTraceList.item(row, 0) if item in selected_items: self._selected_traces.append(item.text()) multiTrace.reload_heatmap(self._selected_traces) self.multi_trace.am_event() def _refresh_multi_list(self): multiTrace = self.multi_trace.am_obj trace_ids = multiTrace.get_all_trace_ids() self.multiTraceList.clearContents() self._populate_trace_table(self.multiTraceList, trace_ids) if self._selected_traces and self.multiTraceList.rowCount() > 0: self.multiTraceList.item(0, 0).setSelected(True) self.multiTraceList.item(0, 1).setSelected(True) else: for row in range(self.multiTraceList.rowCount()): item = self.multiTraceList.item(row, 0) inputItem = self.multiTraceList.item(row, 1) if item.text() in self._selected_traces: item.setSelected(True) inputItem.setSelected(True) self.multi_trace.am_event() def _on_tab_change(self): # self._reset() multiTrace = self.multi_trace.am_obj if self.view.currentIndex() == self.MULTI_TRACE: multiTrace.is_active_tab = True self._refresh_multi_list() elif self.view.currentIndex() == self.SINGLE_TRACE: multiTrace = self.multi_trace.am_obj multiTrace.is_active_tab = False self._show_trace_ids() def _on_select_ins(self, **kwargs): # pylint: disable=unused-argument if self.trace.am_none: return if self.mark is not None: for i in self.mark.childItems(): self.mark.removeFromGroup(i) self.traceScene.removeItem(i) self.traceScene.removeItem(self.mark) self.mark = QGraphicsItemGroup() self.traceScene.addItem(self.mark) if self.selected_ins: addr = next(iter(self.selected_ins)) positions = self.trace.get_positions(addr) if positions: #if addr is in list of positions if not self._use_precise_position: #handle case where insn was selected from disas view self.curr_position = positions[0] - self.trace.count for p in positions: color = self._get_mark_color(p, self.trace.count) y = self._get_mark_y(p) if p == self.trace.count + self.curr_position: #add thicker line for 'current' mark self.mark.addToGroup( self.traceScene.addRect(self.MARK_X, y, self.MARK_WIDTH, self.MARK_HEIGHT * 4, QPen(QColor('black')), QBrush(color))) else: self.mark.addToGroup( self.traceScene.addRect(self.MARK_X, y, self.MARK_WIDTH, self.MARK_HEIGHT, QPen(color), QBrush(color))) self.traceScene.update() #force redraw of the traceScene self.scroll_to_position(self.curr_position) def scroll_to_position(self, position): relative_pos = self.trace.count + position y_offset = self._get_mark_y(relative_pos) scrollValue = 0 if y_offset > 0.5 * self.traceView.size().height(): scrollValue = y_offset - 0.5 * self.traceView.size().height() scrollValue = min(scrollValue, self.traceView.verticalScrollBar().maximum()) self.traceView.verticalScrollBar().setValue(scrollValue) self._use_precise_position = False def jump_next_insn(self): if self.curr_position + self.trace.count < self.trace.count - 1: #for some reason indexing is done backwards self.curr_position += 1 self._use_precise_position = True bbl_addr = self.trace.get_bbl_from_position(self.curr_position) func = self.trace.get_func_from_position(self.curr_position) self._jump_bbl(func, bbl_addr) def jump_prev_insn(self): if self.curr_position + self.trace.count > 0: self.curr_position -= 1 self._use_precise_position = True bbl_addr = self.trace.get_bbl_from_position(self.curr_position) func = self.trace.get_func_from_position(self.curr_position) self._jump_bbl(func, bbl_addr) def eventFilter(self, obj, event): #specifically to catch arrow keys #pylint: disable=unused-argument # more elegant solution to link w/ self.view's scroll bar keypressevent? if event.type() == QEvent.Type.KeyPress: if not event.modifiers() & Qt.ShiftModifier: #shift + arrowkeys return False key = event.key() if key in [Qt.Key_Up, Qt.Key_Left]: self.jump_prev_insn() elif key in [Qt.Key_Down, Qt.Key_Right]: self.jump_next_insn() return True return False # pass through all other events def mousePressEvent(self, event): button = event.button() pos = self._to_logical_pos(event.pos()) if button == Qt.LeftButton and self.view.currentIndex( ) == self.SINGLE_TRACE and self._at_legend(pos): func = self._get_func_from_y(pos.y()) bbl_addr = self._get_bbl_from_y(pos.y()) self._use_precise_position = True self.curr_position = self._get_position(pos.y()) self._jump_bbl(func, bbl_addr) def _jump_bbl(self, func, bbl_addr): all_insn_addrs = self.workspace.instance.project.factory.block( bbl_addr).instruction_addrs # TODO: replace this with am_events perhaps? if func is None: return self.workspace.on_function_selected(func) self.selected_ins.clear() self.selected_ins.update(all_insn_addrs) self.selected_ins.am_event() # TODO: this ought to happen automatically as a result of the am_event self.disasm_view.current_graph.show_instruction(bbl_addr) def _get_mark_color(self, i, total): relative_gradient_pos = i * 1000 // total return self.legend_img.pixelColor(self.LEGEND_WIDTH // 2, relative_gradient_pos) def _get_mark_y(self, i): return self.TRACE_FUNC_Y + self.trace_func_unit_height * i def _show_trace_ids(self): trace_ids = self.multi_trace.get_all_trace_ids() # traceID = self.listScene.addText(id_txt, QFont("Source Code Pro", 7)) # traceID.setPos(5,5) self.listView.clearContents() self._populate_trace_table(self.listView, trace_ids) if len(self.listView.selectedItems()) <= 0 and not self.trace.am_none: for row in range(self.listView.rowCount()): item = self.listView.item(row, 0) inputItem = self.listView.item(row, 1) if self.trace.id in item.text(): item.setSelected(True) inputItem.setSelected(True) break def _show_trace_func(self, show_func_tag): x = self.TRACE_FUNC_X y = self.TRACE_FUNC_Y prev_name = None for position in self.trace.trace_func: bbl_addr = position.bbl_addr func_name = position.func_name l.debug('Draw function %x, %s', bbl_addr, func_name) color = self.trace.get_func_color(func_name) self.trace_func.addToGroup( self.traceScene.addRect(x, y, self.TRACE_FUNC_WIDTH, self.trace_func_unit_height, QPen(color), QBrush(color))) if show_func_tag is True and func_name != prev_name: tag = self.traceScene.addText(func_name, QFont("Source Code Pro", 7)) tag.setPos(x + self.TRACE_FUNC_WIDTH + self.TAG_SPACING, y - tag.boundingRect().height() // 2) self.trace_func.addToGroup(tag) anchor = self.traceScene.addLine( self.TRACE_FUNC_X + self.TRACE_FUNC_WIDTH, y, x + self.TRACE_FUNC_WIDTH + self.TAG_SPACING, y) self.trace_func.addToGroup(anchor) prev_name = func_name y += self.trace_func_unit_height @staticmethod def _make_legend_gradient(x1, y1, x2, y2): gradient = QLinearGradient(x1, y1, x2, y2) gradient.setColorAt(0.0, Qt.red) gradient.setColorAt(0.4, Qt.yellow) gradient.setColorAt(0.6, Qt.green) gradient.setColorAt(0.8, Qt.blue) gradient.setColorAt(1.0, Qt.darkBlue) return gradient def _show_legend(self): pen = QPen(Qt.transparent) gradient = self._make_legend_gradient( self.LEGEND_X, self.LEGEND_Y, self.LEGEND_X, self.LEGEND_Y + self.legend_height) brush = QBrush(gradient) self.legend = self.traceScene.addRect(self.LEGEND_X, self.LEGEND_Y, self.LEGEND_WIDTH, self.legend_height, pen, brush) reference_gradient = self._make_legend_gradient( 0, 0, self.LEGEND_WIDTH, 1000) base_img = QImage(self.LEGEND_WIDTH, 1000, QImage.Format.Format_ARGB32) p = QPainter(base_img) p.fillRect(base_img.rect(), reference_gradient) self.legend_img = base_img #reference shade def _set_mark_color(self): for p in range(self.trace.count): color = self._get_mark_color(p, self.trace.count) self.trace.set_mark_color(p, color) def _at_legend(self, pos): x = pos.x() y = pos.y() return self.TRACE_FUNC_X + self.LEGEND_X < x < self.traceView.width() and \ self.TRACE_FUNC_Y < y < self.TRACE_FUNC_Y + self.legend_height def _to_logical_pos(self, pos): x_offset = self.traceView.horizontalScrollBar().value() y_offset = self.traceView.verticalScrollBar().value() return QPoint(pos.x() + x_offset, pos.y() + y_offset) def _get_position(self, y): y_relative = y - self.legend_height - self.TAB_HEADER_SIZE return int(y_relative // self.trace_func_unit_height) def _get_bbl_from_y(self, y): position = self._get_position(y) return self.trace.get_bbl_from_position(position) def _get_func_from_y(self, y): position = self._get_position(y) func = self.trace.get_func_from_position(position) return func
class defaultRepos(confStack): def __init_stack__(self): self.dbg = False self._debug("confDefault Load") self.menu_description = (_("Choose the default repositories")) self.description = (_("Default repositories")) self.icon = ('go-home') self.tooltip = (_( "From here you can activate/deactivate the default repositories")) self.index = 1 self.enabled = True self.defaultRepos = {} self.changed = [] self.level = 'user' #def __init__ def _load_screen(self): box = QVBoxLayout() lbl_txt = QLabel(_("Enable or disable default repositories")) lbl_txt.setAlignment(Qt.AlignTop) box.addWidget(lbl_txt, 0) self.table = QTableWidget(1, 2) Hheader = self.table.horizontalHeader() Vheader = self.table.verticalHeader() Hheader.setSectionResizeMode(0, QHeaderView.Stretch) Vheader.setSectionResizeMode(QHeaderView.ResizeToContents) self.table.setShowGrid(False) self.table.setSelectionBehavior(QTableWidget.SelectRows) self.table.setSelectionMode(QTableWidget.NoSelection) self.table.setEditTriggers(QTableWidget.NoEditTriggers) self.table.horizontalHeader().hide() self.table.verticalHeader().hide() box.addWidget(self.table) self.setLayout(box) self.updateScreen() #def _load_screen def updateScreen(self): self.table.clearContents() self.changed = [] while self.table.rowCount(): self.table.removeRow(0) config = self.getConfig() try: n4dclass = "RepoManager" n4dmethod = "list_default_repos" repos = self.n4dQuery(n4dclass, n4dmethod) if isinstance(repos, str): #It's a string, something went wrong. Perhaps a llx16 server? if (repos == "METHOD NOT ALLOWED FOR YOUR GROUPS"): #Server is a llx16 so switch to localhost self._debug("LLX16 server detected. Switch to localhost") self.errServer = True repos = self.n4dQuery(n4dclass, n4dmethod) if repos.get('status', 0) != -1: self.defaultRepos = repos.copy() except Exception as e: self._debug(self.n4dQuery(n4dclass, n4dmethod)) states = {} row = 0 for repo, data in self.defaultRepos.items(): self.table.insertRow(row) state = data.get('enabled', 'false') if state == 'true': state = True else: state = False description = data.get('desc', '') lbl = QLabelDescription(repo, _(description)) self.table.setCellWidget(row, 0, lbl) chk = QCheckBox() chk.setTristate(False) chk.setStyleSheet("margin-left:50%;margin-right:50%") chk.stateChanged.connect(lambda x: self.setChanged(True)) chk.stateChanged.connect(self.changeState) self.table.setCellWidget(row, 1, chk) chk.setChecked(state) row += 1 #def _udpate_screen def changeState(self): row = self.table.currentRow() repoWidget = self.table.cellWidget(row, 0) stateWidget = self.table.cellWidget(row, 1) if repoWidget == None: self._debug("Item not found at %s,%s" % (row, 0)) return repo = repoWidget.text()[0] #Check mirror if repo.lower() == "lliurex mirror": #Mirror must be checked against server ret = self.appConfig.n4dQuery("MirrorManager", "is_mirror_available") if isinstance(ret, dict): if ret.get('status') == -1: self._debug("Mirror not available") self.showMsg(_("Mirror not available"), 'RepoMan') self.defaultRepos[repo]['enabled'] = "False" self.updateScreen() return if (type(ret) == type("")): if ret != "Mirror available": self._debug("Mirror not available") self.showMsg(_("Mirror not available"), 'RepoMan') self.defaultRepos[repo]['enabled'] = "False" self.updateScreen() return elif not (ret.get('status', False)): self._debug("Mirror not available") self.showMsg(_("Mirror not available"), 'RepoMan') self.defaultRepos[repo]['enabled'] = "False" self.updateScreen() return state = str(stateWidget.isChecked()).lower() self.defaultRepos[repo]['enabled'] = "%s" % state if repo not in self.changed: self.changed.append(repo) #def changeState def writeConfig(self): ret = True for repo in self.changed: self._debug("Updating %s" % repo) ret = self.n4dQuery("RepoManager", "write_repo_json", {repo: self.defaultRepos[repo]}) if ret: ret = self.n4dQuery("RepoManager", "write_repo", {repo: self.defaultRepos[repo]}) if ret == False: self.showMsg( _("Couldn't write repo") + " {}".format(repo), 'error') else: self.showMsg( _("Couldn't write info for") + " {}".format(repo), 'error') if ret == True: self._updateRepos() self.updateScreen() #def writeConfig def _updateRepos(self): cursor = QtGui.QCursor(Qt.WaitCursor) self.setCursor(cursor) self._debug("Updating repos") ret = self.appConfig.n4dQuery("RepoManager", "update_repos") errList = [] for line in ret.split("\n"): if line.startswith("E: ") or line.startswith("W:"): for name, data in self.defaultRepos.items(): for repoLine in data.get('repos', []): repoItems = repoLine.split(" ") if repoItems: if repoItems[0] in line: if "NODATA" in line: continue err = " *{}".format(name) if err not in errList: errList.append(err) ret = ("\n").join(errList) if ret: #self.showMsg(_("Repositories updated succesfully")) self._debug("Error updating: %s" % ret) ret = _("Failed to update: ") + "\n" + "{}".format(ret) self.showMsg("{}".format(ret), 'RepoMan') self.refresh = True self.changes = False else: self.showMsg(_("Repositories updated succesfully")) cursor = QtGui.QCursor(Qt.PointingHandCursor) self.setCursor(cursor)
class YoutubeDnld(QDialog): def __init__(self): super().__init__() self.downloadName = '' self.downloadPercent = '' self.downloadSpeed = '' self.setWindowTitle('Youtube下载器 (此窗口可关闭至后台下载 支持断点下载 需要自备梯子)') self.resize(1000, 600) self.layout = QGridLayout() self.setLayout(self.layout) self.tipLabel = QLabel('Youtube链接:') self.layout.addWidget(self.tipLabel, 0, 0, 1, 2) self.urlInput = QLineEdit('请输入Youtube视频链接') self.layout.addWidget(self.urlInput, 0, 2, 1, 5) self.searchButton = QPushButton('查询') self.searchButton.clicked.connect(self.checkURL) self.layout.addWidget(self.searchButton, 0, 7, 1, 1) self.searchToken = False self.videoInfo = QTableWidget() self.videoInfo.verticalHeader().setHidden(True) self.videoInfo.setRowCount(10) self.videoInfo.setColumnCount(6) self.videoInfo.setColumnWidth(0, 100) self.videoInfo.setColumnWidth(1, 100) self.videoInfo.setColumnWidth(2, 100) self.videoInfo.setColumnWidth(3, 100) self.videoInfo.setColumnWidth(4, 100) self.videoInfo.setColumnWidth(5, 450) self.videoInfo.setHorizontalHeaderLabels(['序号', '后缀名', '分辨率', '码率', '类型', '备注']) self.layout.addWidget(self.videoInfo, 1, 0, 4, 8) self.dnldInput = QLineEdit() self.layout.addWidget(self.dnldInput, 5, 0, 1, 2) self.dnldLabel = QLabel('输入要下载的视频/音频序号,多个序号用空格隔开 ') self.layout.addWidget(self.dnldLabel, 5, 2, 1, 2) self.jaCheck = QPushButton('下载日语字幕(自动识别)') self.zhCheck = QPushButton('下载中文字幕(油管机翻)') self.thumbnailCheck = QPushButton('下载封面') self.jaCheck.setStyleSheet('background-color:#3daee9') self.zhCheck.setStyleSheet('background-color:#3daee9') self.thumbnailCheck.setStyleSheet('background-color:#3daee9') self.jaCheckStatus = True self.zhCheckStatus = True self.thumbnailCheckStatus = True self.jaCheck.clicked.connect(self.jaCheckClick) self.zhCheck.clicked.connect(self.zhCheckClick) self.thumbnailCheck.clicked.connect(self.thumbnailCheckClick) self.layout.addWidget(self.jaCheck, 5, 4, 1, 1) self.layout.addWidget(self.zhCheck, 5, 5, 1, 1) self.layout.addWidget(self.thumbnailCheck, 5, 6, 1, 1) self.savePath = QLineEdit() self.layout.addWidget(self.savePath, 6, 0, 1, 4) self.saveButton = QPushButton('保存路径') self.saveButton.setFixedWidth(115) self.saveButton.clicked.connect(self.setSavePath) self.layout.addWidget(self.saveButton, 6, 4, 1, 1) self.processInfo = QLabel() self.layout.addWidget(self.processInfo, 6, 5, 1, 2) self.progress = QProgressBar() self.layout.addWidget(self.progress, 7, 0, 1, 7) self.startButton = QPushButton('开始下载') self.startButton.setFixedWidth(140) self.startButton.setFixedHeight(120) self.startButton.setEnabled(False) self.startButton.clicked.connect(self.dnldStart) self.layout.addWidget(self.startButton, 5, 7, 3, 1) self.timer = QTimer() self.timer.setInterval(500) self.timer.start() self.timer.timeout.connect(self.dnldProgress) def jaCheckClick(self): self.jaCheckStatus = not self.jaCheckStatus if self.jaCheckStatus: self.jaCheck.setStyleSheet('background-color:#3daee9') else: self.jaCheck.setStyleSheet('background-color:#31363b') def zhCheckClick(self): self.zhCheckStatus = not self.zhCheckStatus if self.zhCheckStatus: self.zhCheck.setStyleSheet('background-color:#3daee9') else: self.zhCheck.setStyleSheet('background-color:#31363b') def thumbnailCheckClick(self): self.thumbnailCheckStatus = not self.thumbnailCheckStatus if self.thumbnailCheckStatus: self.thumbnailCheck.setStyleSheet('background-color:#3daee9') else: self.thumbnailCheck.setStyleSheet('background-color:#31363b') def checkURL(self): self.url = self.urlInput.text() if self.url: if '&' in self.url: self.url = self.url.split('&')[0] self.videoInfo.clearContents() self.dnldCheck = dnldCheck(self.url) self.dnldCheck.searchCnt.connect(self.refreshSearchButton) self.dnldCheck.checkStatus.connect(self.setCheckStatus) self.dnldCheck.videoTitle.connect(self.setTitle) self.dnldCheck.videoResults.connect(self.setVideoInfo) self.dnldCheck.start() def refreshSearchButton(self, cnt): if cnt: self.searchButton.setText('搜索中' + '.' * cnt) else: self.searchButton.setText('查询') def setCheckStatus(self, checkStatus): if not checkStatus: self.searchToken = False self.videoInfo.setItem(0, 5, QTableWidgetItem('无效的视频链接 请重新输入')) else: self.searchToken = True def setTitle(self, title): self.title = title self.urlInput.setText(title) def setVideoInfo(self, results): self.videoInfo.setRowCount(len(results) - 4) for y, l in enumerate(results[1:-3]): l = l.split(' ') while '' in l: l.remove('') if ',' in l: l.remove(',') if 'tiny' in l: l.remove('tiny') lineData = l[:2] if l[2] == 'audio': lineData.append('无') else: lineData.append('%s %s' % tuple(l[2:4])) lineData.append(l[4]) tip = '' for i in l[4:]: tip += i + ' ' if l[2] == 'audio': lineData.append('audio only') elif 'video only' in tip: lineData.append('video only') else: lineData.append('video + audio') lineData.append(tip[:-1]) for x, data in enumerate(lineData): self.videoInfo.setItem(y, x, QTableWidgetItem(data)) def setSavePath(self): savePath = QFileDialog.getExistingDirectory(self, '选择视频保存文件夹') if savePath: self.savePath.setText(savePath) def dnldProgress(self): if self.searchToken and self.dnldInput.text() and self.savePath.text(): self.startButton.setEnabled(True) else: self.startButton.setEnabled(False) def dnldStart(self): self.processInfo.setText('下载速度:') dnldNum = self.dnldInput.text().split(' ') videoType = [] resolution = [] for num in dnldNum: for y in range(self.videoInfo.rowCount()): if self.videoInfo.item(y, 0).text() == num: videoType.append(self.videoInfo.item(y, 1).text()) resolution.append(self.videoInfo.item(y, 2).text()) break savePath = self.savePath.text() ja = self.jaCheckStatus zh = self.zhCheckStatus if ja and zh: args = ['--write-auto-sub', '--sub-lang', 'ja,zh-Hans'] elif ja and not zh: args = ['--write-auto-sub', '--sub-lang', 'ja'] elif zh and not ja: args = ['--write-auto-sub', '--sub-lang', 'zh-Hans'] else: args = [] if self.thumbnailCheckStatus: args.append('--write-thumbnail') self.dnldThread = dnldThread(dnldNum, videoType, resolution, savePath, self.title, args, self.url) self.dnldThread.downloading.connect(self.dnldName) self.dnldThread.percent.connect(self.dnldPercent) self.dnldThread.done.connect(self.dnldFinish) self.dnldThread.start() def dnldName(self, name): self.savePath.setText(name) def dnldPercent(self, percent): if r'%' in percent: self.downloadPercent = percent.split(r'%')[0].split(' ')[-1] if 'B/s' in percent: self.downloadSpeed = percent.split('B/s')[0].split(' ')[-1] + 'B/s' self.processInfo.setText('下载速度:%s' % self.downloadSpeed) if self.downloadPercent: self.progress.setValue(float(self.downloadPercent)) def dnldFinish(self, done): self.processInfo.setText(done) self.progress.setValue(0)
class Window(QWidget): def __init__(self): super().__init__() self.setWindowTitle("Lab_8") self.setSize() self.setIcon() self.center() self.setButtons() self.Help_Button() self.Search_Button() self.setFontBox() self.Table() self.point = 0 self.point_check = 0 self.result = { "Системный номер", "random_name0", "random_fname0", "random_phone0", "928641057", "WeB_BackenD", "0118532866300" } self.back = False def center(self): qRect = self.frameGeometry() centerPoint = QDesktopWidget().availableGeometry().center() qRect.moveCenter(centerPoint) self.move(qRect.topLeft()) def setSize(self): self.setGeometry(0, 0, 800, 720) self.setMinimumHeight(720) self.setMinimumWidth(800) self.setMaximumHeight(720) self.setMaximumWidth(800) def setIcon(self): appIcon = QIcon("3.jpg") self.setWindowIcon(appIcon) def CreateNewDoc(self): number, ok = QInputDialog.getText(self, 'Input Dialog', 'Write Number:') if ok: name, ok = QInputDialog.getText(self, 'Input Dialog', 'Write name:') if ok: fname, ok = QInputDialog.getText(self, 'Input Dialog', 'Write fname:') if ok: phone, ok = QInputDialog.getText(self, 'Input Dialog', 'Write phone:') if ok: uid, ok = QInputDialog.getText(self, 'Input Dialog', 'Write uid:') if ok: nik, ok = QInputDialog.getText( self, 'Input Dialog', 'Write nik:') if ok: wo, ok = QInputDialog.getText( self, 'Input Dialog', 'Write wo:') if ok: post = { "Number": number, "name": name, "fname": fname, "phone": phone, "uid": uid, "nik": nik, "wo": wo } post_id = posts.insert_one( post).inserted_id def EdditDoc(self): pass def setButtons(self): Create_Doc = QPushButton("Create", self) Browse_Button = QPushButton("Browse", self) self.Stop_But = QPushButton("Stop Parsing", self) self.Update_Data = QPushButton("Update Data", self) Browse_Button.move(24, 649) Create_Doc.move(99, 649) self.Stop_But.move(174, 649) self.Update_Data.move(174, 624) self.Stop_But.setDisabled(True) self.Update_Data.setDisabled(True) Browse_Button.clicked.connect(self.File_path) Create_Doc.clicked.connect(self.CreateNewDoc) self.Update_Data.clicked.connect(self.change) def File_path(self): try: self.dialog = QFileDialog(self) self.path = self.dialog.getOpenFileName() self.fi = QFileInfo(self.path[0]) self.FileSize = self.fi.size() self.point -= 1 self.thread1 = Thread(target=parsing, args=(self.path[0], self.FileSize)) stop_threads = False self.thread1.start() time.sleep(0.5) QMessageBox.warning( self.Back, "Warning!", "База данных еще загружается, все функции кроме просмотра - заблокированы", buttons=QMessageBox.Ok) time.sleep(2) self.StopButton() self.TimerQ() except FileNotFoundError: pass def change(self): if self.alive(5) == 0: row = self.tableWidget.currentRow() column = self.tableWidget.currentColumn() value, ok = QInputDialog.getText(self, "Вввод нового значения", "Введите новое значение", QLineEdit.Normal, '') if value and ok: data = list() documents = list() copi_table = list() try: for r in range(0, 100): for c in range(0, 7): documents.append( self.tableWidget.item(r, c).text()) cpop_Table = { "Number": documents[0], "name": documents[1], "fname": documents[2], "phone": documents[3], "uid": documents[4], "nik": documents[5], "wo": documents[6] } copi_table.append(cpop_Table) documents = list() except AttributeError: pass for currentColum in range(7): item = self.tableWidget.item(row, currentColum).text() data.append(item) header = [ 'Number', 'name', 'fname', 'phone', 'uid', 'nik', 'wo' ] post = { "Number": data[0], "name": data[1], "fname": data[2], "phone": data[3], "uid": data[4], "nik": data[5], "wo": data[6] } posts.update_one(post, {"$set": { f'{header[column]}': f'{value}' }}) post[header[column]] = value copi_table[row] = post self.tableWidget.clearContents() j = 0 for i in copi_table: self.tableWidget.setItem(j, 0, QTableWidgetItem(i['Number'])) self.tableWidget.setItem(j, 1, QTableWidgetItem(i['name'])) self.tableWidget.setItem(j, 2, QTableWidgetItem(i['fname'])) self.tableWidget.setItem(j, 3, QTableWidgetItem(i['phone'])) self.tableWidget.setItem(j, 4, QTableWidgetItem(i['uid'])) self.tableWidget.setItem(j, 5, QTableWidgetItem(i['nik'])) self.tableWidget.setItem(j, 6, QTableWidgetItem(i['wo'])) j += 1 if j == 100: break else: QMessageBox.about(self, 'Ошибка', 'Введите данные.') def alive(self, Number): if self.thread1.is_alive(): QMessageBox.warning( self.Back, "Warning!", "База данных еще загружается, все функции кроме просмотра и создания - заблокированы", buttons=QMessageBox.Ok) else: if Number == 1: self.Stop_But.setDisabled(True) return 0 if Number == 2: self.Stop_But.setDisabled(True) return 0 if Number == 3: self.Stop_But.setDisabled(True) return 0 if Number == 4: self.Stop_But.setDisabled(True) return 0 if Number == 5: self.Stop_But.setDisabled(True) return 0 def StopButton(self): self.Stop_But.setDisabled(False) self.Stop_But.clicked.connect(self.stopped) def stopped(self): global stop_threads stop_threads = True self.Stop_But.setDisabled(True) QMessageBox.warning( self.Back, "Warning!", "Запись в базу данных остановлена. Чтение из файла прекращено", buttons=QMessageBox.Ok) def TimerQ(self): j = 0 self.result = posts.find() for i in self.result: if self.point == -1: if i: self.tableWidget.setItem(j, 0, QTableWidgetItem(i['Number'])) self.tableWidget.setItem(j, 1, QTableWidgetItem(i['name'])) self.tableWidget.setItem(j, 2, QTableWidgetItem(i['fname'])) self.tableWidget.setItem(j, 3, QTableWidgetItem(i['phone'])) self.tableWidget.setItem(j, 4, QTableWidgetItem(i['uid'])) self.tableWidget.setItem(j, 5, QTableWidgetItem(i['nik'])) self.tableWidget.setItem(j, 6, QTableWidgetItem(i['wo'])) j += 1 else: break if j == 100: self.point = 0 self.point_check = 100 break self.Update_Data.setDisabled(False) def Help_Button(self): self.aboutButton = QPushButton("Open About", self) self.aboutButton.move(701, 675) self.aboutButton.clicked.connect(self.aboutBox) def printfel(self, x): if x == 0: self.choose = x elif x == 1: self.choose = x elif x == 2: self.choose = x def Search_Button(self): self.Search_button = QPushButton("Accept and Search", self) self.Search_button.move(152, 674) self.Search_button.clicked.connect(self.Enter_nick) def Table(self): self.tableWidget = QTableWidget(self) self.tableWidget.setColumnCount(7) self.tableWidget.setRowCount(100) self.tableWidget.move(25, 7) self.tableWidget.setMinimumHeight(600) self.tableWidget.setMinimumWidth(750) self.tableWidget.setMaximumHeight(600) self.tableWidget.setMaximumWidth(750) self.tableWidget.setHorizontalHeaderLabels( ["Number", "name", "fname", "phone", "uid", "nik", "wo"]) self.NextButton_Back() def setTable(self): j = 0 print("start") self.tableWidget.clearContents() for i in self.result: self.tableWidget.setItem(j, 0, QTableWidgetItem(i['Number'])) self.tableWidget.setItem(j, 1, QTableWidgetItem(i['name'])) self.tableWidget.setItem(j, 2, QTableWidgetItem(i['fname'])) self.tableWidget.setItem(j, 3, QTableWidgetItem(i['phone'])) self.tableWidget.setItem(j, 4, QTableWidgetItem(i['uid'])) self.tableWidget.setItem(j, 5, QTableWidgetItem(i['nik'])) self.tableWidget.setItem(j, 6, QTableWidgetItem(i['wo'])) j += 1 if j == 100: break def NextButton_Back(self): self.Next = QPushButton("Next >>", self) self.Back = QPushButton("<< Back", self) self.Next.move(400, 610) self.Back.move(330, 610) self.Next.clicked.connect(self.point_plus) self.Back.clicked.connect(self.point_minus) def point_plus(self): if self.alive(1) == 0: self.point += 1 self.setTable() def point_minus(self): if self.alive(2) == 0: if self.point < 1: QMessageBox.warning(self.Back, "Warning!", "We cant go back", buttons=QMessageBox.Ok) else: self.point -= 1 self.back = True self.setTable() def search(self): #dont work need rework result = find_document(series_collection, {'name': 'FRIENDS'}) print(result) delete_document(series_collection, {'_id': id_}) def aboutBox(self): QMessageBox.about(self.aboutButton, "about menu", "https://www.youtube.com/watch?v=dQw4w9WgXcQ") def Enter_nick(self): if self.alive(3) == 0: if self.choose == 0: text, ok = QInputDialog.getText(self, 'Input Dialog', 'Search for nik:') elif self.choose == 1: text, ok = QInputDialog.getText(self, 'Input Dialog', 'Search for phone:') elif self.choose == 2: text, ok = QInputDialog.getText(self, 'Input Dialog', 'Search for fname:') if ok: if self.choose == 0: self.result = posts.find({"nik": str(text)}) elif self.choose == 1: self.result = posts.find({"phone": str(text)}) elif self.choose == 2: self.result = posts.find({"fname": str(text)}) msgBox = QtWidgets.QMessageBox() msgBox.setIcon(QtWidgets.QMessageBox.Information) msgBox.setText("Сохранить результат в файл?") msgBox.setWindowTitle("?") msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel) returnvalue = msgBox.exec() if returnvalue == QtWidgets.QMessageBox.Ok: text, ok = QInputDialog.getText(self, 'Input Dialog', 'Enter name file') self.save_file(text) else: msgBox = QtWidgets.QMessageBox() msgBox.setIcon(QtWidgets.QMessageBox.Information) msgBox.setText("Вывести результат в таблицу?") msgBox.setWindowTitle("?") msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel) returnvalue = msgBox.exec() if returnvalue == QtWidgets.QMessageBox.Ok: j = 0 self.Next.setDisabled(True) self.Back.setDisabled(True) self.tableWidget.clearContents() for i in self.result: self.tableWidget.setItem( j, 0, QTableWidgetItem(i['Number'])) self.tableWidget.setItem( j, 1, QTableWidgetItem(i['name'])) self.tableWidget.setItem( j, 2, QTableWidgetItem(i['fname'])) self.tableWidget.setItem( j, 3, QTableWidgetItem(i['phone'])) self.tableWidget.setItem( j, 4, QTableWidgetItem(i['uid'])) self.tableWidget.setItem( j, 5, QTableWidgetItem(i['nik'])) self.tableWidget.setItem(j, 6, QTableWidgetItem(i['wo'])) j += 1 if j == 100: break def save_file(self, text): with open(text, "w", encoding="UTF-8") as file: result = self.result for i in result: string = "" string = string + str(i['Number']) + "|" + str( i['name']) + "|" + str(i['fname']) + "|" + str( i['phone']) + "|" + str(i['uid']) + "|" + str( i['nik']) + "|" + str(i['wo'] + "\n") file.write(string) msgBox = QtWidgets.QMessageBox() msgBox.setIcon(QtWidgets.QMessageBox.Information) msgBox.setText("Вывести результат в таблицу?") msgBox.setWindowTitle("?") msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel) returnvalue = msgBox.exec() if returnvalue == QtWidgets.QMessageBox.Ok: j = 0 self.Next.setDisabled(True) self.Back.setDisabled(True) self.tableWidget.clearContents() for i in self.result: self.tableWidget.setItem(j, 0, QTableWidgetItem(i['Number'])) self.tableWidget.setItem(j, 1, QTableWidgetItem(i['name'])) self.tableWidget.setItem(j, 2, QTableWidgetItem(i['fname'])) self.tableWidget.setItem(j, 3, QTableWidgetItem(i['phone'])) self.tableWidget.setItem(j, 4, QTableWidgetItem(i['uid'])) self.tableWidget.setItem(j, 5, QTableWidgetItem(i['nik'])) self.tableWidget.setItem(j, 6, QTableWidgetItem(i['wo'])) j += 1 if j == 100: break def setFontBox(self): cbox = QComboBox(self) tables = ("Поиск по нику", "Поиск по телефону", "Поиск по фамилии") cbox.addItems(tables) cbox.move(25, 676) cbox.currentIndexChanged.connect(self.printfel)
class customRepos(confStack): def __init_stack__(self): self.dbg=False self._debug("confDefault Load") self.menu_description=(_("Manage custom repositories")) self.description=(_("Custom repositories")) self.icon=('menu_new') self.tooltip=(_("From here you can manage your custom repositories")) self.index=2 self.enabled=True self.defaultRepos={} self.level='user' self.changed=[] #def __init__ def _load_screen(self): box=QVBoxLayout() info=QWidget() infoBox=QHBoxLayout() lbl_txt=QLabel(_("Manage extra repositories")) lbl_txt.setAlignment(Qt.AlignTop) infoBox.addWidget(lbl_txt,1) icn_add=QtGui.QIcon().fromTheme('document-new') btn_add=QPushButton() btn_add.clicked.connect(self._addRepo) btn_add.setIcon(icn_add) btn_add.setToolTip(_("Add new repository")) infoBox.addWidget(btn_add,0) info.setLayout(infoBox) box.addWidget(info,0) self.table=QTableWidget(1,2) Hheader=self.table.horizontalHeader() Vheader=self.table.verticalHeader() Hheader.setSectionResizeMode(0,QHeaderView.Stretch) Vheader.setSectionResizeMode(QHeaderView.ResizeToContents) self.table.setShowGrid(False) self.table.setSelectionBehavior(QTableWidget.SelectRows) self.table.setSelectionMode(QTableWidget.NoSelection) self.table.setEditTriggers(QTableWidget.NoEditTriggers) self.table.horizontalHeader().hide() self.table.verticalHeader().hide() box.addWidget(self.table) self.setLayout(box) self.updateScreen() #def _load_screen def updateScreen(self): self.table.clearContents() self.changed=[] while self.table.rowCount(): self.table.removeRow(0) config=self.getConfig() repos=self.appConfig.n4dQuery("RepoManager","list_sources") if isinstance(repos,str): #It's a string, something went wrong. Perhaps a llx16 server? #Server is a llx16 so switch to localhost self._debug("LLX16 server detected. Switch to localhost") self.appConfig.n4d.server='localhost' self.appConfig.n4d.n4dClient=None repos=self.appConfig.n4dQuery("RepoManager","list_sources") elif isinstance(repos,dict): status=repos.get('status',None) if status!=0 and status!=None: self.showMsg(_("N4d is down. Check the state of N4d server")) return self.defaultRepos=repos.copy() states={} row=0 orderedKeys=sorted(self.defaultRepos,key=str.casefold) for repo in orderedKeys: data=self.defaultRepos[repo] self.table.insertRow(row) state=data.get('enabled','false').lower() if state=='true': state=True else: state=False description=data.get('desc','') lbl=QLabelDescription(repo,description) locked=data.get('protected','false') locked=str(locked).lower() lbl.click_on.connect(self.editRepo) if locked=='false': lbl.showEdit() if not state: lbl.stateEdit(False) self.table.setCellWidget(row,0,lbl) chk=QCheckBox() chk.setStyleSheet("margin-left:50%;margin-right:50%") chk.stateChanged.connect(lambda x:self.setChanged(True)) chk.stateChanged.connect(self.changeState) self.table.setCellWidget(row,1,chk) chk.setChecked(state) row+=1 #def _update_screen def editRepo(self,repo,*args): sfile=repo.replace(' ','_') self._debug("Editing {}.list".format(sfile)) fpath="{}.list".format(os.path.join(APT_SRC_DIR,sfile)) if os.path.isfile(fpath) or os.path.isfile(fpath.lower()): if os.path.isfile(fpath.lower()): fpath=fpath.lower() edit=True try: display=os.environ['DISPLAY'] subprocess.run(["xhost","+"]) subprocess.run(["pkexec","scite",fpath],check=True) subprocess.run(["xhost","-"]) except Exception as e: self._debug("_edit_source_file error: %s"%e) edit=False if edit: newrepos=[] wrkfile=os.path.join(APT_SRC_DIR,"{}.list".format(sfile)) if not os.path.isfile(wrkfile): wrkfile=wrkfile.lower() try: with open(wrkfile,'r') as f: for line in f: newrepos.append(line.strip()) except Exception as e: self._debug("_edit_source_file failed: {}".format(e)) if sorted(self.defaultRepos[repo]['repos'])!=sorted(newrepos): self.defaultRepos[repo]['repos']=newrepos self.appConfig.n4dQuery("RepoManager","write_repo_json",{repo:self.defaultRepos[repo]}) self._updateRepos() else: self._debug("File {} not found".format(fpath)) #def _edit_source_file def changeState(self): row=self.table.currentRow() repoWidget=self.table.cellWidget(row,0) stateWidget=self.table.cellWidget(row,1) if repoWidget==None: self._debug("Item not found at {},0".format(row)) return repo=repoWidget.text()[0] state=str(stateWidget.isChecked()).lower() self.defaultRepos[repo]['enabled']="%s"%state if repo not in self.changed: self.changed.append(repo) #def changeState(self) def _addRepo(self): self.stack.gotoStack(idx=4,parms="") #def _addRepo def writeConfig(self): ret=True for repo in self.changed: self._debug("Updating {}".format(repo)) self._debug("Updating %s"%self.defaultRepos[repo]) ret=self.appConfig.n4dQuery("RepoManager","write_repo_json",{repo:self.defaultRepos[repo]}) if ret: ret=self.appConfig.n4dQuery("RepoManager","write_repo",{repo:self.defaultRepos[repo]}) if ret==False: self.showMsg(_("Couldn't write repo")+" {}".format(repo),'error') else: self.showMsg(_("Couldn't write info for")+" {}".format(repo),'error') if ret==True: self._updateRepos() self.updateScreen() #def writeConfig def _updateRepos(self): cursor=QtGui.QCursor(Qt.WaitCursor) self.setCursor(cursor) self._debug("Updating repos") ret=self.appConfig.n4dQuery("RepoManager","update_repos") errList=[] for line in ret.split("\n"): if line.startswith("E: ") or line.startswith("W:"): for name,data in self.defaultRepos.items(): for repoLine in data.get('repos',[]): repoItems=repoLine.split(" ") if repoItems: if repoItems[0] in line: err=" *{}".format(name) if err not in errList: errList.append(err) ret=("\n").join(errList) if ret: #self.showMsg(_("Repositories updated succesfully")) self._debug("Error updating: {}".format(ret)) ret=_("Failed to update: ")+"\n"+"{}".format(ret) self.showMsg("{}".format(ret),'RepoMan') self.refresh=True self.changes=False else: self.showMsg(_("Repositories updated succesfully")) cursor=QtGui.QCursor(Qt.PointingHandCursor) self.setCursor(cursor)