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 __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 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()
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()
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
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]
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 __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 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()
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]
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()
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
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
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)
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()
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()
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()
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
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, )
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)