class QCliWidget(QWidget): interpreter = Interpreter() display_widget = None vkbd = None beamer = None result_from_queue = False set_tab_text = pyqtSignal(str) def __init__(self): super().__init__() self.unicode_fonts = UnicodeFonts() self.grid = QGridLayout() self.grid.setContentsMargins(0, 0, 0, 6) self.setLayout(self.grid) self.display_widget = QTextEditEnhanced() self.display_widget.setText( "type in the command 'man' down in the command line for getting started ..." ) self.display_widget.setReadOnly(True) self.addDisplayWidget() line = QInputLine() line.setPlaceholderText( "This is the command line. See 'man commandline' for details.") line.return_pressed.connect(self.commandEntered) self.grid.addWidget(line, 1, 0) vkbdButton = QPushButton(self) vkbdButton.clicked.connect(partial(self.vkbdButtonClicked, line)) vkbdButton.setIcon(QIcon.fromTheme('input-keyboard')) self.grid.addWidget(vkbdButton, 1, 1) zoomOutButton = QPushButton(self) zoomOutButton.setIcon(QIcon.fromTheme('zoom-out')) zoomOutButton.clicked.connect(self.onZoomOutClicked) self.grid.addWidget(zoomOutButton, 1, 2) zoomResetButton = QPushButton(self) zoomResetButton.setIcon(QIcon.fromTheme('zoom-original')) zoomResetButton.clicked.connect(self.onZoomResetClicked) self.grid.addWidget(zoomResetButton, 1, 3) zoomInButton = QPushButton(self) zoomInButton.setIcon(QIcon.fromTheme('zoom-in')) zoomInButton.clicked.connect(self.onZoomInClicked) self.grid.addWidget(zoomInButton, 1, 4) self.applyStylesheet() def applyStylesheet(self): config = ConfigFile(None, None) path = config.readVar('global', 'stylesheet') stylesheet = '' try: with open(path) as css: for line in css: stylesheet += line self.display_widget.setStyleSheet(stylesheet) except FileNotFoundError: pass def addDisplayWidget(self): self.view = QGraphicsView() self.scene = QGraphicsScene() self.scene.addWidget(self.display_widget) self.view.setScene(self.scene) self.view.setStyleSheet("QGraphicsView { border-style: none; }") self.grid.addWidget(self.view, 0, 0, 1, 0) self.resizeDisplayWidget() self.applyStylesheet() def resizeDisplayWidget(self): # the magick numbers are for keeping the size of the view allways small enough not to spawn an outer set of scrollbars: x = self.view.width() - 2.1 y = self.view.height() - 2.1 self.x, self.y = x, y mapped_rect = self.view.mapToScene(QRect(0, 0, x, y)).boundingRect() self.display_widget.setFixedSize(mapped_rect.width(), mapped_rect.height()) self.scene.setSceneRect(0, 0, mapped_rect.width(), mapped_rect.height()) def resizeEvent(self, event): self.resizeDisplayWidget() def vkbdButtonClicked(self, lineEdit): self.vkbd = QVirtualKeyboardWindow() self.vkbd.setLineEdit(lineEdit) def commandEntered(self, command): # to keep the display_widget in the correct size self.resize(self.x, self.y) print("command:", command) if '|' in command: command, pipe = command.split('|') self.handleCommand(command) pipe = pipe.strip() if pipe == 'beamer': if self.beamer: self.beamer.destroy() print('destroyed!!!') self.beamer = QBeamerWindow() from PyQt5.QtWidgets import QLabel, QPushButton widget = QLabel('blaaaa') self.beamer.setWidget(self.display_widget) #self.beamer.setText('test') self.beamer.routeToScreen() self.beamer.showFullScreen() else: #self.handleCommand(command) self.set_tab_text.emit(command) #self.activityIndicator() q = queue.Queue() self.interpreter_thread = HandleCommandThread(command, q) self.interpreter_thread.processResult.connect(self.processResult) self.interpreter_thread.clearDisplayWidget.connect( self.clearDisplayWidget) self.interpreter_thread.makeSnapshot.connect(self.makeSnapshot) self.interpreter_thread.stopQueueListener.connect( self.stopQueueListener) self.interpreter_thread.start() self.queue_thread = GetQueueItemsThread(q) self.queue_thread.processQueueItem.connect(self.processQueueItem) self.queue_thread.start() def stopQueueListener(self): self.queue_thread.stop() def processQueueItem(self, item): self.result_from_queue = True item = item.getItem() json_dict = json.loads(item) if json_dict['category'] == 'progressbar': last_type = type(self.display_widget) if not last_type == QProgressBar: self.display_widget.deleteLater() self.display_widget = QProgressBar() self.display_widget.setMinimum(json_dict['minimum']) self.display_widget.setMaximum(json_dict['maximum']) self.display_widget.setValue(json_dict['value']) if not last_type == QProgressBar: self.addDisplayWidget() else: result_object = Result() result_object.payload = item.getItem() self.resultInTextEdit(result_object) def processResult(self, result): if self.result_from_queue: self.result_from_queue = False else: #if result is None: #self.showErrorMessage('no result found') if hasattr(result, 'payload') and result.payload: if hasattr(result, 'category') and result.category == "table": try: result.payload[0] except IndexError: pass # datastructure does not fit to display type 'table' else: self.resultInTable(result) elif hasattr( result, 'category') and result.category == "multimedia_table": self.resultInMultimediaTable(result) elif hasattr(result, 'category') and result.category == "list": self.resultInTextEdit(result) elif hasattr(result, 'category') and result.category == "text": self.resultInTextEdit(result) elif hasattr(result, 'category') and result.category == "string": self.resultInTextEdit(result) elif hasattr(result, 'category') and result.category == "itemized": self.resultInItemizedWidget(result) elif hasattr(result, 'category') and result.category == "image": self.resultInImageWidget(result) elif hasattr(result, 'category') and result.category == "html": #self.resultInHTMLWidget(result) self.resultInTextEdit(result) elif hasattr(result, 'category') and result.category == 'diagram': self.resultInDiagram(result) elif hasattr(result, 'category') and result.category == 'bloodline': self.resultInBloodlineDiagram(result) elif hasattr(result, 'category') and result.category == 'command': self.showMapWidget() elif hasattr(result, 'error') and result.error: self.showErrorMessage(result.error) else: result = Result() result.payload = 'empty result set' self.resultInTextEdit(result) def activityIndicator(self): self.display_widget.deleteLater() label = QLabel() movie = QMovie('./assets/images/activity_indicator.gif') movie.start() label.setMovie(movie) self.display_widget = QWidget() layout = QVBoxLayout() self.display_widget.setLayout(layout) layout.addWidget(label, Qt.AlignCenter) self.addDisplayWidget() def clearDisplayWidget(self): self.display_widget.deleteLater() self.display_widget = QTextEditEnhanced() self.display_widget.setReadOnly(True) self.addDisplayWidget() def makeSnapshot(self): image = QImage(self.display_widget.size(), QImage.Format_ARGB32) painter = QPainter(image) if painter.isActive(): self.render(painter) painter.end() default_dir = path.join(path.expanduser('~')) filename = QFileDialog.getSaveFileName(self, 'Save Snapshot', default_dir) image.save(filename[0]) def resultInTable(self, result): self.display_widget.deleteLater() self.display_widget = QTableWidget() self.display_widget.setRowCount(len(result.payload)) self.display_widget.setColumnCount(len(result.payload[0])) try: self.display_widget.setHorizontalHeaderLabels(result.header) except TypeError: pass try: self.display_widget.setVerticalHeaderLabels(result.header_left) except TypeError: pass for row, line in enumerate(result.payload): for column, item in enumerate(line): table_item = QTableWidgetItem(str(item)) table_item.setFlags(Qt.ItemIsEnabled) self.unicode_fonts.applyFontToQWidget(str(item), table_item) self.display_widget.setItem(row, column, table_item) self.display_widget.resizeColumnsToContents() self.addDisplayWidget() def resultInMultimediaTable(self, result): self.display_widget.deleteLater() max_length = 0 for line in result.payload: if len(line) > max_length: max_length = len(line) self.display_widget = QTableWidget() self.display_widget.setRowCount(len(result.payload)) self.display_widget.setColumnCount(max_length) audio_count = 0 config = ConfigFile(None, None) deckpath = config.readPath("vocable", "deckpath") for row, line in enumerate(result.payload): deckname = line[0] for column, item in enumerate(line): if self.isImage(str(item)): pixmap = QPixmap() pixmap.load(path.join(deckpath, deckname, str(item))) pixmap = pixmap.scaled(QSize(60, 30), Qt.KeepAspectRatio) image_widget = QLabel() image_widget.setPixmap(pixmap) self.display_widget.setCellWidget(row, column, image_widget) elif self.isAudio(str(item)): splitted = item.split(',') if audio_count < len(splitted): audio_count = len(splitted) audio_widget = QAudioItems(path.join(deckpath, deckname), self.display_widget, 7, max_length) audio_widget.appendPlayButtonsList(splitted, row) else: table_item = QTableWidgetItem(str(item)) table_item.setFlags(Qt.ItemIsEnabled) #self.unicode_fonts.applyFontToQWidget(str(item), table_item) self.display_widget.setItem(row, column, table_item) self.display_widget.setColumnCount(max_length + audio_count) self.display_widget.resizeColumnsToContents() self.addDisplayWidget() def resultInTextEdit(self, result): self.display_widget.deleteLater() self.display_widget = QTextEditEnhanced() self.unicode_fonts.applyFontAndSizeToQWidget(result.toString(), self.display_widget) self.display_widget.setAcceptRichText(True) self.display_widget.setText(result.toString()) self.display_widget.setReadOnly(True) self.display_widget.setTextInteractionFlags( self.display_widget.textInteractionFlags() | Qt.TextSelectableByKeyboard) self.addDisplayWidget() def resultInHTMLWidget(self, result): self.display_widget.deleteLater() self.display_widget = QWebView() self.display_widget.setHtml(result.payload) self.addDisplayWidget() def resultInItemizedWidget(self, result): self.display_widget.deleteLater() self.display_widget = QItemizedWidget(result.payload) self.addDisplayWidget() def resultInImageWidget(self, result): self.display_widget.deleteLater() self.display_widget = QCustomizedGraphicsView() import PIL if type(result.payload) == PIL.Image.Image: from PIL.ImageQt import ImageQt qimage = ImageQt(result.payload) pixmap = QPixmap.fromImage(qimage) #pixmap = QPixmap("/tmp/tmprp3q0gi9.PNG") #pixmap.fromImage(image) item = self.display_widget.scene().addPixmap(pixmap) item.setPos(0, 0) self.addDisplayWidget() def resultInDiagram(self, result): self.display_widget.deleteLater() curve = QLineSeries() pen = curve.pen() pen.setColor(Qt.red) pen.setWidthF(2) curve.setPen(pen) for data in result.payload: if type(data['y']) == str: data['y'] = 0 curve.append(data['x'], data['y'], 10) chart = QChart() chart.setTitle(result.name) chart.legend().hide() chart.addSeries(curve) chart.createDefaultAxes() view = QChartViewEnhanced(chart) view.setRenderHint(QPainter.Antialiasing) self.display_widget = view self.addDisplayWidget() def resultInBloodlineDiagram(self, result): self.display_widget.deleteLater() self.display_widget = QBloodlineWidget(result.payload) self.addDisplayWidget() def showMapWidget(self): self.display_widget.deleteLater() self.display_widget = QMapWidget() self.display_widget.showPosition() self.addDisplayWidget() def showErrorMessage(self, message): self.display_widget.deleteLater() self.display_widget = QTextEditEnhanced() self.display_widget.setText(message) self.display_widget.setReadOnly(True) self.addDisplayWidget() def onZoomInClicked(self): if type(self.display_widget) == QTextEditEnhanced: self.display_widget.zoomIn() elif type(self.display_widget) == QChartViewEnhanced: self.display_widget.chart().zoomIn() else: self.view.scale(SCALE_FACTOR, SCALE_FACTOR) self.resizeDisplayWidget() def onZoomOutClicked(self): if type(self.display_widget) == QTextEditEnhanced: self.display_widget.zoomOut() elif type(self.display_widget) == QChartViewEnhanced: self.display_widget.chart().zoomOut() else: self.view.scale(1 / SCALE_FACTOR, 1 / SCALE_FACTOR) self.resizeDisplayWidget() def onZoomResetClicked(self): if type(self.display_widget) == QTextEditEnhanced: self.display_widget.zoomReset() elif type(self.display_widget) == QChartViewEnhanced: self.display_widget.chart().zoomReset() else: self.view.resetTransform() self.resizeDisplayWidget() def keyPressEvent(self, event): if (event.modifiers() & Qt.ControlModifier): if event.key() == Qt.Key_Plus: self.onZoomInClicked() elif event.key() == Qt.Key_Minus: self.onZoomOutClicked() def isImage(self, data): suffixes = ['.png', '.jpg', '.jpe', '.jpeg', '.svg', '.bmp'] for suffix in suffixes: if data.lower().endswith(suffix): return True return False def isAudio(self, data): suffixes = ['.ogg', '.wav', '.mp3', '.aiff', '.wma'] for suffix in suffixes: if data.lower().endswith(suffix): return True return False
class QSwordGui(QWidget): interpreter = Interpreter() queue = queue.Queue() sword = Sword() config = ConfigFile(os.path.join('modules', 'sword'), 'sword.conf') history = History("history_sword") set_tab_text = pyqtSignal(str) def __init__(self): super().__init__() self.unicode_fonts = UnicodeFonts() self.default_bible = self.config.readVar('global', 'default_bible') self.grid = QGridLayout() self.grid.setContentsMargins(0, 0, 0, 6) self.setLayout(self.grid) self.text_edit = QTextEditEnhanced() self.combo_language = QComboBox() self.combo_translation = QComboBox() self.combo_book = QComboBox() self.combo_chapter = QComboBox() self.combo_language.currentTextChanged.connect(self.languageChanged) self.combo_translation.currentTextChanged.connect( self.translationChanged) self.combo_book.currentTextChanged.connect(self.bookChanged) self.prev_verse_button = QPushButton("<") self.prev_verse_button.setMaximumSize(25, 25) self.next_verse_button = QPushButton(">") self.next_verse_button.setMaximumSize(25, 25) self.prev_verse_button.clicked.connect(self.prevChapter) self.next_verse_button.clicked.connect(self.nextChapter) self.grid.addWidget(QLabel("Language"), 0, 0) self.grid.addWidget(QLabel("Translation"), 0, 1) self.grid.addWidget(QLabel("Book"), 0, 2) self.grid.addWidget(QLabel("Chapter"), 0, 3) self.grid.addWidget(self.combo_language, 1, 0) self.grid.addWidget(self.combo_translation, 1, 1) self.grid.addWidget(self.combo_book, 1, 2) self.grid.addWidget(self.combo_chapter, 1, 3) self.grid.addWidget(self.prev_verse_button, 1, 4) self.grid.addWidget(self.next_verse_button, 1, 5) zoom_in_button = QPushButton(self) zoom_in_button.setIcon(QIcon.fromTheme('zoom-in')) zoom_in_button.clicked.connect(self.onZoomInClicked) zoom_in_button.setMaximumSize(25, 25) zoom_out_button = QPushButton(self) zoom_out_button.setIcon(QIcon.fromTheme('zoom-out')) zoom_out_button.clicked.connect(self.onZoomOutClicked) zoom_out_button.setMaximumSize(25, 25) zoom_reset_button = QPushButton(self) zoom_reset_button.setIcon(QIcon.fromTheme('zoom-original')) zoom_reset_button.clicked.connect(self.onZoomResetClicked) zoom_reset_button.setMaximumSize(25, 25) self.grid.addWidget(zoom_out_button, 1, 6) self.grid.addWidget(zoom_reset_button, 1, 7) self.grid.addWidget(zoom_in_button, 1, 8) self.grid.addWidget(self.text_edit, 2, 0, 1000, 9) self.getLanguagesForDropdown() self.getBooksForDropdown() self.setDefaultBible() self.restoreLastBookAndChapter() """ this has to be after setting the default values to avoid spamming the history on init and to avoid to much gui-updates on init """ self.combo_chapter.currentTextChanged.connect(self.chapterChanged) def languageChanged(self, language): self.getTranslationsForDropdown(language) def translationChanged(self, translation): self.showText() def bookChanged(self, book): self.getChaptersForDropdown(book) def chapterChanged(self, chapter): self.showText() def prevChapter(self): chapter = self.combo_chapter.currentText() self.combo_chapter.setCurrentText(str(int(chapter) - 1)) self.showText() def nextChapter(self): chapter = self.combo_chapter.currentText() self.combo_chapter.setCurrentText(str(int(chapter) + 1)) self.showText() def getLanguagesForDropdown(self): #result = self.interpreter.interpreter('sword.languages', self.queue).payload result = self.sword.listLanguages(None, []).payload if result is None: self.text_edit.clear() self.text_edit.setText( "no sword modules (=bibles) installed. please install some using the \"Sword->Module Manager\" menu entry." ) else: self.combo_language.clear() self.combo_language.insertItems(0, result) def getTranslationsForDropdown(self, language): #result = self.interpreter.interpreter('sword.modules '+language, self.queue).payload result = self.sword.listModules(None, [language]).payload translations = [] for translation in result: translations.append(translation[0]) self.combo_translation.clear() self.combo_translation.insertItems(0, translations) def setDefaultBible(self): #sword_modules = self.interpreter.interpreter('sword.modules', self.queue).payload sword_modules = self.sword.listModules(None, []).payload for module in sword_modules: if module[0] == self.default_bible: self.combo_language.setCurrentText(module[1]) self.combo_translation.setCurrentText(self.default_bible) def restoreLastBookAndChapter(self): last = self.history.historyReadAtIndex(3) try: translation, book, chapter = last.split(" ") self.combo_book.setCurrentText(book) self.combo_chapter.setCurrentText(chapter) self.showText() except ValueError: # probably we have an empty history-file pass def getBooksForDropdown(self): #books = self.interpreter.interpreter('sword.books', self.queue).payload books = self.sword.books(None, []).payload self.combo_book.clear() self.combo_book.insertItems(0, books) def getChaptersForDropdown(self, book): books = self.sword.canons() for testament in books: for _b in books[testament]: if _b[0] == book: chapters = [] for i, length in enumerate(_b[3]): chapters.append(str(i + 1)) self.combo_chapter.clear() self.combo_chapter.insertItems(0, chapters) break # if the inner 'break' was executed, we also want to break the outer loop: else: continue # executed if the loop ended normally (no break) break # executed if 'continue' was skipped (break) def showText(self): current_translation = self.interpreter.interpreter( 'sword.getModule', self.queue).payload translation = self.combo_translation.currentText() book = self.combo_book.currentText() chapter = self.combo_chapter.currentText() if translation: self.interpreter.interpreter('sword.setModule ' + translation, self.queue) text = self.interpreter.interpreter( 'sword.word "' + book + '" ' + chapter, self.queue) text = text.toString() self.interpreter.interpreter( 'sword.setModule ' + current_translation, self.queue) self.text_edit.clear() self.text_edit.setText(text) self.text_edit.append("\nEND") self.text_edit.setReadOnly(True) self.text_edit.setTextInteractionFlags( self.text_edit.textInteractionFlags() | Qt.TextSelectableByKeyboard) self.unicode_fonts.applyFontAndSizeToQWidget(text, self.text_edit) if book and chapter: self.set_tab_text.emit(translation + ": " + book + " " + chapter) self.history.historyWrite(translation + ": " + book + " " + chapter) def onZoomInClicked(self): self.text_edit.zoomIn() def onZoomOutClicked(self): self.text_edit.zoomOut() def onZoomResetClicked(self): self.text_edit.zoomReset()