Beispiel #1
0
    def create_widgets(self):
        """ Setup the widgets for the solver window """
        tk.Label(self,
                 text=self.solver.cipher_name + " - Guess Decryption Key",
                 **TITLE_LABEL_OPTIONS).grid(row=0, column=0)
        # back button
        tk.Button(self, text="Back", command=self.go_back).grid(row=0,
                                                                column=1,
                                                                sticky="NE")
        # stop button
        self.stop_button = tk.Button(self,
                                     text="Stop",
                                     command=self.stop_solver)
        self.stop_button.grid(row=3, column=1, sticky="NE")
        # progress bar
        tk.Label(self, text="Progress",
                 **SUBTITLE_LABEL_OPTIONS).grid(row=3, column=0)
        self.progress_bar = ProgressBar(self)
        self.progress_bar.grid(row=4, column=0, sticky="NSEW")
        # set the first column to be expandable
        self.grid_columnconfigure(0, weight=1)

        # setup the output scroll frame
        tk.Label(self, text="Outputs", **SUBTITLE_LABEL_OPTIONS).grid(row=1,
                                                                      column=0)
        self.outputs_scroll_frame = ScrollFrame(self)
        self.outputs_scroll_frame.grid(row=2, column=0, sticky="NSEW")
        self.outputs_inner_frame = self.outputs_scroll_frame.inner_frame
        # setup headings in the output scroll frame
        tk.Label(self.outputs_inner_frame, text="Score").grid(row=0,
                                                              column=0,
                                                              padx=10)
        tk.Label(self.outputs_inner_frame,
                 text="Decryption Key").grid(row=0, column=1, padx=10)
        tk.Label(self.outputs_inner_frame, text="Text").grid(row=0, column=2)
Beispiel #2
0
 def __init__(self, screen_manager, keyboard_manager, disp):
     super(ContrastScreen, self).__init__(screen_manager, keyboard_manager)
     self._disp = disp
     self._contrast = 0xCF  # initial value from SSD1306.py
     self._pbar = ProgressBar((0, 25), (128, 14), 255)
     self._pbar.set_value(0xCF)
     font = fonts.DEFAULT_FONT_12
     self._label = ScrollingText((25, 5), (100, 15), font, 'Contrast')
Beispiel #3
0
    def addCsv(self, filename, updateProgress=None):
        progress = ProgressBar("Adding nodes...", self.mainWindow)
        try:

            with open(filename, encoding="UTF-8-sig") as csvfile:
                rows = csv.DictReader(csvfile, delimiter=';', quotechar='"', doublequote=True)
                self.mainWindow.tree.treemodel.addSeedNodes(rows, progress=updateProgress)
                self.mainWindow.tree.selectLastRow()

            self.mainWindow.tree.selectLastRow()
        finally:
            progress.close()
    def exportSelectedNodes(self, output):
        progress = ProgressBar("Exporting data...", self.mainWindow)

        #indexes = self.mainWindow.tree.selectionModel().selectedRows()
        #if child nodes should be exported as well, uncomment this line an comment the previous one
        indexes = self.mainWindow.tree.selectedIndexesAndChildren()
        indexes = list(indexes)
        progress.setMaximum(len(indexes))

        try:
            delimiter = self.optionSeparator.currentText()
            delimiter = delimiter.encode('utf-8').decode('unicode_escape')
            writer = csv.writer(output,
                                delimiter=delimiter,
                                quotechar='"',
                                quoting=csv.QUOTE_ALL,
                                doublequote=True,
                                lineterminator='\r\n')

            #headers
            row = [
                str(val)
                for val in self.mainWindow.tree.treemodel.getRowHeader()
            ]
            if self.optionLinebreaks.isChecked():
                row = [
                    val.replace('\n', ' ').replace('\r', ' ') for val in row
                ]
            row = ['path'] + row
            writer.writerow(row)

            #rows
            path = []
            for index in indexes:
                if progress.wasCanceled:
                    break

                # data
                rowdata = self.mainWindow.tree.treemodel.getRowData(index)

                # path of parents (#2=level;#3=object ID)
                while rowdata[2] < len(path):
                    path.pop()
                path.append(rowdata[3])

                # values
                row = [str(val) for val in rowdata]
                row = ["/".join(path)] + row
                if self.optionLinebreaks.isChecked():
                    row = [
                        val.replace('\n', ' ').replace('\r', ' ')
                        for val in row
                    ]

                writer.writerow(row)

                progress.step()

        finally:
            progress.close()
Beispiel #5
0
    def clipboardNodes(self):
        progress = ProgressBar("Copy to clipboard", self.mainWindow)

        indexes = self.mainWindow.tree.selectionModel().selectedRows()
        progress.setMaximum(len(indexes))

        output = io.StringIO()
        try:
            writer = csv.writer(output, delimiter='\t', quotechar='"', quoting=csv.QUOTE_ALL, doublequote=True,
                                lineterminator='\r\n')

            #headers
            row = [str(val) for val in self.mainWindow.tree.treemodel.getRowHeader()]
            writer.writerow(row)

            #rows
            for no in range(len(indexes)):
                if progress.wasCanceled:
                    break

                row = [str(val) for val in self.mainWindow.tree.treemodel.getRowData(indexes[no])]
                writer.writerow(row)

                progress.step()

            clipboard = QApplication.clipboard()
            clipboard.setText(output.getvalue())
        finally:
            output.close()
            progress.close()
Beispiel #6
0
 def __init__(self, screen_manager, keyboard_manager, contrast_screen):
     super(WidgetsTestScreen, self).__init__(screen_manager,
                                             keyboard_manager)
     font = fonts.DEFAULT_FONT_12
     self._val = 0
     self._pbar = ProgressBar((0, 30), (40, 10), 100)
     self._tlist = TextList((45, 5), (80, 55), font, "no playlists")
     self._tlist.set_draw_border(True)
     self._tlist.set_items([
         "one one one one", "two two two two", "three three three three",
         "four", "five"
     ])
     self._stext = ScrollingText((0, 0), (40, 20), font, u'Hello::Привет!')
     self._stext.set_invert(True)
     self._status = PlayingWidget((5, 45), (15, 15))
     # self._status.set_draw_border(True)
     self._contrast_screen = contrast_screen
Beispiel #7
0
class WidgetsTestScreen(Screen):
    def __init__(self, screen_manager, keyboard_manager, contrast_screen):
        super(WidgetsTestScreen, self).__init__(screen_manager,
                                                keyboard_manager)
        font = fonts.DEFAULT_FONT_12
        self._val = 0
        self._pbar = ProgressBar((0, 30), (40, 10), 100)
        self._tlist = TextList((45, 5), (80, 55), font, "no playlists")
        self._tlist.set_draw_border(True)
        self._tlist.set_items([
            "one one one one", "two two two two", "three three three three",
            "four", "five"
        ])
        self._stext = ScrollingText((0, 0), (40, 20), font, u'Hello::Привет!')
        self._stext.set_invert(True)
        self._status = PlayingWidget((5, 45), (15, 15))
        # self._status.set_draw_border(True)
        self._contrast_screen = contrast_screen

    def on_keyboard_event(self, buttons_pressed):
        if buttons_pressed == [KeyboardManager.UP]:
            self._tlist.select_previous()
        elif buttons_pressed == [KeyboardManager.DOWN]:
            self._tlist.select_next()
        elif buttons_pressed == [KeyboardManager.LEFT]:
            self._val = max(0, self._val - 5)
            self._pbar.set_value(self._val)
        elif buttons_pressed == [KeyboardManager.RIGHT]:
            self._val = min(100, self._val + 5)
            self._pbar.set_value(self._val)
        elif buttons_pressed == [KeyboardManager.CENTER]:
            logging.debug("selected: %s" % str(self._tlist.selected))
            self._status.set_status(PlayingWidget.PLAYING)
        elif buttons_pressed == [KeyboardManager.A]:
            logging.debug("Dimming")
            self._screen_manager.dim()
            self._status.set_status(PlayingWidget.STOPPED)
        elif buttons_pressed == [KeyboardManager.B]:
            logging.debug("Undimming")
            self._screen_manager.undim()
            self._status.set_status(PlayingWidget.PAUSED)
        elif buttons_pressed == [KeyboardManager.A, KeyboardManager.B]:
            self._screen_manager.set_screen(self._contrast_screen)

    def widgets(self):
        return [self._pbar, self._tlist, self._stext, self._status]
Beispiel #8
0
    def __init__(self, screen_manager, keyboard_manager, client, status_screen, volmgr):
        super(MainScreen, self).__init__(screen_manager, keyboard_manager)
        self._client = client
        self._status_screen = status_screen
        self._volmgr = volmgr

        font = fonts.DEFAULT_FONT_14

        self._status = PlayingWidget((0, 0), (9, 9))
        self._seekbar = ProgressBar((24, 1), (128 - 24, 7), 100)

        self._artist = ScrollingText((0, 12), (128, 16), font, u'')

        self._title = ScrollingText((0, 32), (128, 16), font, u'')

        self._volume = ProgressBar((0, 54), (128, 7), 100)

        self._play_list_screen = PlayListsScreen(screen_manager, keyboard_manager, client)

        self._last_update = time.time()
Beispiel #9
0
    def __init__(self, QWidgetParent=None):
        QMainWindow.__init__(self, QWidgetParent)
        self._set_main_window()
        self.centralwidget = QWidget(self)

        layout = QVBoxLayout(self.centralwidget)
        layout.setContentsMargins(0, 0, 2, 0)
        layout.setSpacing(0)

        # query frame
        self.frame_query = QueryFrame()
        self._set_frame()
        layout.addWidget(self.frame_query)

        self.setCentralWidget(self.centralwidget)

        # status bar
        self.statusbar = QStatusBar(self)
        self._set_status_bar()
        self.setStatusBar(self.statusbar)

        self.progress_bar = ProgressBar(self)
        self.statusbar.addPermanentWidget(self.progress_bar)
        self.progress_bar.setVisible(False)

        self.dw_top = DockWidget(460, 90, 20000, 50)
        self.dw_top.setTitleBarWidget(QWidget())
        self.dwc_top = DockWidgetContentsTop()
        self.dw_top.setWidget(self.dwc_top)
        self.addDockWidget(QtCore.Qt.TopDockWidgetArea, self.dw_top)

        # dockwidget collection (left side)
        self.dw_collections = DockWidget(350, 620, 700, 20000)
        self.dw_collections.setTitleBarWidget(QWidget())
        self.dwc_left = DockWidgetContentsLeft(self)
        self.dw_collections.setWidget(self.dwc_left)
        self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.dw_collections)

        QtCore.QMetaObject.connectSlotsByName(self)
Beispiel #10
0
    def exportAllNodes(self,output):
        progress = ProgressBar("Exporting data...", self.mainWindow)
        progress.setMaximum(Node.query.count())

        try:
            delimiter = self.optionSeparator.currentText()
            delimiter = delimiter.encode('utf-8').decode('unicode_escape')
            writer = csv.writer(output, delimiter=delimiter, quotechar='"',
                                quoting=csv.QUOTE_ALL, doublequote=True,
                                lineterminator='\r\n')

            # Headers
            row = ["level", "id", "parent_id", "object_id", "object_type","object_key",
                   "query_status", "query_time", "query_type"]
            for key in extractNames(self.mainWindow.tree.treemodel.customcolumns):
                row.append(key)
            if self.optionLinebreaks.isChecked():
                row = [val.replace('\n', ' ').replace('\r',' ') for val in row]
            writer.writerow(row)

            # Rows
            page = 0
            while not progress.wasCanceled:
                allnodes = Node.query.offset(page * 5000).limit(5000)
                if allnodes.count() == 0:
                    break

                for node in allnodes:
                    if progress.wasCanceled:
                        break

                    row = [node.level, node.id, node.parent_id, node.objectid,
                           node.objecttype,getDictValue(node.queryparams,'nodedata'),
                           node.querystatus, node.querytime, node.querytype]
                    for key in self.mainWindow.tree.treemodel.customcolumns:
                        row.append(node.getResponseValue(key)[1])

                    if self.optionLinebreaks.isChecked():
                        row = [str(val).replace('\n', ' ').replace('\r',' ') for val in row]

                    writer.writerow(row)

                    # Step the bar
                    progress.step()

                page += 1

        finally:
            progress.close()
