コード例 #1
0
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()
コード例 #2
0
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)
コード例 #3
0
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"))
コード例 #4
0
ファイル: main.py プロジェクト: willnix/trine2browser
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)
コード例 #5
0
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
コード例 #6
0
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_()
コード例 #7
0
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_()
コード例 #8
0
    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)
コード例 #9
0
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
コード例 #10
0
ファイル: defaultRepos.py プロジェクト: lliurex/repoman
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)
コード例 #11
0
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)
コード例 #12
0
ファイル: Lab_8.py プロジェクト: avocadik28/HomeWorks
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)
コード例 #13
0
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)