Beispiel #11
0
class ContrastScreen(Screen):
    def __init__(self, screen_manager, keyboard_manager, disp):
        super(ContrastScreen, self).__init__(screen_manager, keyboard_manager)
        self._disp = disp
        self._contrast = 0xCF  # initial value from SSD1306.py
        self._pbar = ProgressBar((0, 25), (128, 14), 255)
        self._pbar.set_value(0xCF)
        font = fonts.DEFAULT_FONT_12
        self._label = ScrollingText((25, 5), (100, 15), font, 'Contrast')

    def on_keyboard_event(self, buttons_pressed):
        if buttons_pressed == [KeyboardManager.LEFT]:
            self._contrast = max(0, self._contrast - 5)
        elif buttons_pressed == [KeyboardManager.RIGHT]:
            self._contrast = min(255, self._contrast + 5)
        elif buttons_pressed == [KeyboardManager.CENTER]:
            self._screen_manager.pop_screen()

        logging.debug("setting contrast to %d", self._contrast)
        self._disp.set_contrast(self._contrast)
        self._pbar.set_value(self._contrast)

    def widgets(self):
        return [self._pbar, self._label]
Beispiel #12
0
    def addAllColumns(self):
        progress = ProgressBar("Analyzing data...", self.mainWindow)
        columns = self.mainWindow.fieldList.toPlainText().splitlines()
        try:
            indexes = self.mainWindow.tree.selectedIndexesAndChildren()
            indexes = list(indexes)
            progress.setMaximum(len(indexes))

            for no in range(len(indexes)):
                progress.step()
                item = indexes[no].internalPointer()
                columns.extend([key for key in recursiveIterKeys(item.data['response']) if not key in columns])
                if progress.wasCanceled:
                    break
        finally:
            self.mainWindow.fieldList.setPlainText("\n".join(columns))
            self.mainWindow.tree.treemodel.setCustomColumns(columns)

            progress.close()
Beispiel #13
0
    def deleteNodes(self):

        reply = QMessageBox.question(self.mainWindow, 'Delete Nodes', "Are you sure to delete all selected nodes?",
                                     QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply != QMessageBox.Yes:
            return

        progress = ProgressBar("Deleting data...", self.mainWindow)

        self.mainWindow.tree.setUpdatesEnabled(False)
        try:
            todo = self.mainWindow.tree.selectedIndexesAndChildren({'persistent': True})
            todo = list(todo)
            progress.setMaximum(len(todo))
            for index in todo:
                progress.step()
                self.mainWindow.tree.treemodel.deleteNode(index, delaycommit=True)
                if progress.wasCanceled:
                    break
        finally:
            # commit the operation on the db-layer afterwards (delaycommit is True)
            self.mainWindow.tree.treemodel.commitNewNodes()
            self.mainWindow.tree.setUpdatesEnabled(True)
            progress.close()
class DataViewer(QDialog):
    def __init__(self, parent=None):
        super(DataViewer, self).__init__(parent)

        # Main window
        self.mainWindow = parent
        self.setWindowTitle("Extract Data")
        self.setMinimumWidth(400)

        # layout
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        self.extractLayout = QFormLayout()
        layout.addLayout(self.extractLayout)

        # Extract key input
        self.input_extract = QLineEdit()
        self.input_extract.setFocus()
        self.input_extract.textChanged.connect(self.delayPreview)
        self.extractLayout.addRow("Key to extract:",self.input_extract)

        # Object ID key input
        self.input_id = QLineEdit()
        self.input_id.textChanged.connect(self.delayPreview)
        self.extractLayout.addRow("Key for Object ID:", self.input_id)

        # Options
        optionsLayout = QHBoxLayout()
        self.extractLayout.addRow(optionsLayout)

        self.allnodesCheckbox = QCheckBox("Select all nodes")
        self.allnodesCheckbox.setToolTip(wraptip("Check if you want to extract data for all nodes."))
        self.allnodesCheckbox.setChecked(False)
        optionsLayout.addWidget(self.allnodesCheckbox)

        self.levelEdit=QSpinBox()
        self.levelEdit.setMinimum(1)
        self.levelEdit.setToolTip(wraptip("Based on the selected nodes, only extract data for nodes and subnodes of the specified level (base level is 1)"))
        self.levelEdit.valueChanged.connect(self.delayPreview)
        optionsLayout.addWidget(QLabel("Node level"))
        optionsLayout.addWidget(self.levelEdit)

        self.objecttypeEdit = QLineEdit("offcut")
        self.objecttypeEdit.setToolTip(wraptip("Skip nodes with these object types."))
        self.objecttypeEdit.textChanged.connect(self.delayPreview)
        optionsLayout.addWidget(QLabel("Exclude object types"))
        optionsLayout.addWidget(self.objecttypeEdit)
        #self.extractLayout.addRow("Exclude object types", self.objecttypeEdit)


        # Preview toggle
        previewLayout = QHBoxLayout()
        layout.addLayout(previewLayout)
        self.togglePreviewCheckbox = QCheckBox()
        self.togglePreviewCheckbox .setCheckState(Qt.Checked)
        self.togglePreviewCheckbox.setToolTip(wraptip("Check to see a dumped preview of the value"))
        self.togglePreviewCheckbox.stateChanged.connect(self.showPreview)
        previewLayout.addWidget(self.togglePreviewCheckbox)

        self.previewTimer = QTimer()
        self.previewTimer.timeout.connect(self.showPreview)
        self.previewTimer.setSingleShot(True)

        self.togglePreviewLabel = QLabel("Preview")
        previewLayout.addWidget(self.togglePreviewLabel)
        previewLayout.addStretch()

        # Data
        self.dataEdit = QTextEdit(self)
        self.dataEdit.setReadOnly(True)
        self.dataEdit.setMinimumHeight(400)
        layout.addWidget(self.dataEdit)

        # Buttons
        buttons = QDialogButtonBox(QDialogButtonBox.Apply | QDialogButtonBox.Close)
        buttons.button(QDialogButtonBox.Apply).clicked.connect(self.createNodes)
        buttons.button(QDialogButtonBox.Close).clicked.connect(self.close)
        layout.addWidget(buttons)

    def showValue(self, key = ''):
        self.input_extract.setText(key)
        #self.input_id.setText(key)

        self.allnodesCheckbox.setChecked(self.mainWindow.allnodesCheckbox.isChecked())
        self.levelEdit.setValue(self.mainWindow.levelEdit.value())
        self.objecttypeEdit.setText(self.mainWindow.typesEdit.text())

        self.show()
        self.raise_()

    @Slot()
    def delayPreview(self):
        self.previewTimer.stop()
        self.previewTimer.start(500)

    def updateNode(self, current):
        self.delayPreview()
        if current.isValid():
            level = current.model().getLevel(current) + 1
            self.levelEdit.setValue(level)

    @Slot()
    def showPreview(self):
        if self.togglePreviewCheckbox.isChecked():
            try:
                # Get nodes
                key_nodes = self.input_extract.text()
                subkey = key_nodes.split('|').pop(0).rsplit('.', 1)[0]
                key_id = self.input_id.text()
                #selected = self.mainWindow.tree.selectionModel().selectedRows()

                objecttypes = self.objecttypeEdit.text().replace(' ', '').split(',')
                level = self.levelEdit.value() - 1
                conditions = {'filter': {'level': level, '!objecttype': objecttypes}}
                selected = self.mainWindow.tree.selectedIndexesAndChildren(conditions)

                nodes = []
                for item in selected:
                    if not item.isValid():
                        continue
                    treenode = item.internalPointer()
                    dbnode = treenode.dbnode()
                    if dbnode is not None:
                        name, nodes = extractValue(dbnode.response, key_nodes, dump=False)
                    break

                # Dump nodes
                value = []
                nodes = [nodes] if not (type(nodes) is list) else nodes

                for n in nodes:
                    nodedata = json.dumps(n) if isinstance(n, Mapping) else n

                    n = n if isinstance(n, Mapping) else {subkey: n}
                    objectid = extractValue(n, key_id, default=None)[1] if key_id != '' else ''

                    value.append((str(objectid), str(nodedata)))
            except Exception as e:
                value = [('',str(e))]

            value = ['<b>{}</b><p>{}</p><hr>'.format(html.escape(x),html.escape(y)) for x,y in value]
            value = "\n\n".join(value)

            self.dataEdit.setHtml(value)

        self.dataEdit.setVisible(self.togglePreviewCheckbox.isChecked())
        if not self.togglePreviewCheckbox.isChecked():
            self.adjustSize()
        self.show()

    def initProgress(self):
        self.progressBar = ProgressBar("Extracting data...", self.mainWindow)
        self.progressTotal = None
        self.progressLevel = None
        self.progressUpdate = datetime.now()

    def updateProgress(self,current, total, level=0):
        if datetime.now() >= self.progressUpdate:
            if (self.progressLevel is None) or (level < self.progressLevel):
                self.progressLevel = level
                self.progressTotal = total

            if (level == self.progressLevel) or (total > self.progressTotal):
                self.progressBar.setMaximum(total)
                self.progressBar.setValue(current)
                self.progressUpdate = datetime.now() + timedelta(milliseconds=50)

            QApplication.processEvents()

        return not self.progressBar.wasCanceled

    def finishProgress(self):
        self.progressBar.close()

    @Slot()
    def createNodes(self):
        key_nodes = self.input_extract.text()
        key_objectid = self.input_id.text()
        if key_nodes == '':
            return False
        if key_objectid == '':
            key_objectid = None

        try:
            self.initProgress()
            objecttypes = self.objecttypeEdit.text().replace(' ', '').split(',')
            level = self.levelEdit.value() - 1
            allnodes = self.allnodesCheckbox.isChecked()
            conditions = {'filter': {'level': level, '!objecttype': objecttypes},
                          'selectall': allnodes}
            selected = self.mainWindow.tree.selectedIndexesAndChildren(conditions, self.updateProgress)

            for item in selected:
                if self.progressBar.wasCanceled:
                    break
                if not item.isValid():
                    continue
                treenode = item.internalPointer()
                treenode.unpackList(key_nodes, key_objectid, delaycommit=True)
        except Exception as e:
            self.mainWindow.logmessage(e)
        finally:
            self.mainWindow.tree.treemodel.commitNewNodes()
            self.finishProgress()

        #self.close()
        return True
Beispiel #15
0
    def __init__(self, parent=None):
        super(PresetWindow, self).__init__(parent)

        self.mainWindow = parent
        self.setWindowTitle("Presets")
        self.setMinimumWidth(800)
        self.setMinimumHeight(600)

        #layout
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        #loading indicator
        self.loadingLock = threading.Lock()
        self.loadingIndicator = QLabel('Loading...please wait a second.')
        self.loadingIndicator.hide()
        layout.addWidget(self.loadingIndicator)

        #Middle
        central = QSplitter(self)
        layout.addWidget(central, 1)

        #list view
        self.presetList = QTreeWidget(self)
        self.presetList.setHeaderHidden(True)
        self.presetList.setColumnCount(1)
        self.presetList.setIndentation(15)
        self.presetList.itemSelectionChanged.connect(self.currentChanged)
        central.addWidget(self.presetList)
        central.setStretchFactor(0, 0)

        # category / pipeline
        self.categoryWidget = QWidget()
        p = self.categoryWidget.palette()
        p.setColor(self.categoryWidget.backgroundRole(), Qt.white)
        self.categoryWidget.setPalette(p)
        self.categoryWidget.setAutoFillBackground(True)

        self.categoryLayout = QVBoxLayout()
        #self.categoryLayout.setContentsMargins(0, 0, 0, 0)
        self.categoryWidget.setLayout(self.categoryLayout)

        self.categoryView = QScrollArea()
        self.categoryView.setWidgetResizable(True)
        self.categoryView.setWidget(self.categoryWidget)
        central.addWidget(self.categoryView)
        central.setStretchFactor(1, 2)

        # Pipeline header
        self.pipelineName = QLabel('')
        self.pipelineName.setWordWrap(True)
        self.pipelineName.setStyleSheet("QLabel  {font-size:15pt;}")
        self.categoryLayout.addWidget(self.pipelineName)

        # Pipeline items
        # self.pipelineWidget = QTreeWidget()
        # self.pipelineWidget.setIndentation(0)
        # self.pipelineWidget.setUniformRowHeights(True)
        # self.pipelineWidget.setColumnCount(4)
        # self.pipelineWidget.setHeaderLabels(['Name','Module','Basepath','Resource'])
        # self.categoryLayout.addWidget(self.pipelineWidget)

        # preset widget
        self.presetWidget = QWidget()

        p = self.presetWidget.palette()
        p.setColor(self.presetWidget.backgroundRole(), Qt.white)
        self.presetWidget.setPalette(p)
        self.presetWidget.setAutoFillBackground(True)

        #self.presetWidget.setStyleSheet("background-color: rgb(255,255,255);")
        self.presetView = QScrollArea()
        self.presetView.setWidgetResizable(True)
        self.presetView.setWidget(self.presetWidget)

        central.addWidget(self.presetView)
        central.setStretchFactor(2, 2)

        #self.detailView.setFrameStyle(QFrame.Box)
        self.presetLayout = QVBoxLayout()
        self.presetWidget.setLayout(self.presetLayout)

        self.detailName = QLabel('')
        self.detailName.setWordWrap(True)
        self.detailName.setStyleSheet("QLabel  {font-size:15pt;}")

        self.presetLayout.addWidget(self.detailName)

        self.detailDescription = TextViewer()
        self.presetLayout.addWidget(self.detailDescription)

        self.presetForm = QFormLayout()
        self.presetForm.setRowWrapPolicy(QFormLayout.DontWrapRows)
        self.presetForm.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow)
        self.presetForm.setFormAlignment(Qt.AlignLeft | Qt.AlignTop)
        self.presetForm.setLabelAlignment(Qt.AlignLeft)
        self.presetLayout.addLayout(self.presetForm, 1)

        # Module
        self.detailModule = QLabel('')
        self.presetForm.addRow('<b>Module</b>', self.detailModule)

        #Options
        self.detailOptionsLabel = QLabel('<b>Options</b>')
        self.detailOptionsLabel.setStyleSheet("QLabel {height:25px;}")
        self.detailOptions = TextViewer()
        self.presetForm.addRow(self.detailOptionsLabel, self.detailOptions)

        # Columns
        self.detailColumnsLabel = QLabel('<b>Columns</b>')
        self.detailColumnsLabel.setStyleSheet("QLabel {height:25px;}")
        self.detailColumns = TextViewer()
        self.presetForm.addRow(self.detailColumnsLabel, self.detailColumns)

        # Speed
        self.detailSpeed = QLabel('')
        self.presetForm.addRow('<b>Speed</b>', self.detailSpeed)

        # Timeout
        self.detailTimeout = QLabel('')
        self.presetForm.addRow('<b>Timeout</b>', self.detailTimeout)

        # Headers
        self.detailHeaders = QLabel('')
        self.presetForm.addRow('<b>Header nodes</b>', self.detailHeaders)

        # Buttons
        buttons = QHBoxLayout()  #QDialogButtonBox()
        self.saveButton = QPushButton('New preset')
        self.saveButton.clicked.connect(self.newPreset)
        self.saveButton.setToolTip(
            wraptip(
                "Create a new preset using the current tab and parameters"))
        #buttons.addButton(self.saveButton,QDialogButtonBox.ActionRole)
        buttons.addWidget(self.saveButton)

        self.overwriteButton = QPushButton('Edit preset')
        self.overwriteButton.clicked.connect(self.overwritePreset)
        self.overwriteButton.setToolTip(wraptip("Edit the selected preset."))
        #buttons.addButton(self.overwriteButton,QDialogButtonBox.ActionRole)
        buttons.addWidget(self.overwriteButton)

        self.deleteButton = QPushButton('Delete preset')
        self.deleteButton.clicked.connect(self.deletePreset)
        self.deleteButton.setToolTip(
            wraptip(
                "Delete the selected preset. Default presets can not be deleted."
            ))
        #buttons.addButton(self.deleteButton,QDialogButtonBox.ActionRole)
        buttons.addWidget(self.deleteButton)

        #layout.addWidget(buttons,1)

        buttons.addStretch()

        self.reloadButton = QPushButton('Reload')
        self.reloadButton.clicked.connect(self.reloadPresets)
        self.reloadButton.setToolTip(wraptip("Reload all preset files."))
        buttons.addWidget(self.reloadButton)

        self.rejectButton = QPushButton('Cancel')
        self.rejectButton.clicked.connect(self.close)
        self.rejectButton.setToolTip(wraptip("Close the preset dialog."))
        buttons.addWidget(self.rejectButton)

        self.applyButton = QPushButton('Apply')
        self.applyButton.setDefault(True)
        self.applyButton.clicked.connect(self.applyPreset)
        self.applyButton.setToolTip(wraptip("Load the selected preset."))
        buttons.addWidget(self.applyButton)
        layout.addLayout(buttons)

        #status bar
        self.statusbar = QStatusBar()
        #self.folderLabel = QLabel("")
        self.folderButton = QPushButton("")
        self.folderButton.setFlat(True)
        self.folderButton.clicked.connect(self.statusBarClicked)
        self.statusbar.insertWidget(0, self.folderButton)
        layout.addWidget(self.statusbar)

        #self.presetFolder = os.path.join(os.path.dirname(self.mainWindow.settings.fileName()),'presets')
        self.presetFolder = os.path.join(os.path.expanduser("~"), 'Facepager',
                                         'Presets')
        self.presetFolderDefault = os.path.join(os.path.expanduser("~"),
                                                'Facepager', 'DefaultPresets')
        self.folderButton.setText(self.presetFolder)

        self.presetsDownloaded = False
        self.presetSuffix = ['.3_9.json', '.3_10.json', '.fp4.json']
        self.lastSelected = None

        # Progress bar (sync with download thread by signals
        self.progress = ProgressBar(
            "Downloading default presets from GitHub...", self, hidden=True)
        self.progressStart.connect(self.setProgressStart)
        self.progressShow.connect(self.setProgressShow)
        self.progressMax.connect(self.setProgressMax)
        self.progressStep.connect(self.setProgressStep)
        self.progressStop.connect(self.setProgressStop)
class TransferNodes(QDialog):
    def __init__(self, parent=None):
        super(TransferNodes, self).__init__(parent)

        # Main window
        self.mainWindow = parent
        self.setWindowTitle("Add selected nodes as seed nodes")
        #self.setMinimumWidth(400)

        # layout
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        self.extractLayout = QFormLayout()
        layout.addLayout(self.extractLayout)

        # Options
        self.allnodesCheckbox = QCheckBox("Select all nodes")
        self.allnodesCheckbox.setToolTip(wraptip("Check if you want to transfer all nodes."))
        self.allnodesCheckbox.setChecked(False)
        self.extractLayout.addRow("Nodes", self.allnodesCheckbox)

        self.levelEdit=QSpinBox()
        self.levelEdit.setMinimum(1)
        self.levelEdit.setToolTip(wraptip("Based on the selected nodes, only subnodes of the specified level are processed (base level is 1)"))
        self.extractLayout.addRow("Node level", self.levelEdit)

        self.objecttypeEdit = QLineEdit("offcut")
        self.objecttypeEdit.setToolTip(wraptip("Skip nodes with these object types."))
        self.extractLayout.addRow("Exclude object types", self.objecttypeEdit)

        # Buttons
        buttons = QDialogButtonBox(QDialogButtonBox.Apply | QDialogButtonBox.Close)
        buttons.button(QDialogButtonBox.Apply).clicked.connect(self.createNodes)
        buttons.button(QDialogButtonBox.Close).clicked.connect(self.close)
        layout.addWidget(buttons)

    def show(self):
        self.allnodesCheckbox.setChecked(self.mainWindow.allnodesCheckbox.isChecked())
        self.levelEdit.setValue(self.mainWindow.levelEdit.value())
        self.objecttypeEdit.setText(self.mainWindow.typesEdit.text())

        super(TransferNodes, self).show()
        self.raise_()

    def updateNode(self, current):
        if current.isValid():
            level = current.model().getLevel(current) + 1
            self.levelEdit.setValue(level)

    def initProgress(self):
        self.progressBar = ProgressBar("Transferring nodes...", self.mainWindow)
        self.progressTotal = None
        self.progressLevel = None
        self.progressUpdate = datetime.now()

    def updateProgress(self,current, total, level=0):
        if datetime.now() >= self.progressUpdate:
            if (self.progressLevel is None) or (level < self.progressLevel):
                self.progressLevel = level
                self.progressTotal = total

            if (level == self.progressLevel) or (total > self.progressTotal):
                self.progressBar.setMaximum(total)
                self.progressBar.setValue(current)
                self.progressUpdate = datetime.now() + timedelta(milliseconds=50)

            QApplication.processEvents()

        return not self.progressBar.wasCanceled

    def finishProgress(self):
        self.progressBar.close()

    @Slot()
    def createNodes(self):
        try:
            self.initProgress()

            # Get list of seed nodes to avoid duplicates
            seednodes = Node.query.filter(Node.parent_id == None).add_columns('objectid')
            seednodes = [node.objectid for node in seednodes]

            # Iterate nodes
            objecttypes = self.objecttypeEdit.text().replace(' ', '').split(',')
            level = self.levelEdit.value() - 1
            allnodes = self.allnodesCheckbox.isChecked()
            conditions = {'filter': {'level': level, '!objecttype': objecttypes},
                          'selectall': allnodes}
            selected = self.mainWindow.tree.selectedIndexesAndChildren(conditions, self.updateProgress)
            nodes_new = 0
            nodes_dupl = 0


            for item in selected:
                if self.progressBar.wasCanceled:
                    break
                if not item.isValid():
                    continue

                treenode = item.internalPointer()
                objectid = treenode.data.get("objectid")

                # no duplicates
                if not objectid in seednodes:
                    seednodes.append(objectid)
                    treenode.copyNode(delaycommit=True)
                    nodes_new += 1
                else:
                    nodes_dupl += 1

            self.mainWindow.tree.treemodel.commitNewNodes()
            self.mainWindow.tree.selectLastRow()
            self.mainWindow.logmessage(f"{nodes_new} nodes added as seed nodes. {nodes_dupl} duplicate nodes skipped.")
            self.close()

        except Exception as e:
            self.mainWindow.logmessage(e)
        finally:
            self.mainWindow.tree.treemodel.commitNewNodes()
            self.finishProgress()

        #self.close()
        return True
Beispiel #17
0
class PresetWindow(QDialog):
    logmessage = Signal(str)

    progressStart = Signal()
    progressShow = Signal()
    progressMax = Signal(int)
    progressStep = Signal()
    progressStop = Signal()

    def __init__(self, parent=None):
        super(PresetWindow, self).__init__(parent)

        self.mainWindow = parent
        self.setWindowTitle("Presets")
        self.setMinimumWidth(800)
        self.setMinimumHeight(600)

        #layout
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        #loading indicator
        self.loadingLock = threading.Lock()
        self.loadingIndicator = QLabel('Loading...please wait a second.')
        self.loadingIndicator.hide()
        layout.addWidget(self.loadingIndicator)

        #Middle
        central = QSplitter(self)
        layout.addWidget(central, 1)

        #list view
        self.presetList = QTreeWidget(self)
        self.presetList.setHeaderHidden(True)
        self.presetList.setColumnCount(1)
        self.presetList.setIndentation(15)
        self.presetList.itemSelectionChanged.connect(self.currentChanged)
        central.addWidget(self.presetList)
        central.setStretchFactor(0, 0)

        # category / pipeline
        self.categoryWidget = QWidget()
        p = self.categoryWidget.palette()
        p.setColor(self.categoryWidget.backgroundRole(), Qt.white)
        self.categoryWidget.setPalette(p)
        self.categoryWidget.setAutoFillBackground(True)

        self.categoryLayout = QVBoxLayout()
        #self.categoryLayout.setContentsMargins(0, 0, 0, 0)
        self.categoryWidget.setLayout(self.categoryLayout)

        self.categoryView = QScrollArea()
        self.categoryView.setWidgetResizable(True)
        self.categoryView.setWidget(self.categoryWidget)
        central.addWidget(self.categoryView)
        central.setStretchFactor(1, 2)

        # Pipeline header
        self.pipelineName = QLabel('')
        self.pipelineName.setWordWrap(True)
        self.pipelineName.setStyleSheet("QLabel  {font-size:15pt;}")
        self.categoryLayout.addWidget(self.pipelineName)

        # Pipeline items
        # self.pipelineWidget = QTreeWidget()
        # self.pipelineWidget.setIndentation(0)
        # self.pipelineWidget.setUniformRowHeights(True)
        # self.pipelineWidget.setColumnCount(4)
        # self.pipelineWidget.setHeaderLabels(['Name','Module','Basepath','Resource'])
        # self.categoryLayout.addWidget(self.pipelineWidget)

        # preset widget
        self.presetWidget = QWidget()

        p = self.presetWidget.palette()
        p.setColor(self.presetWidget.backgroundRole(), Qt.white)
        self.presetWidget.setPalette(p)
        self.presetWidget.setAutoFillBackground(True)

        #self.presetWidget.setStyleSheet("background-color: rgb(255,255,255);")
        self.presetView = QScrollArea()
        self.presetView.setWidgetResizable(True)
        self.presetView.setWidget(self.presetWidget)

        central.addWidget(self.presetView)
        central.setStretchFactor(2, 2)

        #self.detailView.setFrameStyle(QFrame.Box)
        self.presetLayout = QVBoxLayout()
        self.presetWidget.setLayout(self.presetLayout)

        self.detailName = QLabel('')
        self.detailName.setWordWrap(True)
        self.detailName.setStyleSheet("QLabel  {font-size:15pt;}")

        self.presetLayout.addWidget(self.detailName)

        self.detailDescription = TextViewer()
        self.presetLayout.addWidget(self.detailDescription)

        self.presetForm = QFormLayout()
        self.presetForm.setRowWrapPolicy(QFormLayout.DontWrapRows)
        self.presetForm.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow)
        self.presetForm.setFormAlignment(Qt.AlignLeft | Qt.AlignTop)
        self.presetForm.setLabelAlignment(Qt.AlignLeft)
        self.presetLayout.addLayout(self.presetForm, 1)

        # Module
        self.detailModule = QLabel('')
        self.presetForm.addRow('<b>Module</b>', self.detailModule)

        #Options
        self.detailOptionsLabel = QLabel('<b>Options</b>')
        self.detailOptionsLabel.setStyleSheet("QLabel {height:25px;}")
        self.detailOptions = TextViewer()
        self.presetForm.addRow(self.detailOptionsLabel, self.detailOptions)

        # Columns
        self.detailColumnsLabel = QLabel('<b>Columns</b>')
        self.detailColumnsLabel.setStyleSheet("QLabel {height:25px;}")
        self.detailColumns = TextViewer()
        self.presetForm.addRow(self.detailColumnsLabel, self.detailColumns)

        # Speed
        self.detailSpeed = QLabel('')
        self.presetForm.addRow('<b>Speed</b>', self.detailSpeed)

        # Timeout
        self.detailTimeout = QLabel('')
        self.presetForm.addRow('<b>Timeout</b>', self.detailTimeout)

        # Headers
        self.detailHeaders = QLabel('')
        self.presetForm.addRow('<b>Header nodes</b>', self.detailHeaders)

        # Buttons
        buttons = QHBoxLayout()  #QDialogButtonBox()
        self.saveButton = QPushButton('New preset')
        self.saveButton.clicked.connect(self.newPreset)
        self.saveButton.setToolTip(
            wraptip(
                "Create a new preset using the current tab and parameters"))
        #buttons.addButton(self.saveButton,QDialogButtonBox.ActionRole)
        buttons.addWidget(self.saveButton)

        self.overwriteButton = QPushButton('Edit preset')
        self.overwriteButton.clicked.connect(self.overwritePreset)
        self.overwriteButton.setToolTip(wraptip("Edit the selected preset."))
        #buttons.addButton(self.overwriteButton,QDialogButtonBox.ActionRole)
        buttons.addWidget(self.overwriteButton)

        self.deleteButton = QPushButton('Delete preset')
        self.deleteButton.clicked.connect(self.deletePreset)
        self.deleteButton.setToolTip(
            wraptip(
                "Delete the selected preset. Default presets can not be deleted."
            ))
        #buttons.addButton(self.deleteButton,QDialogButtonBox.ActionRole)
        buttons.addWidget(self.deleteButton)

        #layout.addWidget(buttons,1)

        buttons.addStretch()

        self.reloadButton = QPushButton('Reload')
        self.reloadButton.clicked.connect(self.reloadPresets)
        self.reloadButton.setToolTip(wraptip("Reload all preset files."))
        buttons.addWidget(self.reloadButton)

        self.rejectButton = QPushButton('Cancel')
        self.rejectButton.clicked.connect(self.close)
        self.rejectButton.setToolTip(wraptip("Close the preset dialog."))
        buttons.addWidget(self.rejectButton)

        self.applyButton = QPushButton('Apply')
        self.applyButton.setDefault(True)
        self.applyButton.clicked.connect(self.applyPreset)
        self.applyButton.setToolTip(wraptip("Load the selected preset."))
        buttons.addWidget(self.applyButton)
        layout.addLayout(buttons)

        #status bar
        self.statusbar = QStatusBar()
        #self.folderLabel = QLabel("")
        self.folderButton = QPushButton("")
        self.folderButton.setFlat(True)
        self.folderButton.clicked.connect(self.statusBarClicked)
        self.statusbar.insertWidget(0, self.folderButton)
        layout.addWidget(self.statusbar)

        #self.presetFolder = os.path.join(os.path.dirname(self.mainWindow.settings.fileName()),'presets')
        self.presetFolder = os.path.join(os.path.expanduser("~"), 'Facepager',
                                         'Presets')
        self.presetFolderDefault = os.path.join(os.path.expanduser("~"),
                                                'Facepager', 'DefaultPresets')
        self.folderButton.setText(self.presetFolder)

        self.presetsDownloaded = False
        self.presetSuffix = ['.3_9.json', '.3_10.json', '.fp4.json']
        self.lastSelected = None

        # Progress bar (sync with download thread by signals
        self.progress = ProgressBar(
            "Downloading default presets from GitHub...", self, hidden=True)
        self.progressStart.connect(self.setProgressStart)
        self.progressShow.connect(self.setProgressShow)
        self.progressMax.connect(self.setProgressMax)
        self.progressStep.connect(self.setProgressStep)
        self.progressStop.connect(self.setProgressStop)


#         if getattr(sys, 'frozen', False):
#             self.defaultPresetFolder = os.path.join(os.path.dirname(sys.executable),'presets')
#         elif __file__:
#             self.defaultPresetFolder = os.path.join(os.path.dirname(__file__),'presets')

# Sycn progress bar with download thread

    @Slot()
    def setProgressStart(self):
        if self.progress is None:
            self.progress = ProgressBar(
                "Downloading default presets from GitHub...",
                self,
                hidden=True)

    def setProgressShow(self):
        if self.progress is not None:
            self.progress.setModal(True)
            self.progress.show()
        QApplication.processEvents()

    def setProgressMax(self, maximum):
        if self.progress is not None:
            self.progress.setMaximum(maximum)

    def setProgressStep(self):
        if self.progress is not None:
            self.progress.step()

    def setProgressStop(self):
        self.progress.close()
        self.progress = None

    def statusBarClicked(self):
        if not os.path.exists(self.presetFolder):
            os.makedirs(self.presetFolder)

        if platform.system() == "Windows":
            webbrowser.open(self.presetFolder)
        elif platform.system() == "Darwin":
            webbrowser.open('file:///' + self.presetFolder)
        else:
            webbrowser.open('file:///' + self.presetFolder)

    def currentChanged(self):
        #hide
        self.detailName.setText("")
        self.detailModule.setText("")
        self.detailDescription.setText("")
        self.detailOptions.setText("")
        self.detailColumns.setText("")

        self.presetView.hide()
        self.categoryView.hide()

        current = self.presetList.currentItem()
        if current and current.isSelected():
            data = current.data(0, Qt.UserRole)

            # Single preset
            if not data.get('iscategory', False):
                self.lastSelected = os.path.join(data.get('folder', ''),
                                                 data.get('filename', ''))

                self.detailName.setText(data.get('name'))
                self.detailModule.setText(data.get('module'))
                self.detailDescription.setText(data.get('description') + "\n")
                self.detailOptions.setHtml(formatdict(data.get('options', [])))
                self.detailColumns.setText("\r\n".join(data.get('columns',
                                                                [])))
                self.detailSpeed.setText(str(data.get('speed', '')))
                self.detailTimeout.setText(str(data.get('timeout', '')))

                #self.applyButton.setText("Apply")
                self.presetView.show()

            # Category
            else:
                #                self.pipelineName.setText(str(data.get('category')))

                #                 self.pipelineWidget.clear()
                #                 for i in range(current.childCount()):
                #                     presetitem = current.child(i)
                #                     preset = presetitem.data(0, Qt.UserRole)
                #
                #                     treeitem = QTreeWidgetItem(self.pipelineWidget)
                #                     treeitem.setText(0,preset.get('name'))
                #                     treeitem.setText(1, preset.get('module'))
                #                     treeitem.setText(2, getDictValue(preset,'options.basepath'))
                #                     treeitem.setText(3, getDictValue(preset,'options.resource'))
                # #                   treeitem.setText(4, preset.get('description'))
                #
                #                     self.pipelineWidget.addTopLevelItem(treeitem)

                #self.applyButton.setText("Run pipeline")
                self.categoryView.show()

    def showPresets(self):
        self.clear()
        self.show()
        QApplication.processEvents()

        self.progressShow.emit()

        self.initPresets()
        self.raise_()

    def addPresetItem(self, folder, filename, default=False, online=False):
        try:
            if online:
                data = requests.get(folder + filename).json()
            else:
                with open(os.path.join(folder, filename),
                          'r',
                          encoding="utf-8") as input:
                    data = json.load(input)

            data['filename'] = filename
            data['folder'] = folder
            data['default'] = default
            data['online'] = online

            if data.get('type', 'preset') == 'pipeline':
                data['category'] = data.get('category', 'noname')
                if not data['category'] in self.categoryNodes:
                    categoryItem = PresetWidgetItem()
                    categoryItem.setText(0, data['category'])

                    ft = categoryItem.font(0)
                    ft.setWeight(QFont.Bold)
                    categoryItem.setFont(0, ft)

                    self.presetList.addTopLevelItem(categoryItem)
                else:
                    categoryItem = self.categoryNodes[data['category']]

                data['iscategory'] = True
                categoryItem.setData(0, Qt.UserRole, data)

            else:
                data['caption'] = data.get('name')
                if default:
                    data['caption'] = data['caption'] + " *"

                data['category'] = data.get('category', '')
                if (data['category'] == ''):
                    if (data.get('module') in ['Generic', 'Files']):
                        try:
                            data['category'] = data.get(
                                'module') + " (" + urlparse(
                                    data['options']['basepath']).netloc + ")"
                        except:
                            data['category'] = data.get('module')
                    else:
                        data['category'] = data.get('module')

                if not data['category'] in self.categoryNodes:
                    categoryItem = PresetWidgetItem()
                    categoryItem.setText(0, data['category'])

                    ft = categoryItem.font(0)
                    ft.setWeight(QFont.Bold)
                    categoryItem.setFont(0, ft)

                    categoryItem.setData(
                        0, Qt.UserRole, {
                            'iscategory': True,
                            'name': data['module'],
                            'category': data['category']
                        })

                    self.presetList.addTopLevelItem(categoryItem)
                    self.categoryNodes[data['category']] = categoryItem

                else:
                    categoryItem = self.categoryNodes[data['category']]

                newItem = PresetWidgetItem()
                newItem.setText(0, data['caption'])
                newItem.setData(0, Qt.UserRole, data)
                if default:
                    newItem.setForeground(0, QBrush(QColor("darkblue")))
                categoryItem.addChild(newItem)

            #self.presetList.setCurrentItem(newItem,0)
            QApplication.processEvents()

            return newItem

        except Exception as e:
            QMessageBox.information(self, "Facepager",
                                    "Error loading preset:" + str(e))
            return None

    def clear(self):
        self.presetList.clear()
        self.presetView.hide()
        self.categoryView.hide()
        self.loadingIndicator.show()

    def checkDefaultFiles(self):
        if not os.path.exists(self.presetFolderDefault):
            self.downloadDefaultFiles()
        elif len(os.listdir(self.presetFolderDefault)) == 0:
            self.downloadDefaultFiles()

    def downloadDefaultFiles(self, silent=False):
        with self.loadingLock:
            if self.presetsDownloaded:
                return False

            # Progress
            self.progressStart.emit()
            if not silent:
                self.progressShow.emit()

            # Create temporary download folder
            tmp = TemporaryDirectory(suffix='FacepagerDefaultPresets')
            try:
                #Download
                files = requests.get(
                    "https://api.github.com/repos/strohne/Facepager/contents/presets"
                ).json()
                files = [
                    f['path'] for f in files
                    if f['path'].endswith(tuple(self.presetSuffix))
                ]
                self.progressMax.emit(len(files))

                for filename in files:
                    response = requests.get(
                        "https://raw.githubusercontent.com/strohne/Facepager/master/"
                        + filename)
                    if response.status_code != 200:
                        raise (
                            f"GitHub is not available (status code {response.status_code})"
                        )
                    with open(
                            os.path.join(tmp.name, os.path.basename(filename)),
                            'wb') as f:
                        f.write(response.content)

                    self.progressStep.emit()

                #Create folder
                if not os.path.exists(self.presetFolderDefault):
                    os.makedirs(self.presetFolderDefault)

                #Clear folder
                for filename in os.listdir(self.presetFolderDefault):
                    os.remove(os.path.join(self.presetFolderDefault, filename))

                # Move files from tempfolder
                for filename in os.listdir(tmp.name):
                    shutil.move(os.path.join(tmp.name, filename),
                                self.presetFolderDefault)

                self.logmessage.emit("Default presets downloaded from GitHub.")
            except Exception as e:
                if not silent:
                    QMessageBox.information(
                        self, "Facepager",
                        "Error downloading default presets:" + str(e))
                self.logmessage.emit("Error downloading default presets:" +
                                     str(e))
                return False
            else:
                self.presetsDownloaded = True
                return True
            finally:
                tmp.cleanup()
                self.progressStop.emit()

    def reloadPresets(self):
        self.presetsDownloaded = False
        self.downloadDefaultFiles()
        self.initPresets()

    def initPresets(self):
        self.loadingIndicator.show()

        #self.defaultPresetFolder
        self.categoryNodes = {}
        self.presetList.clear()
        self.presetView.hide()
        self.categoryView.hide()

        selectitem = None

        while not self.presetsDownloaded:
            QApplication.processEvents()

        if os.path.exists(self.presetFolderDefault):
            files = [
                f for f in os.listdir(self.presetFolderDefault)
                if f.endswith(tuple(self.presetSuffix))
            ]
            for filename in files:
                newitem = self.addPresetItem(self.presetFolderDefault,
                                             filename, True)
                if self.lastSelected is not None and (
                        self.lastSelected == os.path.join(
                            self.presetFolderDefault, filename)):
                    selectitem = newitem

        if os.path.exists(self.presetFolder):
            files = [
                f for f in os.listdir(self.presetFolder)
                if f.endswith(tuple(self.presetSuffix))
            ]
            for filename in files:
                newitem = self.addPresetItem(self.presetFolder, filename)
                if self.lastSelected is not None and (self.lastSelected == str(
                        os.path.join(self.presetFolder, filename))):
                    selectitem = newitem

        #self.presetList.expandAll()
        self.presetList.setFocus()
        self.presetList.sortItems(0, Qt.AscendingOrder)

        selectitem = self.presetList.topLevelItem(
            0) if selectitem is None else selectitem
        self.presetList.setCurrentItem(selectitem)

        self.applyButton.setDefault(True)
        self.loadingIndicator.hide()

    def getCategories(self):
        categories = []

        root = self.presetList.invisibleRootItem()
        for i in range(root.childCount()):
            item = root.child(i)
            data = item.data(0, Qt.UserRole)
            categories.append(data.get('category', ''))

        return categories

    def startPipeline(self):
        if not self.presetList.currentItem():
            return False

        # Get category item
        root_item = self.presetList.currentItem()
        root_data = root_item.data(0, Qt.UserRole)
        if not root_data.get('iscategory', False):
            root_item = root_item.parent()
            root_data = root_item.data(0, Qt.UserRole)

        # Create pipeline
        pipeline = []

        for i in range(root_item.childCount()):
            item = root_item.child(i)

            preset = item.data(0, Qt.UserRole)
            module = self.mainWindow.getModule(preset.get('module', None))
            options = module.getOptions()
            options.update(preset.get('options', {}))
            preset['options'] = options.copy()
            preset['item'] = item

            pipeline.append(preset)

        # Process pipeline
        return self.mainWindow.apiActions.queryPipeline(pipeline)
        #self.close()

    def applyPreset(self):
        if not self.presetList.currentItem():
            return False

        data = self.presetList.currentItem().data(0, Qt.UserRole)
        if data.get('iscategory', False):
            return False
            #self.startPipeline()
        else:
            self.mainWindow.apiActions.applySettings(data)

        self.close()

    def uniqueFilename(self, name):
        filename = re.sub('[^a-zA-Z0-9_-]+', '_', name) + self.presetSuffix[-1]
        i = 1
        while os.path.exists(os.path.join(self.presetFolder,
                                          filename)) and i < 10000:
            filename = re.sub('[^a-zA-Z0-9_-]+', '_',
                              name) + "-" + str(i) + self.presetSuffix[-1]
            i += 1

        if os.path.exists(os.path.join(self.presetFolder, filename)):
            raise Exception('Could not find unique filename')
        return filename

    def deletePreset(self):
        if not self.presetList.currentItem():
            return False
        data = self.presetList.currentItem().data(0, Qt.UserRole)
        if data.get('default', False):
            QMessageBox.information(self, "Facepager",
                                    "Cannot delete default presets.")
            return False

        if data.get('iscategory', False):
            return False

        reply = QMessageBox.question(
            self, 'Delete Preset',
            "Are you sure to delete the preset \"{0}\"?".format(
                data.get('name', '')), QMessageBox.Yes | QMessageBox.No,
            QMessageBox.No)
        if reply != QMessageBox.Yes:
            return False

        os.remove(os.path.join(self.presetFolder, data.get('filename')))
        self.initPresets()

    def editPreset(self, data=None):
        dialog = QDialog(self.mainWindow)

        self.currentData = data if data is not None else {}
        self.currentFilename = self.currentData.get('filename', None)

        if self.currentFilename is None:
            dialog.setWindowTitle("New Preset")
        else:
            dialog.setWindowTitle("Edit selected preset")

        layout = QVBoxLayout()
        label = QLabel("<b>Name</b>")
        layout.addWidget(label)
        name = QLineEdit()
        name.setText(self.currentData.get('name', ''))
        layout.addWidget(name, 0)

        label = QLabel("<b>Category</b>")
        layout.addWidget(label)
        category = QComboBox(self)
        category.addItems(self.getCategories())
        category.setEditable(True)

        category.setCurrentText(self.currentData.get('category', ''))
        layout.addWidget(category, 0)

        label = QLabel("<b>Description</b>")
        layout.addWidget(label)
        description = QTextEdit()
        description.setMinimumWidth(500)
        description.acceptRichText = False
        description.setPlainText(self.currentData.get('description', ''))
        description.setFocus()
        layout.addWidget(description, 1)

        overwriteLayout = QHBoxLayout()
        self.overwriteCheckbox = QCheckBox(self)
        self.overwriteCheckbox.setCheckState(Qt.Unchecked)
        overwriteLayout.addWidget(self.overwriteCheckbox)
        label = QLabel("<b>Overwrite parameters with current settings</b>")
        overwriteLayout.addWidget(label)
        overwriteLayout.addStretch()

        if self.currentFilename is not None:
            layout.addLayout(overwriteLayout)

        buttons = QDialogButtonBox(QDialogButtonBox.Ok
                                   | QDialogButtonBox.Cancel)
        layout.addWidget(buttons, 0)
        dialog.setLayout(layout)

        def save():
            data_meta = {
                'name': name.text(),
                'category': category.currentText(),
                'description': description.toPlainText()
            }

            data_settings = self.mainWindow.apiActions.getPresetOptions()
            self.currentData.update(data_meta)

            if self.currentFilename is None:
                self.currentData.update(data_settings)

            elif self.overwriteCheckbox.isChecked():
                reply = QMessageBox.question(
                    self, 'Overwrite Preset',
                    "Are you sure to overwrite the selected preset \"{0}\" with the current settings?"
                    .format(data.get('name', '')),
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
                if reply != QMessageBox.Yes:
                    dialog.close()
                    self.currentFilename = None
                    return False
                else:
                    self.currentData.update(data_settings)

            # Sanitize and reorder
            keys = [
                'name', 'category', 'description', 'module', 'options',
                'speed', 'saveheaders', 'timeout', 'columns'
            ]
            self.currentData = {k: self.currentData.get(k, None) for k in keys}

            # Create folder
            if not os.path.exists(self.presetFolder):
                os.makedirs(self.presetFolder)

            # Remove old file
            if self.currentFilename is not None:
                filepath = os.path.join(self.presetFolder,
                                        self.currentFilename)
                if os.path.exists(filepath):
                    os.remove(filepath)

            # Save new file
            catname = category.currentText() if category.currentText(
            ) != "" else self.mainWindow.RequestTabs.currentWidget().name
            self.currentFilename = self.uniqueFilename(catname + "-" +
                                                       name.text())

            with open(os.path.join(self.presetFolder, self.currentFilename),
                      'w') as outfile:
                json.dump(self.currentData,
                          outfile,
                          indent=2,
                          separators=(',', ': '))

            dialog.close()
            return True

        def close():
            dialog.close()
            self.currentFilename = None
            return False

        #connect the nested functions above to the dialog-buttons
        buttons.accepted.connect(save)
        buttons.rejected.connect(close)
        dialog.exec()
        return self.currentFilename

    def newPreset(self):
        filename = self.editPreset()
        if filename is not None:
            newitem = self.addPresetItem(self.presetFolder, filename)
            self.presetList.sortItems(0, Qt.AscendingOrder)
            self.presetList.setCurrentItem(newitem, 0)

    def overwritePreset(self):
        if not self.presetList.currentItem():
            return False

        item = self.presetList.currentItem()
        data = item.data(0, Qt.UserRole)

        if data.get('default', False):
            QMessageBox.information(self, "Facepager",
                                    "Cannot edit default presets.")
            return False

        if data.get('iscategory', False):
            return False

        filename = self.editPreset(data)

        if filename is not None:
            item.parent().removeChild(item)
            item = self.addPresetItem(self.presetFolder, filename)

            self.presetList.sortItems(0, Qt.AscendingOrder)
            self.presetList.setCurrentItem(item, 0)
Beispiel #18
0
 def setProgressStart(self):
     if self.progress is None:
         self.progress = ProgressBar(
             "Downloading default presets from GitHub...",
             self,
             hidden=True)
 def initProgress(self):
     self.progressBar = ProgressBar("Transferring nodes...", self.mainWindow)
     self.progressTotal = None
     self.progressLevel = None
     self.progressUpdate = datetime.now()
Beispiel #20
0
    def downloadDefaultFiles(self, silent=False):
        with self.loadingLock:
            if self.filesDownloaded:
                return False

            # Progress
            progress = ProgressBar(
                "Downloading default API definitions from GitHub...",
                self) if not silent else None
            QApplication.processEvents()

            # Create temporary download folder
            tmp = TemporaryDirectory(suffix='FacepagerDefaultAPIs')
            try:
                #Download
                files = requests.get(
                    "https://api.github.com/repos/strohne/Facepager/contents/apis"
                ).json()
                files = [
                    f['path'] for f in files
                    if f['path'].endswith(tuple(self.filesSuffix))
                ]
                if progress is not None:
                    progress.setMaximum(len(files))
                for filename in files:
                    response = requests.get(
                        "https://raw.githubusercontent.com/strohne/Facepager/master/"
                        + filename)
                    if response.status_code != 200:
                        raise Exception(
                            f"GitHub is not available (status code {response.status_code})"
                        )
                    with open(
                            os.path.join(tmp.name, os.path.basename(filename)),
                            'wb') as f:
                        f.write(response.content)
                    if progress is not None:
                        progress.step()

                    # Create folder
                if not os.path.exists(self.folderDefault):
                    os.makedirs(self.folderDefault)

                    # Clear folder
                for filename in os.listdir(self.folderDefault):
                    os.remove(os.path.join(self.folderDefault, filename))

                # Move files from tempfolder
                for filename in os.listdir(tmp.name):
                    shutil.move(os.path.join(tmp.name, filename),
                                self.folderDefault)

                self.logmessage.emit(
                    "Default API definitions downloaded from GitHub.")
            except Exception as e:
                if not silent:
                    QMessageBox.information(
                        self, "Facepager",
                        "Error downloading default API definitions:" + str(e))

                self.logmessage.emit(
                    "Error downloading default API definitions:" + str(e))

                return False
            else:
                self.filesDownloaded = True
                return True
            finally:
                tmp.cleanup()
                if progress is not None:
                    progress.close()
Beispiel #21
0
class MainScreen(Screen):
    # refresh on updates from server or every <REFRESH_RATE> seconds
    REFRESH_RATE = 5
    # playlist to start on pressing 'A' button
    A_PLAYLIST = u'Дождь'
    # playlist to start on pressing 'A' and 'B' buttons together
    # (doesn't work, have to debug)
    AB_PLAYLIST = u'шум со звуком в конце'
    # volume adjustment step
    VOLUME_STEP = 3

    def __init__(self, screen_manager, keyboard_manager, client, status_screen,
                 volmgr):
        super(MainScreen, self).__init__(screen_manager, keyboard_manager)
        self._client = client
        self._status_screen = status_screen
        self._volmgr = volmgr

        font = fonts.DEFAULT_FONT_14

        self._status = PlayingWidget((0, 0), (9, 9))
        self._seekbar = ProgressBar((24, 1), (128 - 24, 7), 100)

        self._artist = ScrollingText((0, 12), (128, 16), font, u'')

        self._title = ScrollingText((0, 32), (128, 16), font, u'')

        self._volume = ProgressBar((0, 54), (128, 7), 100)

        self._play_list_screen = PlayListsScreen(screen_manager,
                                                 keyboard_manager, client)

        self._last_update = time.time()

    def widgets(self):
        return [
            self._status,
            self._seekbar,
            self._artist,
            self._title,
            # self._volume_label, self._volume]
            self._volume
        ]

    def activate(self):
        super(MainScreen, self).activate()
        # this will immediately trigger _connected if already connected
        self._client.add_connected_callback(self._connected)

    def deactivate(self):
        super(MainScreen, self).deactivate()
        self._client.remove_connected_callback(self._connected)
        # print("deactivate: noidle")
        self._stop_idle()

    def _connected(self):
        logging.info("Main screen connected, focing update")
        self._force_update()

    def _idle_update_status(self):
        try:
            self._client.fetch_idle()
        except mpd.base.PendingCommandError:
            pass

        self._update_status()
        # print("_idle_update_status: idle")
        self._client.send_idle()  # continue idling

    def _update_status(self):
        st = self._client.status()
        cs = self._client.currentsong()

        state = st.get('state', 'stop')  # play/stop/pause
        if state == 'play':
            self._status.set_status(PlayingWidget.PLAYING)
        elif state == 'stop':
            self._status.set_status(PlayingWidget.STOPPED)
        elif state == 'pause':
            self._status.set_status(PlayingWidget.PAUSED)

        if state == 'stop':
            self._artist.set_text(u'<stopped>')
            self._title.set_text(u'')
        elif isinstance(cs, basestring):
            # got this once, not sure what it means
            self._artist.set_text(cs)
            self._title.set_text(cs)
        else:
            artist = cs.get('artist')
            name = cs.get('name')
            if artist is not None:
                self._artist.set_text(artist)
            elif name is not None:
                self._artist.set_text(name)
            else:
                self._artist.set_text(u'Unknown Artist')

            title = cs.get('title', None)
            file = cs.get('file', None)
            if title is not None:
                self._title.set_text(title)
            elif file is not None:
                self._title.set_text(file)
            else:
                self._title.set_text(u'Unknown Title')

        elapsed = float(st.get('elapsed', 0.0))
        duration = float(st.get('duration', 0.0))
        if elapsed == 0 or duration == 0:
            _time = st.get('time', '0:0').split(':')
            elapsed = float(_time[0])
            duration = float(_time[1])
        if duration > 0:
            self._seekbar.set_value(elapsed * 100 / duration)
        else:
            self._seekbar.set_value(0)

        volume = self._volmgr.volume
        self._volume.set_value(volume)

        self._last_update = time.time()

    def _stop_idle(self):
        self._client.safe_noidle()

    def _force_update(self):
        # print("_force_update: noidle")
        self._stop_idle()
        self._update_status()
        # print("_force_update: idle")
        self._client.send_idle()

    def tick(self):
        try:
            if self._client.connected:
                force_update = time.time(
                ) - self._last_update > MainScreen.REFRESH_RATE
                if force_update and not self._screen_manager.is_screen_off():
                    self._force_update()
                elif select([self._client], [], [], 0)[0]:
                    self._idle_update_status()
            else:
                self._screen_manager.set_screen(self._status_screen)
        except (socket.timeout, mpd.ConnectionError):
            self._screen_manager.set_screen(self._status_screen)

    def on_keyboard_event(self, buttons_pressed):
        # print("on_kbd_event: noidle")
        self._stop_idle()
        try:

            resume_idle = True

            if buttons_pressed == [KeyboardManager.UP] or buttons_pressed == [
                    KeyboardManager.DOWN
            ]:
                self._screen_manager.set_screen(self._play_list_screen)
                resume_idle = False
            elif buttons_pressed == [KeyboardManager.LEFT]:
                volume = self._volmgr.volume
                volume = max(0, volume - MainScreen.VOLUME_STEP)
                self._volmgr.set_volume(volume)
                self._volume.set_value(volume)
            elif buttons_pressed == [KeyboardManager.RIGHT]:
                volume = self._volmgr.volume
                volume = min(100, volume + MainScreen.VOLUME_STEP)
                self._volmgr.set_volume(volume)
                self._volume.set_value(volume)
            elif buttons_pressed == [KeyboardManager.CENTER]:
                status = self._status.status
                if status == PlayingWidget.PLAYING:
                    self._client.pause(1)
                    self._status.set_status(PlayingWidget.PAUSED)
                elif status == PlayingWidget.PAUSED:
                    self._client.pause(0)
                    self._status.set_status(PlayingWidget.PLAYING)
            elif buttons_pressed == [KeyboardManager.A]:
                self._client.play_playlist(MainScreen.A_PLAYLIST)
            elif buttons_pressed == [KeyboardManager.A, KeyboardManager.B]:
                self._client.play_playlist(MainScreen.AB_PLAYLIST)
            elif buttons_pressed == [KeyboardManager.B]:
                status = self._status.status
                if status == PlayingWidget.PLAYING:
                    self._client.next()

            if resume_idle:
                # print("on_kbd_event: idle")
                self._client.send_idle()

        except (socket.timeout, mpd.ConnectionError):
            self._screen_manager.set_screen(self._status_screen)
 def initProgress(self):
     self.progressBar = ProgressBar("Extracting data...", self.mainWindow)
     self.progressTotal = None
     self.progressLevel = None
     self.progressUpdate = datetime.now()
Beispiel #23
0
    def fetchData(self, indexes=None, apimodule=False, options=None):
        # Check seed nodes
        if not (self.mainWindow.tree.selectedCount() or self.mainWindow.allnodesCheckbox.isChecked() or (indexes is not None)):
            return False

        # Get options
        apimodule, options = self.getQueryOptions(apimodule, options)
        if not apimodule.auth_userauthorized and apimodule.auth_preregistered:
            msg = 'You are not authorized, login please!'
            QMessageBox.critical(self.mainWindow, "Not authorized",msg,QMessageBox.StandardButton.Ok)
            return False

        #Show progress window
        progress = ProgressBar("Fetching Data", parent=self.mainWindow)

        try:
            # Get seed nodes
            indexes = self.getIndexes(options, indexes, progress)

            # Update progress window
            self.mainWindow.logmessage("Start fetching data.")
            totalnodes = 0
            hasindexes = True
            progress.setMaximum(totalnodes)
            self.mainWindow.tree.treemodel.nodecounter = 0

            #Init status messages
            statuscount = defaultdict(int)
            errorcount = 0
            ratelimitcount = 0
            allowedstatus = ['fetched (200)','downloaded (200)','fetched (202)']

            try:
                #Spawn Threadpool
                threadpool = ApiThreadPool(apimodule)
                threadpool.spawnThreads(options.get("threads", 1))

                #Process Logging/Input/Output Queue
                while True:
                    try:
                        #Logging (sync logs in threads with main thread)
                        msg = threadpool.getLogMessage()
                        if msg is not None:
                            self.mainWindow.logmessage(msg)

                        # Jobs in: packages of 100 at a time
                        jobsin = 0
                        while hasindexes and (jobsin < 100):
                            index = next(indexes, False)
                            if index:
                                jobsin += 1
                                totalnodes += 1
                                if index.isValid():
                                    job = self.prepareJob(index, options)
                                    threadpool.addJob(job)
                            else:
                                threadpool.applyJobs()
                                progress.setRemaining(threadpool.getJobCount())
                                progress.resetRate()
                                hasindexes = False
                                progress.removeInfo('input')
                                self.mainWindow.logmessage("Added {} node(s) to queue.".format(totalnodes))

                        if jobsin > 0:
                            progress.setMaximum(totalnodes)

                        #Jobs out
                        job = threadpool.getJob()

                        #-Finished all nodes (sentinel)...
                        if job is None:
                            break

                        #-Finished one node...
                        elif 'progress' in job:
                            progresskey = 'nodeprogress' + str(job.get('threadnumber', ''))

                            # Update single progress
                            if 'current' in job:
                                percent = int((job.get('current',0) * 100.0 / job.get('total',1)))
                                progress.showInfo(progresskey, "{}% of current node processed.".format(percent))
                            elif 'page' in job:
                                if job.get('page', 0) > 1:
                                    progress.showInfo(progresskey, "{} page(s) of current node processed.".format(job.get('page',0)))

                            # Update total progress
                            else:
                                progress.removeInfo(progresskey)
                                if not threadpool.suspended:
                                    progress.step()

                        #-Add data...
                        elif 'data' in job and (not progress.wasCanceled):
                            if not job['nodeindex'].isValid():
                                continue

                            # Add data
                            treeindex = job['nodeindex']
                            treenode = treeindex.internalPointer()

                            newcount = treenode.appendNodes(job['data'], job['options'], True)
                            if options.get('expand',False):
                                 self.mainWindow.tree.setExpanded(treeindex,True)

                            # Count status and errors
                            status = job['options'].get('querystatus', 'empty')
                            statuscount[status] += 1
                            errorcount += int(not status in allowedstatus)

                            # Detect rate limit
                            ratelimit = job['options'].get('ratelimit', False)
                            #ratelimit = ratelimit or (not newcount)
                            ratelimitcount += int(ratelimit)
                            autoretry = (ratelimitcount) or (status == "request error")

                            # Clear errors when everything is ok
                            if not threadpool.suspended and (status in allowedstatus) and (not ratelimit):
                                #threadpool.clearRetry()
                                errorcount = 0
                                ratelimitcount = 0
                                self.state = 'fetchdata'

                            # Suspend on error or ratelimit
                            elif (errorcount >= options['errors']) or (ratelimitcount > 0):
                                threadpool.suspendJobs()
                                self.state = 'ratelimit'

                                if ratelimit:
                                    msg = "You reached the rate limit of the API."
                                else:
                                    msg = "{} consecutive errors occurred.\nPlease check your settings.".format(errorcount)

                                timeout = 60 * 5 # 5 minutes

                                # Adjust progress
                                progress.showError(msg, timeout, autoretry)
                                self.mainWindow.tree.treemodel.commitNewNodes()

                            # Add job for retry
                            if not status in allowedstatus:
                                threadpool.addError(job)

                            # Show info
                            progress.showInfo(status,"{} response(s) with status: {}".format(statuscount[status],status))
                            progress.showInfo('newnodes',"{} new node(s) created".format(self.mainWindow.tree.treemodel.nodecounter))
                            progress.showInfo('threads',"{} active thread(s)".format(threadpool.getThreadCount()))
                            progress.setRemaining(threadpool.getJobCount())

                            # Custom info from modules
                            info = job['options'].get('info', {})
                            for name, value in info.items():
                                progress.showInfo(name, value)

                        # Abort
                        elif progress.wasCanceled:
                            progress.showInfo('cancel', "Disconnecting from stream, may take some time.")
                            threadpool.stopJobs()

                        # Retry
                        elif progress.wasResumed:
                            if progress.wasRetried:
                                threadpool.retryJobs()
                            else:
                                threadpool.clearRetry()
                                # errorcount = 0
                                # ratelimitcount = 0
                                threadpool.resumeJobs()

                            progress.setRemaining(threadpool.getJobCount())
                            progress.hideError()

                        # Continue
                        elif not threadpool.suspended:
                            threadpool.resumeJobs()

                        # Finished with pending errors
                        if not threadpool.hasJobs() and threadpool.hasErrorJobs():
                            msg = "All nodes finished but you have {} pending errors. Skip or retry?".format(threadpool.getErrorJobsCount())
                            autoretry = False
                            timeout = 60 * 5  # 5 minutes
                            progress.showError(msg, timeout, autoretry)

                        # Finished
                        if not threadpool.hasJobs():
                            progress.showInfo('cancel', "Work finished, shutting down threads.")
                            threadpool.stopJobs()

                        #-Waiting...
                        progress.computeRate()
                        time.sleep(1.0 / 1000.0)
                    finally:
                        QApplication.processEvents()

            finally:
                request_summary = [str(val)+" x "+key for key,val in statuscount.items()]
                request_summary = ", ".join(request_summary)
                request_end = "Fetching completed" if not progress.wasCanceled else 'Fetching cancelled by user'

                self.mainWindow.logmessage("{}, {} new node(s) created. Summary of responses: {}.".format(request_end, self.mainWindow.tree.treemodel.nodecounter,request_summary))

                self.mainWindow.tree.treemodel.commitNewNodes()
        except Exception as e:
            self.mainWindow.logmessage("Error in scheduler, fetching aborted: {}.".format(str(e)))
        finally:
            progress.close()
            return not progress.wasCanceled
Beispiel #24
0
class SolverWindow(tk.Frame):
    def __init__(self, application, solver, text, cipher_window):
        super(SolverWindow, self).__init__(application)
        self.application = application
        self.solver = solver
        self.cipher_window = cipher_window
        self.outputs = []
        # setup widgets
        self.create_widgets()
        # start the solver
        self.solver_process = start_solver(self.solver, text)
        # schedule update
        self.after(1000 // 30, self.update_from_solver)

    def create_widgets(self):
        """ Setup the widgets for the solver window """
        tk.Label(self,
                 text=self.solver.cipher_name + " - Guess Decryption Key",
                 **TITLE_LABEL_OPTIONS).grid(row=0, column=0)
        # back button
        tk.Button(self, text="Back", command=self.go_back).grid(row=0,
                                                                column=1,
                                                                sticky="NE")
        # stop button
        self.stop_button = tk.Button(self,
                                     text="Stop",
                                     command=self.stop_solver)
        self.stop_button.grid(row=3, column=1, sticky="NE")
        # progress bar
        tk.Label(self, text="Progress",
                 **SUBTITLE_LABEL_OPTIONS).grid(row=3, column=0)
        self.progress_bar = ProgressBar(self)
        self.progress_bar.grid(row=4, column=0, sticky="NSEW")
        # set the first column to be expandable
        self.grid_columnconfigure(0, weight=1)

        # setup the output scroll frame
        tk.Label(self, text="Outputs", **SUBTITLE_LABEL_OPTIONS).grid(row=1,
                                                                      column=0)
        self.outputs_scroll_frame = ScrollFrame(self)
        self.outputs_scroll_frame.grid(row=2, column=0, sticky="NSEW")
        self.outputs_inner_frame = self.outputs_scroll_frame.inner_frame
        # setup headings in the output scroll frame
        tk.Label(self.outputs_inner_frame, text="Score").grid(row=0,
                                                              column=0,
                                                              padx=10)
        tk.Label(self.outputs_inner_frame,
                 text="Decryption Key").grid(row=0, column=1, padx=10)
        tk.Label(self.outputs_inner_frame, text="Text").grid(row=0, column=2)

    def update_from_solver(self):
        """ Called 30 times a second on the main process to update progress from solver process """
        # check if the solver has been stopped
        if self.solver.solver_queue is None:
            return
        # only update the outputs once per set of messages
        outputs = None
        # only mark as done after updating outputs
        done = False
        # loop through and progress each message
        while True:
            # try and get a message
            try:
                command_name, value = self.solver.solver_queue.get_nowait()
            except queue.Empty:
                # break if there aren't any messages in the queue
                break
            # process the messages
            if command_name == "total_possibilities":
                self.progress_bar.set_total(value)
            elif command_name == "indeterminate_possibilities":
                self.progress_bar.indeterminate()
            elif command_name == "increment_progress":
                self.progress_bar.increment_progress()
            elif command_name == "done":
                done = True
            elif command_name == "outputs":
                # not called straight away to avoid updating the gui multiple times a set of messages
                outputs = value
            else:
                # raise an error
                raise ValueError("Invalid command {}".format(command_name))
        # if outputs were received, update the inner scroll window
        if outputs is not None:
            self.set_output(outputs)
        # ensures the outputs are updated before running self.done()
        if done:
            self.done()
        # schedule next update
        self.after(1000 // 30, self.update_from_solver)

    def go_back(self):
        """ Method to go back to the cipher window """
        self.stop_solver()
        self.application.show_existing(self.cipher_window)

    def stop_solver(self):
        """ Stop / wait for the solver to stop """
        if self.solver_process is not None:
            self.solver_process.terminate()
            self.solver_process.join()
            self.solver_process = None
            self.done()

    def done(self):
        """ Run when the Solver sends a message saying it is done """
        # mark the progress bar as done
        self.progress_bar.done()

        # hide stop button
        if self.stop_button is not None:
            self.stop_button.destroy()
            self.stop_button = None

        # show full texts in output boxes
        # Whilst the solver is running only the first 500 characters are displayed
        # of the outputs so Tkinter doesn't slow with the rapid updates
        for row, (text, key, score) in enumerate(self.outputs, start=1):
            self.outputs_inner_frame.grid_slaves(row=row,
                                                 column=2)[0].set_text(text)

    def set_output(self, outputs):
        """ Update the outputs displayed in the inner scroll window """
        # outputs should be in the format:
        #   [(text, key, score), (text, key, score) ... ]
        # and sorted by score

        frame = self.outputs_inner_frame
        for i in range(len(outputs)):
            text, key, score = outputs[i]
            # limit the length of the output to 500 characters to prevent tkinter
            # from slowing down
            if len(text) > 500:
                display_text = text[:500] + "..."
            else:
                display_text = text
            # row to display output on
            row = i + 1
            if i == len(self.outputs):
                # if this is a new row, create new blank placeholder widgets
                tk.Label(frame, text="").grid(row=row, column=0)
                self.solver.get_key_widget(frame).grid(row=row, column=1)
                OutputText(frame, wrap=tk.WORD, height=3,
                           width=80).grid(row=row, column=2)
                self.outputs.append(None)
            # update the widgets which already exist (or were just created)
            # if the output does not match the current one
            if outputs[i] != self.outputs[i]:
                frame.grid_slaves(
                    row=row, column=0)[0]["text"] = "{0:.3f}".format(score)
                self.solver.update_key_widget(
                    frame.grid_slaves(row=row, column=1)[0], key)
                frame.grid_slaves(row=row, column=2)[0].set_text(display_text)
                self.outputs[i] = outputs[i]
class DataFromServer(tk.Toplevel, object):
    def __init__(self, gui):
        if globals.debug > 1: print("datafromserver.__init__")
        # Setup the window
        super(DataFromServer, self).__init__(gui)

        self.gui = gui
        self.gui_root = self.gui.winfo_toplevel()

        self.pad = 5
        aspect = self.gui_root.winfo_screenheight(
        ) / self.gui_root.winfo_screenwidth()
        self.width = int(self.gui_root.winfo_screenwidth() / 4)
        height = self.width * aspect

        gui_root_path = os.path.dirname(
            os.path.dirname(os.path.realpath(__file__)))
        self.tmp_path = os.path.join(gui_root_path, "tmp")

        self.withdraw()

        self.protocol("WM_DELETE_WINDOW", self.close)
        self.resizable(False, False)
        self.title("Get data from server")
        self.configure(width=self.width, height=height)

        self.create_variables()
        self.create_widgets()
        self.place_widgets()

        self.filelist = []
        self.total_size = 0
        self.filenames = []
        self.server = ""

        self.thread = None

        # Show the window
        self.tk.eval('tk::PlaceWindow ' + str(self) + ' center')

        self.canceled = False
        self.subprocess = None

        #self.grab_set()

    def create_variables(self, *args, **kwargs):
        if globals.debug > 1: print("datafromserver.create_variables")
        # Gather the preferences
        preference = self.gui.get_preference("getdatafromserver")
        if preference is None:
            preference = {'username': '', 'address': '', 'path': ''}

        # Create variables
        self.username = tk.StringVar(value=preference['username'])
        self.address = tk.StringVar(value=preference['address'])
        self.path = tk.StringVar(value=preference['path'])

        self.command_choice = tk.StringVar(value='scp')
        self.command_options = tk.StringVar(value='-Cp')

    def create_widgets(self, *args, **kwargs):
        if globals.debug > 1: print("datafromserver.create_widgets")
        # Create widgets
        self.description = ttk.Label(
            self,
            text=
            "You must first ensure that you can ssh to the specified server without a password prompt. You can either specify a path to a single file, such as '/home/myuser/data0.dat' or to a pattern of files, such as '/home/myuser/data*.dat'.",
            wraplength=self.width - 2 * self.pad,
            justify='left',
        )
        self.server_info_frame = tk.Frame(self)

        self.server_username_label = tk.Label(
            self.server_info_frame,
            text="Username:"******"Server address:",
        )
        self.server_address_entry = tk.Entry(
            self.server_info_frame,
            width=30,
            textvariable=self.address,
        )

        self.filepath_label = tk.Label(
            self.server_info_frame,
            text="Remote file path:",
        )
        self.filepath_entry = tk.Entry(
            self.server_info_frame,
            width=30,
            textvariable=self.path,
        )

        self.command_choice_label = tk.Label(
            self.server_info_frame,
            text='Command:',
        )
        self.command_choice_frame = tk.Frame(self.server_info_frame)

        self.scp_button = tk.Radiobutton(
            self.command_choice_frame,
            text="scp",
            value="scp",
            variable=self.command_choice,
            command=self.on_scp_button_pressed,
        )
        self.rsync_button = tk.Radiobutton(
            self.command_choice_frame,
            text="rsync",
            value="rsync",
            variable=self.command_choice,
            command=self.on_rsync_button_pressed,
        )

        self.command_options_label = tk.Label(
            self.server_info_frame,
            text="Options:",
        )
        self.command_options_entry = tk.Entry(
            self.server_info_frame,
            textvariable=self.command_options,
        )

        self.progressbar = ProgressBar(self,
                                       orient='horizontal',
                                       maximum=100,
                                       mode='determinate')

        self.buttons_frame = tk.Frame(self)
        self.download_button = tk.Button(
            self.buttons_frame,
            text="Download",
            width=len("Download"),
            command=self.download_pressed,
        )
        self.close_button = tk.Button(
            self.buttons_frame,
            text="Close",
            command=self.close_soft,
        )

    def place_widgets(self, *args, **kwargs):
        if globals.debug > 1: print("datafromserver.place_widgets")
        # Place widgets
        self.description.pack(side='top',
                              fill='x',
                              padx=self.pad,
                              pady=(self.pad, 0))

        self.server_username_label.grid(row=0, column=0, sticky='nes')
        self.server_username_entry.grid(row=0, column=1, sticky='news')
        self.server_address_label.grid(row=1, column=0, sticky='nes')
        self.server_address_entry.grid(row=1, column=1, sticky='news')
        self.filepath_label.grid(row=2, column=0, sticky='nes')
        self.filepath_entry.grid(row=2, column=1, sticky='news')

        self.command_choice_label.grid(row=3, column=0, sticky='nes')
        self.rsync_button.pack(side='right', fill='both', expand=True)
        self.scp_button.pack(side='right', fill='both', expand=True)
        self.command_choice_frame.grid(row=3, column=1, sticky='nws')

        self.command_options_label.grid(row=4, column=0, sticky='nes')
        self.command_options_entry.grid(row=4, column=1, sticky='nws')

        self.server_info_frame.columnconfigure(1, weight=1)
        self.server_info_frame.pack(side='top',
                                    padx=self.pad,
                                    pady=(0, self.pad))

        self.progressbar.pack(side='left',
                              fill='x',
                              expand=True,
                              padx=(self.pad, 0),
                              pady=0)
        self.download_button.pack(side='right')
        self.close_button.pack(side='right')
        self.buttons_frame.pack(side='right',
                                fill='y',
                                pady=(0, self.pad),
                                padx=self.pad)

    def close(self, *args, **kwargs):
        if globals.debug > 1: print("datafromserver.close")
        self.grab_release()
        self.destroy()

    def close_soft(self, *args, **kwargs):
        if globals.debug > 1: print("datafromserver.close_soft")
        self.grab_release()
        self.cancel()
        self.destroy()

    def cancel(self, *args, **kwargs):
        if globals.debug > 1: print("datafromserver.cancel")
        self.canceled = True

        self.download_button.configure(relief='raised',
                                       text='Download',
                                       command=self.download_pressed)
        self.progressbar.set_text("Download canceled")
        self.progressbar.configure(value=0)
        self.enable_widgets()

        if self.thread is not None: self.thread.stop()
        if self.subprocess is not None:
            try:
                os.killpg(os.getpgid(self.subprocess.pid), signal.SIGTERM)
            except OSError:
                pass

    def on_scp_button_pressed(self, *args, **kwargs):
        if globals.debug > 1: print("datafromserver.on_scp_button_pressed")
        self.command_options.set("-Cp")

    def on_rsync_button_pressed(self, *args, **kwargs):
        if globals.debug > 1: print("datafromserver.on_rsync_button_pressed")
        self.command_options.set("-a")

    def set_widget_states(self, state):
        if globals.debug > 1: print("datafromserver.set_widget_states")
        for child in self.server_info_frame.winfo_children():
            if hasattr(child, "configure") and 'state' in child.configure():
                child.configure(state=state)

    def disable_widgets(self, *args, **kwargs):
        if globals.debug > 1: print("datafromserver.disable_widgets")
        self.set_widget_states('disabled')
        # Don't know why, but the radio buttons don't behave normally
        self.rsync_button.configure(state='disabled')
        self.scp_button.configure(state='disabled')

    def enable_widgets(self, *args, **kwargs):
        if globals.debug > 1: print("datafromserver.enable_widgets")
        self.set_widget_states('normal')
        # Don't know why, but the radio buttons don't behave normally
        self.rsync_button.configure(state='normal')
        self.scp_button.configure(state='normal')

    def download_pressed(self, *args, **kwargs):
        if globals.debug > 1: print("datafromserver.download_pressed")
        # Save the entries in the gui preferences so they pop up
        # automatically the next time we want to use them
        self.gui.set_preference(
            "getdatafromserver",
            {
                'username': self.username.get(),
                'address': self.address.get(),
                'path': self.path.get(),
            },
        )

        self.disable_widgets()

        # Reset the progressbar
        self.progressbar.configure(value=0)

        # Get the server
        self.server = self.username.get() + "@" + self.address.get()

        # Get the file list
        self.thread = ThreadedTask(
            self,
            target=self.get_file_list,
        )

        self.canceled = False
        self.download_button.configure(relief='sunken',
                                       text="Cancel",
                                       command=self.cancel)

        # Block until the task has finished
        while self.thread.isAlive():
            self.gui_root.update()

        if not self.canceled:
            # After getting the file list, start downloading the files
            self.progressbar.set_text("Starting download...")
            self.thread = ThreadedTask(
                self,
                target=self.download_files,
            )

            # Wait until the thread had finished
            while self.thread.isAlive():
                self.download_update()

            if not self.canceled:
                # Now add the downloaded files to the gui file list
                self.close()

                self.gui.update_filenames()
                self.gui.plotcontrols.current_file.set(self.gui.filenames[0])
                self.gui.read()
                self.gui.interactiveplot.update()
                self.gui.controls.save_state()

                return

        self.subprocess = None
        self.enable_widgets()
        self.progressbar.configure(value=0)

    def download_files(self, *args, **kwargs):
        if globals.debug > 1: print("datafromserver.download_files")
        cmd = self.command_choice.get() + " " + self.command_options.get(
        ) + " " + self.server + ":" + self.path.get() + " " + self.tmp_path
        self.subprocess = subprocess.Popen(
            cmd.split(" "),
            stdout=DEVNULL,
            stderr=subprocess.STDOUT,
            preexec_fn=os.setsid,
        )
        self.subprocess.communicate()

    def get_file_list(self, *args, **kwargs):
        if globals.debug > 1: print("datafromserver.get_file_list")
        # Get the list of files that will be downloaded
        self.progressbar.set_text("Retrieving file list...")
        self.subprocess = subprocess.Popen([
            "ssh",
            self.server,
            "stat -c '%s %n'",
            self.path.get(),
        ],
                                           stdout=subprocess.PIPE,
                                           stderr=DEVNULL,
                                           preexec_fn=os.setsid)

        stdout, stderr = self.subprocess.communicate()
        if not self.canceled:
            stdout = stdout.decode('ascii').strip().split("\n")
            self.filelist = [o.split(" ") for o in stdout]
            self.filenames = [f[1] for f in self.filelist]
            self.total_size = sum(
                [int(f[0].strip("'")) for f in self.filelist])

    def download_update(self, *args, **kwargs):
        if globals.debug > 1: print("datafromserver.download_update")
        filebasenames = [
            os.path.basename(filename) for filename in self.filenames
        ]

        filesintmp = os.listdir(self.tmp_path)

        tmpfilenames = []
        for filename in filebasenames:
            for tmpfilename in filesintmp:
                if filename in tmpfilename:
                    tmpfilenames.append(
                        os.path.join(self.tmp_path, tmpfilename))

        if tmpfilenames:
            cmd = "stat -c '%s' " + " ".join(tmpfilenames)
            result = None
            try:
                result = subprocess.check_output(
                    cmd.split(" "),
                    stderr=DEVNULL,
                ).decode('ascii').strip().split("\n")
            except subprocess.CalledProcessError:
                # This probably only happens when we search for a file that isn't there
                # (namely when rsync renames its temporary files to the expected filenames)
                pass

            if result is not None:
                for i in range(len(result)):
                    result[i] = float(result[i].strip("'"))

                progress = sum(result)
                current = progress / float(self.total_size) * 100
                self.progressbar.configure(value=current)
                self.progressbar.set_text("Downloading... (%3.2f%%)" % current)

        self.gui_root.update()
    def create_widgets(self, *args, **kwargs):
        if globals.debug > 1: print("datafromserver.create_widgets")
        # Create widgets
        self.description = ttk.Label(
            self,
            text=
            "You must first ensure that you can ssh to the specified server without a password prompt. You can either specify a path to a single file, such as '/home/myuser/data0.dat' or to a pattern of files, such as '/home/myuser/data*.dat'.",
            wraplength=self.width - 2 * self.pad,
            justify='left',
        )
        self.server_info_frame = tk.Frame(self)

        self.server_username_label = tk.Label(
            self.server_info_frame,
            text="Username:"******"Server address:",
        )
        self.server_address_entry = tk.Entry(
            self.server_info_frame,
            width=30,
            textvariable=self.address,
        )

        self.filepath_label = tk.Label(
            self.server_info_frame,
            text="Remote file path:",
        )
        self.filepath_entry = tk.Entry(
            self.server_info_frame,
            width=30,
            textvariable=self.path,
        )

        self.command_choice_label = tk.Label(
            self.server_info_frame,
            text='Command:',
        )
        self.command_choice_frame = tk.Frame(self.server_info_frame)

        self.scp_button = tk.Radiobutton(
            self.command_choice_frame,
            text="scp",
            value="scp",
            variable=self.command_choice,
            command=self.on_scp_button_pressed,
        )
        self.rsync_button = tk.Radiobutton(
            self.command_choice_frame,
            text="rsync",
            value="rsync",
            variable=self.command_choice,
            command=self.on_rsync_button_pressed,
        )

        self.command_options_label = tk.Label(
            self.server_info_frame,
            text="Options:",
        )
        self.command_options_entry = tk.Entry(
            self.server_info_frame,
            textvariable=self.command_options,
        )

        self.progressbar = ProgressBar(self,
                                       orient='horizontal',
                                       maximum=100,
                                       mode='determinate')

        self.buttons_frame = tk.Frame(self)
        self.download_button = tk.Button(
            self.buttons_frame,
            text="Download",
            width=len("Download"),
            command=self.download_pressed,
        )
        self.close_button = tk.Button(
            self.buttons_frame,
            text="Close",
            command=self.close_soft,
        )
Beispiel #27
0
class GeneralMainDesign(QMainWindow):
    """General design of the main window"""
    def __init__(self, QWidgetParent=None):
        QMainWindow.__init__(self, QWidgetParent)
        self._set_main_window()
        self.centralwidget = QWidget(self)

        layout = QVBoxLayout(self.centralwidget)
        layout.setContentsMargins(0, 0, 2, 0)
        layout.setSpacing(0)

        # query frame
        self.frame_query = QueryFrame()
        self._set_frame()
        layout.addWidget(self.frame_query)

        self.setCentralWidget(self.centralwidget)

        # status bar
        self.statusbar = QStatusBar(self)
        self._set_status_bar()
        self.setStatusBar(self.statusbar)

        self.progress_bar = ProgressBar(self)
        self.statusbar.addPermanentWidget(self.progress_bar)
        self.progress_bar.setVisible(False)

        self.dw_top = DockWidget(460, 90, 20000, 50)
        self.dw_top.setTitleBarWidget(QWidget())
        self.dwc_top = DockWidgetContentsTop()
        self.dw_top.setWidget(self.dwc_top)
        self.addDockWidget(QtCore.Qt.TopDockWidgetArea, self.dw_top)

        # dockwidget collection (left side)
        self.dw_collections = DockWidget(350, 620, 700, 20000)
        self.dw_collections.setTitleBarWidget(QWidget())
        self.dwc_left = DockWidgetContentsLeft(self)
        self.dw_collections.setWidget(self.dwc_left)
        self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.dw_collections)

        QtCore.QMetaObject.connectSlotsByName(self)

    def _set_main_window(self):
        """Sets the size policies of the main window"""
        self.resize(1000, 750)
        size_policy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        size_policy.setHorizontalStretch(0)
        size_policy.setVerticalStretch(0)
        size_policy.setHeightForWidth(self.sizePolicy().hasHeightForWidth())
        self.setSizePolicy(size_policy)
        self.setMinimumSize(QtCore.QSize(1000, 750))

        # main window icon
        self.setWindowIcon(QIcon(DUNYA_ICON))
        self.setWindowTitle('Dunya Desktop')

    def _set_frame(self):
        self.frame_query.setFrameShape(QFrame.StyledPanel)
        self.frame_query.setFrameShadow(QFrame.Raised)

    def _set_status_bar(self):
        self.statusbar.setMinimumSize(QtCore.QSize(0, 18))
        font = QFont()
        font.setPointSize(9)
        self.statusbar.setFont(font)