class ToolBar(QToolBar): back_button_clicked = pyqtSignal(name="backClicked") forward_button_clicked = pyqtSignal(name="forwardClicked") stop_reload_button_clicked = pyqtSignal(int, name="stopReloadClicked") address_changed = pyqtSignal(QUrl, name="addressChanged") dom_tree_viewer_clicked = pyqtSignal(name="domTreeViewerClicked") def __init__(self): QToolBar.__init__(self) self.setMovable(False) self.toggleViewAction().setEnabled(False) self.le = QLineEdit() self.init_ui() def init_ui(self): back_action = QAction(self) back_action.setShortcut(QKeySequence(Qt.Key_Back)) back_action.setIcon(QIcon("images/go-previous.png")) self.addAction(back_action) back_action.triggered.connect(self.back_button_clicked) forward_action = QAction(self) forward_action.setShortcut(QKeySequence(Qt.Key_Forward)) forward_action.setIcon(QIcon("images/go-next.png")) self.addAction(forward_action) forward_action.triggered.connect(self.forward_button_clicked) self.stop_reload_action = QAction(self) self.stop_reload_action.setShortcut(QKeySequence(Qt.Key_F5)) self.stop_reload_action.setIcon(QIcon("images/view-refresh.png")) self.stop_reload_action.setData(QWebEnginePage.Reload) self.addAction(self.stop_reload_action) self.stop_reload_action.triggered.connect( lambda: self.stop_reload_button_clicked.emit( QWebEnginePage.WebAction(self.stop_reload_action.data()))) fav_action = QAction(self) self.le.addAction(fav_action, QLineEdit.LeadingPosition) self.le.setClearButtonEnabled(True) self.addWidget(self.le) self.le.editingFinished.connect( lambda: self.address_changed.emit(QUrl(self.le.text()))) self.addSeparator() self.dom_tree_viewer = QAction(self) self.dom_tree_viewer.setIcon(QIcon("images/view-dom_tree.png")) self.dom_tree_viewer.triggered.connect(self.dom_tree_viewer_clicked) self.addAction(self.dom_tree_viewer) @pyqtSlot(bool, name="changeStopReload") def change_stop_reload(self, state): if state: self.stop_reload_action.setShortcut(QKeySequence(Qt.Key_F5)) self.stop_reload_action.setIcon(QIcon("images/view-refresh.png")) self.stop_reload_action.setData(QWebEnginePage.Reload) else: self.stop_reload_action.setShortcut(QKeySequence(Qt.Key_Escape)) self.stop_reload_action.setIcon(QIcon("images/process-stop.png")) self.stop_reload_action.setData(QWebEnginePage.Stop)
class Line(QDialog): ''' 单词拼写检查 ''' def __init__(self): ''' 一些初始设置 ''' super().__init__() self.Ui() def Ui(self): ''' 界面初始设置 ''' self.resize(450, 100) self.setWindowTitle('微信公众号:学点编程吧--单词拼写检查') self.line = QLineEdit(self) self.line.move(20, 20) action = QAction(self) action.setIcon(QIcon('check.ico')) action.triggered.connect(self.Check) self.line.addAction(action, QLineEdit.TrailingPosition) # 部件显示在文本右侧 self.show() def Check(self): ''' 检查下你写的是什么单词 ''' word = self.line.text() if correct(word) != word: QMessageBox.information(self, '提示信息', '你或许想要表达的单词是:' + correct(word)) else: QMessageBox.information(self, '提示信息', '你填写的单词是:' + word)
class Toolbar(QToolBar): back_button_clicked = pyqtSignal(name="backButtonClicked") forward_button_clicked = pyqtSignal(name="forwardButtonClicked") stop_reload_button_clicked = pyqtSignal(int, name="stopReloadButtonClicked") address_changed = pyqtSignal(str, name="addressChanged") def __init__(self): QToolBar.__init__(self) self.setMovable(False) self.toggleViewAction().setEnabled(False) self.setIconSize(QSize(24, 24)) # 뒤로가기 버튼 self.back_action = QAction(self) self.back_action.setShortcut(QKeySequence(Qt.Key_Back)) self.back_action.setIcon(QIcon("assets/svg/left.svg")) self.addAction(self.back_action) self.back_action.triggered.connect(self.back_button_clicked) # 앞으로가기 버튼 self.forward_action = QAction(self) self.forward_action.setShortcut(QKeySequence(Qt.Key_Forward)) self.forward_action.setIcon(QIcon("assets/svg/right.svg")) self.addAction(self.forward_action) self.forward_action.triggered.connect(self.forward_button_clicked) # 새로고침 취소 액션 self.stop_reload_action = QAction(self) self.stop_reload_action.setShortcut(QKeySequence(Qt.Key_F5)) self.stop_reload_action.setIcon(QIcon("assets/svg/reload.svg")) self.stop_reload_action.setData(QWebEnginePage.Reload) self.addAction(self.stop_reload_action) self.stop_reload_action.triggered.connect( lambda: self.stop_reload_button_clicked.emit( QWebEnginePage.WebAction(self.stop_reload_action.data()))) # 주소창 self.le = QLineEdit() fav_action = QAction(self) self.le.addAction(fav_action, QLineEdit.LeadingPosition) self.le.setClearButtonEnabled(True) self.le.setContentsMargins(8, 8, 8, 8) self.addWidget(self.le) self.le.editingFinished.connect( lambda: self.address_changed.emit(self.le.text())) @pyqtSlot(bool, name="changeStopReload") def change_stop_reload(self, state): if state: self.stop_reload_action.setShortcut(QKeySequence(Qt.Key_F5)) self.stop_reload_action.setIcon(QIcon("assets/svg/reload.svg")) self.stop_reload_action.setData(QWebEnginePage.Reload) else: self.stop_reload_action.setShortcut(QKeySequence(Qt.Key_Escape)) self.stop_reload_action.setIcon(QIcon("assets/svg/close.svg")) self.stop_reload_action.setData(QWebEnginePage.Stop)
class Page(QWizardPage): def __init__(self): super().__init__() vbox = QVBoxLayout(self) self.setTitle("Python Project") frame = QFrame() frame.setLineWidth(2) vbox.addStretch(1) frame.setFrameShape(QFrame.StyledPanel) vbox.addWidget(frame) box = QGridLayout(frame) box.addWidget(QLabel("Project Name:"), 0, 0) self._line_project_name = QLineEdit() self.registerField("name*", self._line_project_name) box.addWidget(self._line_project_name, 0, 1) box.addWidget(QLabel("Create in:"), 1, 0) self.line = QLineEdit() self.registerField("path", self.line) choose_dir_action = self.line.addAction( QIcon(self.style().standardPixmap( self.style().SP_DirIcon)), QLineEdit.TrailingPosition) box.addWidget(self.line, 1, 1) box.addWidget(QLabel("Interpreter:"), 2, 0) line_interpreter = QComboBox() line_interpreter.setEditable(True) line_interpreter.addItems(utils.get_python()) box.addWidget(line_interpreter, 2, 1) choose_dir_action.triggered.connect(self._choose_dir) self.line.setText(utils.get_home_dir()) def _choose_dir(self): directory = QFileDialog.getExistingDirectory( self, "Choose Directory", "~") if directory: self.line.setText(directory)
class FirstPage(QWizardPage): def __init__(self, parent=None): super().__init__(parent) self.setTitle("Nueva Base de Datos de Pireal") self.setSubTitle("A continuación elija el nombre y el destino de la DB") # Widgets box = QVBoxLayout(self) hbox = QHBoxLayout() hbox.addWidget(QLabel(self.tr("Database Name:"))) self._database_name_line = QLineEdit() hbox.addWidget(self._database_name_line) box.addLayout(hbox) hbox = QHBoxLayout() hbox.addWidget(QLabel(self.tr("Location:"))) self._database_location_line = QLineEdit() # Left action to change db location change_location_action = self._database_location_line.addAction( self.style().standardIcon(QStyle.SP_DirIcon), 1) self._database_location_line.setReadOnly(True) hbox.addWidget(self._database_location_line) box.addLayout(hbox) hbox = QHBoxLayout() hbox.addWidget(QLabel(self.tr("Filename:"))) self._database_filename_line = QLineEdit() self._database_filename_line.setReadOnly(True) hbox.addWidget(self._database_filename_line) box.addLayout(hbox) # Register fields self.registerField("dbname*", self._database_name_line) self.registerField("dblocation", self._database_location_line) self.registerField("dbfilename", self._database_filename_line) self.__location_folder = settings.PIREAL_DATABASES self._database_filename_line.setText(self.__location_folder) self._database_location_line.setText(self.__location_folder) # Conexiones self._database_name_line.textChanged.connect(self._update_filename) change_location_action.triggered.connect(self.__select_location) @pyqtSlot() def __select_location(self): location = QFileDialog.getExistingDirectory(self, self.tr("Select Folder")) if not location: return self._database_location_line.setText(location) self.__location_folder = os.path.join(self.__location_folder, location) self._database_filename_line.setText(os.path.join( location, self._database_name_line.text())) @pyqtSlot('QString') def _update_filename(self, filename): new_filename = os.path.join(self.__location_folder, filename) self._database_filename_line.setText(new_filename + '.pdb')
class Line(QDialog): def Ui(self): self.line = QLineEdit(self) self.line.move(20, 20) action = QAction(self) action.setIcon(QIcon('check.ico')) action.triggered.connect(self.Check) self.line.addAction(action, QLineEdit.TrailingPosition) def Check(self): word = self.line.text() if correct(word) != word: QMessageBox.information(self, '提示信息', '你或许想要表达的单词是:' + correct(word)) else: QMessageBox.information(self, '提示信息', '你填写的单词是:' + word)
def setAction(self, action, position=LeftPosition): """ Set `action` to be displayed at `position`. Existing action (if present) will be removed. Parameters ---------- action : :class:`QAction` position : int Position where to set the action (default: ``LeftPosition``). """ curr = self.actionAt(position) if curr is not None: self.removeAction(position) # Add the action using QWidget.addAction (for shortcuts) QLineEdit.addAction(self, action) button = LineEditButton(self) button.setToolButtonStyle(Qt.ToolButtonIconOnly) button.setDefaultAction(action) button.setVisible(self.isVisible()) button.show() button.setCursor(Qt.ArrowCursor) button.triggered.connect(self.triggered) button.triggered.connect(self.__onTriggered) slot = _ActionSlot(position, action, button, False) self.__actions[position - 1] = slot if not self.testAttribute(Qt.WA_Resized): # Need some sensible height to do the layout. self.adjustSize() self.__layoutActions()
class Page(QWizardPage): def __init__(self): super().__init__() vbox = QVBoxLayout(self) self.setTitle("Python Project") frame = QFrame() frame.setLineWidth(2) vbox.addStretch(1) frame.setFrameShape(QFrame.StyledPanel) vbox.addWidget(frame) box = QGridLayout(frame) box.addWidget(QLabel("Project Name:"), 0, 0) self._line_project_name = QLineEdit() self.registerField("name*", self._line_project_name) box.addWidget(self._line_project_name, 0, 1) box.addWidget(QLabel("Create in:"), 1, 0) self.line = QLineEdit() self.registerField("path", self.line) choose_dir_action = self.line.addAction( QIcon(self.style().standardPixmap( self.style().SP_DirIcon)), QLineEdit.TrailingPosition) box.addWidget(self.line, 1, 1) box.addWidget(QLabel("Interpreter:"), 2, 0) line_interpreter = QComboBox() line_interpreter.setEditable(True) line_interpreter.addItems(utils.get_python()) box.addWidget(line_interpreter, 2, 1) # from ninja_ide.utils import utils choose_dir_action.triggered.connect(self._choose_dir) self.line.setText(utils.get_home_dir()) def _choose_dir(self): directory = QFileDialog.getExistingDirectory( self, "Choose Directory", "~") if directory: self.line.setText(directory)
class MainWindow(QMainWindow): def __init__(self): try: with open('favs.yaml', 'r') as yaml_stream: self.fav_list = yaml.load(yaml_stream, Loader=yaml.SafeLoader) except: print("Cannot read yaml config file, check formatting.") self.fav_list = None super(MainWindow, self).__init__() self.setGeometry(0, 0, 700, 400) self.setContentsMargins(6, 6, 6, 6) self.setWindowTitle("pyRadioQt") self.setWindowIcon(QIcon('./icon/icon.png')) self.uiGenreCombo() self.uiSearchField() self.path = './icon/icon.png' self.pix = QPixmap(self.path) self.label_image = QLabel() self.label_image.setPixmap(QPixmap(self.pix)) self.field = QPlainTextEdit() self.field.setContextMenuPolicy(Qt.CustomContextMenu) self.field.customContextMenuRequested.connect(self.contextMenuRequested) self.field.cursorPositionChanged.connect(self.selectLine) self.field.setWordWrapMode(QTextOption.NoWrap) self.saveButton = QPushButton("Save as txt") self.saveButton.setIcon(QIcon.fromTheme("document-save")) self.saveButton.clicked.connect(self.saveStations) self.savePlaylistButton = QPushButton("Save as m3u") self.savePlaylistButton.setIcon(QIcon.fromTheme("document-save")) self.savePlaylistButton.clicked.connect(self.savePlaylist) # Toolbar self.tb = self.addToolBar("tools") self.tb.setContextMenuPolicy(Qt.PreventContextMenu) self.tb.setMovable(False) self.tb.addWidget(self.searchField) self.tb.addWidget(self.saveButton) self.tb.addWidget(self.savePlaylistButton) self.tb.addSeparator() self.tb.addWidget(self.genreCombo) # Main Layout self.createFavoriteLayout() self.mainWidget = QWidget(self) self.mainLayout = QVBoxLayout(self.mainWidget) self.centerLayout = QHBoxLayout() self.centerLayout.addWidget(self.label_image) self.centerLayout.addWidget(self.field) self.mainLayout.addLayout(self.centerLayout) self.mainLayout.addWidget(self.horizontalGroupBox) self.mainWidget.setLayout(self.mainLayout) self.setCentralWidget(self.mainWidget) # player ### self.player = QMediaPlayer() self.player.metaDataChanged.connect(self.metaDataChanged) self.startButton = QPushButton("Play") self.startButton.setIcon(QIcon.fromTheme("media-playback-start")) self.startButton.clicked.connect(self.getURLtoPlay) self.stopButton = QPushButton("Stop") self.stopButton.setIcon(QIcon.fromTheme("media-playback-stop")) self.stopButton.clicked.connect(self.stopPlayer) self.statusBar().addPermanentWidget(self.startButton) self.statusBar().addPermanentWidget(self.stopButton) # actions self.getNameAction = QAction(QIcon.fromTheme("edit-copy"), "copy Station Name", self, triggered=self.getName) self.getUrlAction = QAction(QIcon.fromTheme("edit-copy"), "copy Station URL", self, triggered=self.getURL) self.getNameAndUrlAction = QAction(QIcon.fromTheme("edit-copy"), "copy Station Name,URL", self, triggered=self.getNameAndUrl) self.getURLtoPlayAction = QAction(QIcon.fromTheme("media-playback-start"), "play Station", self, shortcut="F6", triggered=self.getURLtoPlay) self.addAction(self.getURLtoPlayAction) self.stopPlayerAction = QAction(QIcon.fromTheme("media-playback-stop"), "stop playing", self, shortcut="F7", triggered=self.stopPlayer) self.addAction(self.stopPlayerAction) self.helpAction = QAction(QIcon.fromTheme("help-info"), "Help", self, shortcut="F1", triggered=self.showHelp) self.addAction(self.helpAction) self.statusBar().showMessage("Welcome", 0) def uiGenreCombo(self): self.genreList = genres.splitlines() self.genreCombo = QComboBox() self.genreCombo.setFixedWidth(150) self.genreCombo.currentIndexChanged.connect(self.genreSearch) self.genreCombo.addItem("choose Genre") for m in self.genreList: self.genreCombo.addItem(m) def uiSearchField(self): self.searchField = QLineEdit() self.searchField.setFixedWidth(250) self.searchField.addAction(QIcon.fromTheme("edit-find"), 0) self.searchField.setPlaceholderText("type search term and press RETURN ") self.searchField.returnPressed.connect(self.findStations) def createFavoriteLayout(self): self.horizontalGroupBox = QGroupBox("Favorites") layout = QHBoxLayout() if self.fav_list is not None: self.buttongroup = QButtonGroup() self.buttongroup.buttonClicked[int].connect(self.handleButtonClicked) i = 1 for station in self.fav_list: #print(station) self.button = QPushButton(station, self) self.buttongroup.addButton(self.button, i) i = i + 1 layout.addWidget(self.button) else: l1 = QLabel() l1.setText("No Favorites") layout.addWidget(l1) self.horizontalGroupBox.setLayout(layout) def handleButtonClicked(self, id): for button in self.buttongroup.buttons(): if button is self.buttongroup.button(id): #print(button.text() + " Was Clicked ") for station, url in self.fav_list.items(): if station == button.text(): #print(url[0]) self.getURLtoPlay(True, station, url[0]) def genreSearch(self): if self.genreCombo.currentIndex() > 0: self.searchField.setText(self.genreCombo.currentText()) self.findStations() def getName(self): t = self.field.textCursor().selectedText().partition(",")[0] clip = QApplication.clipboard() clip.setText(t) def getURL(self): t = self.field.textCursor().selectedText().partition(",")[2] clip = QApplication.clipboard() clip.setText(t) def getNameAndUrl(self): t = self.field.textCursor().selectedText() clip = QApplication.clipboard() clip.setText(t) def selectLine(self): tc = self.field.textCursor() tc.select(QTextCursor.LineUnderCursor) tc.movePosition(QTextCursor.StartOfLine, QTextCursor.MoveAnchor) tc.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor) self.field.setTextCursor(tc) def showHelp(self): QMessageBox.information(self, "Information", "F6 -> play Station (from line where cursor is)\n\ F7 -> stop playing") def stopPlayer(self): self.player.stop() self.statusBar().showMessage("Player stopped", 0) # QPlainTextEdit contextMenu def contextMenuRequested(self, point): cmenu = QMenu() if not self.field.toPlainText() == "": cmenu.addAction(self.getNameAction) cmenu.addAction(self.getUrlAction) cmenu.addAction(self.getNameAndUrlAction) cmenu.addSeparator() cmenu.addAction(self.getURLtoPlayAction) cmenu.addAction(self.stopPlayerAction) cmenu.addSeparator() cmenu.addAction(self.helpAction) cmenu.exec_(self.field.mapToGlobal(point)) def getURLtoPlay(self, fav=False, name="", url_fav=""): url = "" stext = "" if fav: # print("url_fav=",url_fav) # print("name in func:", name) stext = name url = url_fav else: tc = self.field.textCursor() rtext = tc.selectedText().partition(",")[2] stext = tc.selectedText().partition(",")[0] if rtext.endswith(".pls"): url = self.getURLfromPLS(rtext) elif rtext.endswith(".m3u"): url = self.getURLfromM3U(rtext) else: url = rtext # print("stream url=", url) self.player.setMedia(QMediaContent(QUrl(url))) self.player.play() self.statusBar().showMessage("%s %s" % ("playing", stext), 0) def metaDataChanged(self): if self.player.isMetaDataAvailable(): trackInfo = (self.player.metaData("Title")) trackInfo2 = (self.player.metaData("Comment")) if trackInfo is not None: self.statusBar().showMessage(trackInfo, 0) if trackInfo2 is not None: self.statusBar().showMessage("%s %s" % (trackInfo, trackInfo2)) def getURLfromPLS(self, inURL): if "&" in inURL: inURL = inURL.partition("&")[0] response = request.urlopen(inURL) html = response.read().decode("utf-8").splitlines() if len(html) > 3: if "http" in str(html[1]): t = str(html[1]) elif "http" in str(html[2]): t = str(html[2]) elif "http" in str(html[3]): t = str(html[3]) elif len(html) > 2: if "http" in str(html[1]): t = str(html[1]) elif "http" in str(html[2]): t = str(html[2]) else: t = str(html[0]) url = t.partition("=")[2].partition("'")[0] # print(url) return (url) def getURLfromM3U(self, inURL): if "?u=" in inURL: inURL = inURL.partition("?u=")[2] if "&" in inURL: inURL = inURL.partition("&")[0] response = request.urlopen(inURL) html = response.read().splitlines() if len(html) > 1: if "http" in str(html[1]): t = str(html[1]) else: t = str(html[0]) else: t = str(html[0]) url = t.partition("'")[2].partition("'")[0] # print(url) return (url) def findStations(self): self.field.setPlainText("") mysearch = self.searchField.text() self.statusBar().showMessage("searching ...") rb = RadioBrowser() myparams = {'name': 'search', 'nameExact': 'false'} for key in myparams.keys(): if key == "name": myparams[key] = mysearch self.r = rb.station_search(params=myparams) n = "" m = "" for i in range(len(self.r)): for key, value in self.r[i].items(): if str(key) == "favicon": self.path = value print(self.path) if str(key) == "name": n = value.replace(",", " ") # print (n) if str(key) == "url": m = value self.field.appendPlainText("%s,%s" % (n, m)) # self.combo.setCurrentIndex(0) if not self.field.toPlainText() == "": self.statusBar().showMessage("found " + str(self.field.toPlainText().count('\n')+1) + " '" + self.searchField.text() + "' Stations") else: self.statusBar().showMessage("nothing found", 0) # self.field.textCursor().movePosition(QTextCursor.Start, Qt.MoveAnchor) def saveStations(self): if not self.field.toPlainText() == "": path, _ = QFileDialog.getSaveFileName(None, "RadioStations", self.searchField.text() + ".txt", "Text Files (*.txt)") if path: s = self.field.toPlainText() with open(path, 'w') as f: f.write(s) f.close() self.statusBar().showMessage("saved!", 0) def savePlaylist(self): if not self.field.toPlainText() == "": path, _ = QFileDialog.getSaveFileName(None, "RadioStations", self.searchField.text() + ".m3u", "Playlist Files (*.m3u)") if path: result = "" s = self.field.toPlainText() st = [] for line in s.splitlines(): st.append(line) result += "#EXTM3U" result += '\n' for x in range(len(st)): result += "#EXTINF:" + str(x) + "," + st[x].partition(",")[0] result += '\n' result += st[x].partition(",")[2] result += '\n' with open(path, 'w') as f: f.write(result) f.close() self.statusBar().showMessage("saved!", 0)
class MyWindow_2(QMainWindow): def __init__(self, aPath, parent=None): super(MyWindow_2, self).__init__(parent) # QIcon.setThemeName('gnome') QMetaObject.connectSlotsByName(self) self.delimit = '\t' self.mycolumn = 0 self.MaxRecentFiles = 5 self.windowList = [] self.recentFileActs = [] self.settings = QSettings('Axel Schneider', 'CSVEditor') self.setAttribute(Qt.WA_DeleteOnClose) self.isChanged = False self.fileName = "" self.fname = "Liste" self.mytext = "" self.colored = False self.copiedRow = [] self.copiedColumn = [] ### QTableView seetings self.tableView = TableWidgetDragRows() # self.tableView.horizontalHeader().setStretchLastSection(True) self.tableView.setGridStyle(1) self.tableView.setCornerButtonEnabled(False) self.tableView.setShowGrid(True) self.tableView.selectionModel().selectionChanged.connect( self.makeAllWhite) self.tableView.itemClicked.connect(self.getItem) self.tableView.setEditTriggers(QAbstractItemView.DoubleClicked) self.tableView.cellChanged.connect(self.finishedEdit) self.tableView.setDropIndicatorShown(True) self.findBar = QLineEdit() self.findBar.addAction(QIcon.fromTheme("gtk-find"), 0) self.findBar.setPlaceholderText("find") self.findBar.setFixedWidth(200) self.findBar.returnPressed.connect(self.findText) self.editLine = QLineEdit() self.editLine.setToolTip("edit and press ENTER") self.editLine.setStatusTip("edit and press ENTER") self.editLine.returnPressed.connect(self.updateCell) grid = QGridLayout() grid.setSpacing(1) grid.addWidget(self.editLine, 0, 0) grid.addWidget(self.findBar, 0, 1) grid.addWidget(self.tableView, 1, 0, 1, 3) mywidget = QWidget() mywidget.setLayout(grid) self.setCentralWidget(mywidget) self.isChanged = False self.createActions() self.createMenuBar() self.setStyleSheet(stylesheet(self)) self.readSettings() self.msg("Welcome to CSV Reader") if len(sys.argv) > 1: print(sys.argv[1]) self.fileName = sys.argv[1] self.loadCsvOnOpen(self.fileName) self.msg(self.fileName + "loaded") else: self.msg("Ready") self.addRow() self.isChanged = False def changeSelection(self): self.tableView.setSelectionMode(QAbstractItemView.ExtendedSelection) def updateCell(self): if self.tableView.selectionModel().hasSelection(): row = self.selectedRow() column = self.selectedColumn() newtext = QTableWidgetItem(self.editLine.text()) self.tableView.setItem(row, column, newtext) def getItem(self): item = self.tableView.selectedItems()[0] row = self.selectedRow() column = self.selectedColumn() if not item == None: name = item.text() else: name = "" self.msg("'" + name + "' on Row " + str(row + 1) + " Column " + str(column + 1)) self.editLine.setText(name) def selectedRow(self): if self.tableView.selectionModel().hasSelection(): row = self.tableView.selectionModel().selectedIndexes()[0].row() return int(row) def selectedColumn(self): column = self.tableView.selectionModel().selectedIndexes()[0].column() return int(column) def findText(self): self.findTableItems() self.changeSelection() def findTableItems(self): # self.tableView.setSelectionMode(QAbstractItemView.MultiSelection) findText = self.findBar.text() self.tableView.clearSelection() # if findText.isnumeric(): # items = self.tableView.findItems(findText, Qt.MatchExactly) # else: items = self.tableView.findItems(findText, Qt.MatchContains) if items: self.colored = True self.makeAllWhite() for item in items: item.setBackground(Qt.yellow) self.colored = True self.isChanged = False def findThis(self): # self.tableView.setSelectionMode(QAbstractItemView.MultiSelection) self.tableView.clearSelection() items = self.tableView.findItems(self.mytext, Qt.MatchContains) if items: self.colored = True self.makeAllWhite() for item in items: item.setBackground(Qt.yellow) item.setForeground(Qt.blue) self.colored = True self.isChanged = False def msgbox(self, message): QMessageBox.warning(self, "Message", message) def createMenuBar(self): bar = self.menuBar() self.filemenu = bar.addMenu("File") self.separatorAct = self.filemenu.addSeparator() self.filemenu.addAction(QIcon.fromTheme("document-new"), "New", self.newCsv, QKeySequence.New) self.filemenu.addAction(QIcon.fromTheme("document-open"), "Open", self.loadCsv, QKeySequence.Open) self.filemenu.addAction(QIcon.fromTheme("document-save"), "Save", self.saveOnQuit, QKeySequence.Save) self.filemenu.addAction(QIcon.fromTheme("document-save-as"), "Save as ...", self.writeCsv, QKeySequence.SaveAs) self.filemenu.addSeparator() self.filemenu.addAction(QIcon.fromTheme("document-print-preview"), "Print Preview", self.handlePreview, "Shift+Ctrl+P") self.filemenu.addAction(QIcon.fromTheme("document-print"), "Print", self.handlePrint, QKeySequence.Print) self.filemenu.addSeparator() for i in range(self.MaxRecentFiles): self.filemenu.addAction(self.recentFileActs[i]) self.updateRecentFileActions() self.filemenu.addSeparator() self.clearRecentAct = QAction("clear Recent Files List", self, triggered=self.clearRecentFiles) self.clearRecentAct.setIcon(QIcon.fromTheme("edit-clear")) self.filemenu.addAction(self.clearRecentAct) self.filemenu.addSeparator() self.filemenu.addAction(QIcon.fromTheme("application-exit"), "Exit", self.handleQuit, QKeySequence.Quit) self.editmenu = bar.addMenu("Edit") self.editmenu.addAction(self.actionUndo) self.editmenu.addAction(self.actionRedo) self.editmenu.addSeparator() self.editmenu.addAction(QIcon.fromTheme("edit"), "first row to headers", self.setHeaders) self.editmenu.addAction(QIcon.fromTheme("edit"), "headers to first row", self.setHeadersToFirstRow) self.editmenu.addSeparator() self.editmenu.addAction(QIcon.fromTheme("edit-copy"), "copy Cell", self.copyByContext, QKeySequence.Copy) self.editmenu.addAction(QIcon.fromTheme("edit-paste"), "paste Cell", self.pasteByContext, QKeySequence.Paste) self.editmenu.addAction(QIcon.fromTheme("edit-cut"), "cut Cell", self.cutByContext, QKeySequence.Cut) self.editmenu.addAction(QIcon.fromTheme("edit-delete"), "delete Cell", self.deleteCell, QKeySequence.Delete) self.editmenu.addSeparator() self.editmenu.addAction(QIcon.fromTheme("edit-copy"), "copy Row", self.copyRow) self.editmenu.addAction(QIcon.fromTheme("edit-paste"), "paste Row", self.pasteRow) self.editmenu.addSeparator() self.editmenu.addAction(QIcon.fromTheme("edit-copy"), "copy Column", self.copyColumn) self.editmenu.addAction(QIcon.fromTheme("edit-paste"), "paste Column", self.pasteColumn) self.editmenu.addSeparator() self.editmenu.addAction(QIcon.fromTheme("add"), "add Row", self.addRow) self.editmenu.addAction(QIcon.fromTheme("edit-delete"), "remove Row", self.removeRow) self.editmenu.addSeparator() self.editmenu.addAction(QIcon.fromTheme("add"), "add Column", self.addColumn) self.editmenu.addAction(QIcon.fromTheme("edit-delete"), "remove Column", self.removeColumn) self.editmenu.addSeparator() self.editmenu.addAction(QIcon.fromTheme("edit-clear"), "clear List", self.clearList) self.editmenu.addSeparator() self.editmenu.addAction(QIcon.fromTheme("pane-show-symbolic"), "toggle horizontal Headers", self.toggleHorizHeaders) self.editmenu.addAction(QIcon.fromTheme("pane-hide-symbolic"), "toggle vertical Headers", self.toggleVertHeaders) self.editmenu.addAction(self.whiteAction) self.editmenu = bar.addMenu("Help") def deleteCell(self): row = self.selectedRow() col = self.selectedColumn() self.tableView.takeItem(row, col) def toggleHorizHeaders(self): if self.tableView.horizontalHeader().isVisible(): self.tableView.horizontalHeader().setVisible(False) else: self.tableView.horizontalHeader().setVisible(True) def toggleVertHeaders(self): if self.tableView.verticalHeader().isVisible(): self.tableView.verticalHeader().setVisible(False) else: self.tableView.verticalHeader().setVisible(True) def createActions(self): self.actionUndo = QAction(self) icon = QIcon.fromTheme("edit-undo") self.actionUndo.setText("Undo") self.actionUndo.setIcon(icon) self.actionUndo.setObjectName("actionUndo") self.actionUndo.setShortcut(QKeySequence.Undo) self.actionRedo = QAction(self) icon = QIcon.fromTheme("edit-redo") self.actionRedo.setText("Redo") self.actionRedo.setIcon(icon) self.actionRedo.setObjectName("actionRedo") self.actionRedo.setShortcut(QKeySequence.Redo) # all items white BG self.whiteAction = QAction(QIcon.fromTheme("pane-hide-symbolic"), "all items white background", self) self.whiteAction.triggered.connect(lambda: self.makeAllWhite()) for i in range(self.MaxRecentFiles): self.recentFileActs.append( QAction(self, visible=False, triggered=self.openRecentFile)) def openRecentFile(self): action = self.sender() if action: if self.isChanged == True: quit_msg = "<b>The Document was changed.<br>Do you want to save changes?</ b>" reply = QMessageBox.question(self, 'Save Confirmation', quit_msg, QMessageBox.Yes, QMessageBox.No) if reply == QMessageBox.Yes: self.saveOnQuit() file = action.data() if QFile.exists(file): self.loadCsvOnOpen(file) else: self.msg("File not exists") def handleQuit(self): quit() def loadCsvOnOpen(self, fileName): if fileName: f = open(fileName, 'r', encoding='utf-8') mystring = f.read() ### comma if mystring.count(",") > mystring.count('\t'): if mystring.count(",") > mystring.count(';'): self.delimit = "," elif mystring.count(";") > mystring.count(','): self.delimit = ";" else: self.delimit = "\t" elif mystring.count(";") > mystring.count('\t'): self.delimit = ';' else: self.delimit = "\t" # print(mystring) f.close() f = open(fileName, 'r', encoding='utf-8') self.tableView.setRowCount(0) self.tableView.setColumnCount(0) for rowdata in csv.reader(f, delimiter=self.delimit): row = self.tableView.rowCount() self.tableView.insertRow(row) if len(rowdata) == 0: self.tableView.setColumnCount(len(rowdata) + 1) else: self.tableView.setColumnCount(len(rowdata)) for column, data in enumerate(rowdata): item = QTableWidgetItem(data) self.tableView.setItem(row, column, item) self.tableView.selectRow(0) self.isChanged = False self.setCurrentFile(fileName) self.tableView.resizeColumnsToContents() self.tableView.resizeRowsToContents() self.msg(fileName + " loaded") def loadCsv(self): if self.isChanged == True: quit_msg = "<b>The Document was changed.<br>Do you want to save changes?</ b>" reply = QMessageBox.question(self, 'Save Confirmation', quit_msg, QMessageBox.Yes, QMessageBox.No) if reply == QMessageBox.Yes: self.saveOnQuit() fileName, _ = QFileDialog.getOpenFileName( self, "Open CSV", (QDir.homePath() + "/Dokumente/CSV"), "CSV (*.csv *.tsv *.txt)") if fileName: self.loadCsvOnOpen(fileName) def newCsv(self): if self.isChanged == True: quit_msg = "<b>The Document was changed.<br>Do you want to save changes?</ b>" reply = QMessageBox.question(self, 'Save Confirmation', quit_msg, QMessageBox.Yes, QMessageBox.No) if reply == QMessageBox.Yes: self.saveOnQuit() i = 0 for row in range(self.tableView.rowCount()): self.tableView.removeRow(i) i = +1 j = 0 for column in range(self.tableView.columnCount()): self.tableView.removeColumn(j) j = +1 self.tableView.clearContents() self.fileName = "" self.setWindowTitle('New' + "[*]") self.isChanged = False def writeCsv(self): path, _ = QFileDialog.getSaveFileName(self, 'Save File', QDir.homePath() + "/export.csv", "CSV Files(*.csv *.txt)") if path: with open(path, 'w') as stream: print("saving", path) writer = csv.writer(stream, delimiter=self.delimit) for row in range(self.tableView.rowCount()): rowdata = [] for column in range(self.tableView.columnCount()): item = self.tableView.item(row, column) if item is not None: rowdata.append(item.text()) else: rowdata.append('') writer.writerow(rowdata) self.isChanged = False self.setCurrentFile(path) def handlePrint(self): if self.tableView.rowCount() == 0: self.msg("no rows") else: dialog = QtPrintSupport.QPrintDialog() if dialog.exec_() == QDialog.Accepted: self.handlePaintRequest(dialog.printer()) self.msg("Document printed") def handlePreview(self): if self.tableView.rowCount() == 0: self.msg("no rows") else: dialog = QtPrintSupport.QPrintPreviewDialog() dialog.setFixedSize(1000, 700) dialog.paintRequested.connect(self.handlePaintRequest) dialog.exec_() self.msg("Print Preview closed") def handlePaintRequest(self, printer): printer.setDocName(self.fname) document = QTextDocument() cursor = QTextCursor(document) model = self.tableView.model() tableFormat = QTextTableFormat() tableFormat.setBorder(0.2) tableFormat.setBorderStyle(3) tableFormat.setCellSpacing(0) tableFormat.setTopMargin(0) tableFormat.setCellPadding(4) table = cursor.insertTable(model.rowCount() + 1, model.columnCount(), tableFormat) model = self.tableView.model() ### get headers myheaders = [] for i in range(0, model.columnCount()): myheader = model.headerData(i, Qt.Horizontal) cursor.insertText(str(myheader)) cursor.movePosition(QTextCursor.NextCell) ### get cells for row in range(0, model.rowCount()): for col in range(0, model.columnCount()): index = model.index(row, col) cursor.insertText(str(index.data())) cursor.movePosition(QTextCursor.NextCell) document.print_(printer) def removeRow(self): if self.tableView.rowCount() > 0: row = self.selectedRow() tableView.removeRow(row) self.isChanged = True def addRow(self): if self.tableView.rowCount() > 0: if self.tableView.selectionModel().hasSelection(): row = self.selectedRow() item = QTableWidgetItem("") self.tableView.insertRow(row, 0, item) else: row = 0 item = QTableWidgetItem("") self.tableView.insertRow(row, 0, item) self.tableView.selectRow(0) else: self.tableView.setRowCount(1) if self.tableView.columnCount() == 0: self.addColumn() self.tableView.selectRow(0) self.isChanged = True def clearList(self): self.tableView.clear() self.isChanged = True def removeColumn(self): self.tableView.removeColumn(self.selectedColumn()) self.isChanged = True def addColumn(self): count = self.tableView.columnCount() self.tableView.setColumnCount(count + 1) self.tableView.resizeColumnsToContents() self.isChanged = True if self.tableView.rowCount() == 0: self.addRow() self.tableView.selectRow(0) def makeAllWhite(self): if self.colored == True: for row in range(self.tableView.rowCount()): for column in range(self.tableView.columnCount()): item = self.tableView.item(row, column) if item is not None: item.setForeground(Qt.black) item.setBackground(QColor("#fbfbfb")) self.colored = False def finishedEdit(self): self.isChanged = True def contextMenuEvent(self, event): self.menu = QMenu(self) if self.tableView.selectionModel().hasSelection(): # copy copyAction = QAction(QIcon.fromTheme("edit-copy"), 'Copy Cell', self) copyAction.triggered.connect(lambda: self.copyByContext()) # paste pasteAction = QAction(QIcon.fromTheme("edit-paste"), 'Paste Cell', self) pasteAction.triggered.connect(lambda: self.pasteByContext()) # cut cutAction = QAction(QIcon.fromTheme("edit-cut"), 'Cut Cell', self) cutAction.triggered.connect(lambda: self.cutByContext()) # delete selected Row removeAction = QAction(QIcon.fromTheme("edit-delete"), 'delete Row', self) removeAction.triggered.connect( lambda: self.deleteRowByContext(event)) # add Row after addAction = QAction(QIcon.fromTheme("add"), 'insert new Row after', self) addAction.triggered.connect(lambda: self.addRowByContext(event)) # add Row before addAction2 = QAction(QIcon.fromTheme("add"), 'insert new Row before', self) addAction2.triggered.connect(lambda: self.addRowByContext2(event)) # add Column before addColumnBeforeAction = QAction(QIcon.fromTheme("add"), 'insert new Column before', self) addColumnBeforeAction.triggered.connect( lambda: self.addColumnBeforeByContext(event)) # add Column after addColumnAfterAction = QAction(QIcon.fromTheme("add"), 'insert new Column after', self) addColumnAfterAction.triggered.connect( lambda: self.addColumnAfterByContext(event)) # delete Column deleteColumnAction = QAction(QIcon.fromTheme("edit-delete"), 'delete Column', self) deleteColumnAction.triggered.connect( lambda: self.deleteColumnByContext(event)) # replace all row = self.selectedRow() col = self.selectedColumn() myitem = self.tableView.item(row, col) if myitem is not None: self.mytext = myitem.text() replaceThisAction = QAction( QIcon.fromTheme("edit-find-and-replace"), "replace all occurrences of '" + self.mytext + "'", self) replaceThisAction.triggered.connect(lambda: self.replaceThis()) # find all findThisAction = QAction( QIcon.fromTheme("edit-find"), "find all rows contains '" + self.mytext + "'", self) findThisAction.triggered.connect(lambda: self.findThis()) ### self.menu.addAction(copyAction) self.menu.addAction(pasteAction) self.menu.addAction(cutAction) self.menu.addSeparator() self.menu.addAction(QIcon.fromTheme("edit-delete"), "delete", self.deleteCell, QKeySequence.Delete) self.menu.addSeparator() self.menu.addAction(QIcon.fromTheme("edit-copy"), "copy Row", self.copyRow) self.menu.addAction(QIcon.fromTheme("edit-paste"), "paste Row", self.pasteRow) self.menu.addSeparator() self.menu.addAction(QIcon.fromTheme("edit-copy"), "copy Column", self.copyColumn) self.menu.addAction(QIcon.fromTheme("edit-paste"), "paste Column", self.pasteColumn) self.menu.addSeparator() self.menu.addAction(addAction) self.menu.addAction(addAction2) self.menu.addSeparator() self.menu.addAction(addColumnBeforeAction) self.menu.addAction(addColumnAfterAction) self.menu.addSeparator() self.menu.addAction(removeAction) self.menu.addAction(deleteColumnAction) self.menu.addSeparator() self.menu.addAction(replaceThisAction) self.menu.addAction(findThisAction) self.menu.addSeparator() self.menu.addAction(self.whiteAction) self.menu.popup(QCursor.pos()) def replaceThis(self): row = self.selectedRow() col = self.selectedColumn() myitem = self.tableView.item(row, col) if myitem is not None: mytext = myitem.text() dlg = QInputDialog() newtext, ok = dlg.getText( self, "Replace all", "replace all <b>" + mytext + " </b> with:", QLineEdit.Normal, "", Qt.Dialog) if ok: items = self.tableView.findItems(mytext, Qt.MatchExactly) if items: for item in items: newItem = QTableWidgetItem(newtext) self.tableView.setItem(item.row(), item.column(), newItem) def deleteRowByContext(self, event): row = self.selectedRow() self.tableView.removeRow(row) self.msg("Row " + str(row) + " deleted") self.tableView.selectRow(row) self.isChanged = True def addRowByContext(self, event): if self.tableView.columnCount() == 0: self.tableView.setColumnCount(1) if self.tableView.rowCount() == 0: self.tableView.setRowCount(1) self.tableView.selectRow(0) else: row = self.selectedRow() self.tableView.insertRow(row + 1) self.msg("Row at " + str(row) + " inserted") self.tableView.selectRow(row + 1) self.isChanged = True def addRowByContext2(self, event): if self.tableView.columnCount() == 0: self.tableView.setColumnCount(1) if self.tableView.rowCount() == 0: self.tableView.setRowCount(1) self.tableView.selectRow(0) else: row = self.selectedRow() self.tableView.insertRow(row) self.msg("Row at " + str(row) + " inserted") self.tableView.selectRow(row) self.isChanged = True def addColumnBeforeByContext(self, event): if self.tableView.columnCount() == 0: self.tableView.setColumnCount(1) else: col = self.selectedColumn() self.tableView.insertColumn(col) self.msg("Column at " + str(col) + " inserted") if self.tableView.rowCount() == 0: self.tableView.setRowCount(1) self.isChanged = True def addColumnAfterByContext(self, event): if self.tableView.columnCount() == 0: self.tableView.setColumnCount(1) else: col = self.selectedColumn() + 1 self.tableView.insertColumn(col) self.msg("Column at " + str(col) + " inserted") if self.tableView.rowCount() == 0: self.tableView.setRowCount(1) self.isChanged = True def deleteColumnByContext(self, event): col = self.selectedColumn() self.tableView.removeColumn(col) self.msg("Column at " + str(col) + " removed") self.isChanged = True def copyByContext(self): row = self.selectedRow() col = self.selectedColumn() myitem = self.tableView.item(row, col) if myitem is not None: clip = QApplication.clipboard() clip.setText(myitem.text()) def pasteByContext(self): row = self.selectedRow() col = self.selectedColumn() clip = QApplication.clipboard() newItem = QTableWidgetItem(clip.text()) self.tableView.setItem(row, col, newItem) self.tableView.resizeColumnsToContents() self.isChanged = True def cutByContext(self): row = self.selectedRow() col = self.selectedColumn() myitem = self.tableView.item(row, col) if myitem is not None: clip = QApplication.clipboard() clip.setText(myitem.text()) newItem = QTableWidgetItem("") self.tableView.setItem(row, col, newItem) self.isChanged = True def closeEvent(self, event): if self.isChanged == True: quit_msg = "<b>The document was changed.<br>Do you want to save the changes?</ b>" reply = QMessageBox.question(self, 'Save Confirmation', quit_msg, QMessageBox.Yes, QMessageBox.No) if reply == QMessageBox.Yes: event.accept() self.saveOnQuit() self.saveSettings() print("Goodbye ...") def readSettings(self): print("reading settings") if self.settings.contains("geometry"): self.setGeometry(self.settings.value('geometry')) if self.settings.contains("horHeader"): if self.settings.value('horHeader') == "true": self.tableView.horizontalHeader().setVisible(True) else: self.tableView.horizontalHeader().setVisible(False) if self.settings.contains("vertHeader"): if self.settings.value('vertHeader') == "true": self.tableView.verticalHeader().setVisible(True) else: self.tableView.verticalHeader().setVisible(False) def saveSettings(self): print("saving settings") self.settings.setValue('geometry', self.geometry()) self.settings.setValue('horHeader', self.tableView.horizontalHeader().isVisible()) self.settings.setValue('vertHeader', self.tableView.verticalHeader().isVisible()) def saveOnQuit(self): if self.fileName == "": self.writeCsv() else: path = self.fileName with open(path, 'w') as stream: print("saving", path) writer = csv.writer(stream, delimiter=self.delimit) for row in range(self.tableView.rowCount()): rowdata = [] for column in range(self.tableView.columnCount()): item = self.tableView.item(row, column) if item is not None: rowdata.append(item.text()) else: rowdata.append('') writer.writerow(rowdata) self.isChanged = False def setCurrentFile(self, fileName): self.fileName = fileName self.fname = os.path.splitext(str(fileName))[0].split("/")[-1] if self.fileName: self.setWindowTitle(self.strippedName(self.fileName) + "[*]") else: self.setWindowTitle("no File") files = self.settings.value('recentFileList', []) try: files.remove(fileName) except ValueError: pass files.insert(0, fileName) del files[self.MaxRecentFiles:] self.settings.setValue('recentFileList', files) for widget in QApplication.topLevelWidgets(): if isinstance(widget, MyWindow_2): widget.updateRecentFileActions() def updateRecentFileActions(self): mytext = "" files = self.settings.value('recentFileList', []) numRecentFiles = min(len(files), self.MaxRecentFiles) for i in range(numRecentFiles): text = "&%d %s" % (i + 1, self.strippedName(files[i])) self.recentFileActs[i].setText(text) self.recentFileActs[i].setData(files[i]) self.recentFileActs[i].setVisible(True) self.recentFileActs[i].setIcon( QIcon.fromTheme("gnome-mime-text-x")) for j in range(numRecentFiles, self.MaxRecentFiles): self.recentFileActs[j].setVisible(False) self.separatorAct.setVisible((numRecentFiles > 0)) def clearRecentFiles(self, fileName): # self.settings.clear() mf = [] self.settings.setValue('recentFileList', mf) self.updateRecentFileActions() def strippedName(self, fullFileName): return QFileInfo(fullFileName).fileName() def msg(self, message): self.statusBar().showMessage(message) def setHeaders(self): self.tableView.selectRow(0) self.copyRow() for column in range(self.tableView.columnCount()): newItem = QTableWidgetItem(self.copiedRow[column]) self.tableView.setHorizontalHeaderItem(column, newItem) self.tableView.removeRow(0) self.tableView.resizeColumnsToContents() def setHeadersToFirstRow(self): self.tableView.insertRow(0) for column in range(self.tableView.columnCount()): newItem = QTableWidgetItem( self.tableView.horizontalHeaderItem(column)) ind = QTableWidgetItem(str(column + 1)) self.tableView.setHorizontalHeaderItem(column, ind) self.tableView.setItem(0, column, newItem) def copyRow(self): row = self.selectedRow() for column in range(self.tableView.columnCount()): if not self.tableView.item(row, column) == None: self.copiedRow.append(self.tableView.item(row, column).text()) # print(self.copiedRow) def pasteRow(self): row = self.selectedRow() for column in range(self.tableView.columnCount()): newItem = QTableWidgetItem(self.copiedRow[column]) self.tableView.setItem(row, column, newItem) def copyColumn(self): column = self.selectedColumn() for row in range(self.tableView.rowCount()): self.copiedColumn.append(self.tableView.item(row, column).text()) # print(self.copiedColumn) def pasteColumn(self): column = self.selectedColumn() for row in range(self.tableView.rowCount()): newItem = QTableWidgetItem(self.copiedColumn[row]) self.tableView.setItem(row, column, newItem) self.tableView.resizeColumnsToContents()
class LineEditTableCellDelegate(QItemDelegate): """ Used for enabling read-only and text selectable cells in QTableView widgets. """ def __init__(self, parent, img_dir: str): QItemDelegate.__init__( self, parent, ) self.img_dir = img_dir self.save_action = QAction('Save', self) self.set_icon(self.save_action, "*****@*****.**") self.save_action.triggered.connect(self.on_save_data) self.undo_action = QAction('Revert', self) self.set_icon(self.undo_action, "*****@*****.**") self.undo_action.triggered.connect(self.on_revert_data) self.editor = None self.old_data = '' self.cur_item_index = None self.data_history: Dict[QModelIndex, List[str]] = {} def set_icon(self, widget, ico_name): icon = QIcon() icon.addPixmap(QPixmap(os.path.join(self.img_dir, ico_name))) widget.setIcon(icon) def on_save_data(self): if self.editor: self.commitData.emit(self.editor) self.closeEditor.emit(self.editor) self.editor = None def on_revert_data(self): if self.editor and self.cur_item_index: sd = self.data_history.get(self.cur_item_index) if sd: sd.pop() if sd: t = sd[-1] else: t = '' self.editor.setText(t) def createEditor(self, parent, option, index): self.cur_item_index = index self.editor = QLineEdit(parent) self.editor.addAction(self.save_action, QLineEdit.TrailingPosition) if self.data_history.get(index): self.editor.addAction(self.undo_action, QLineEdit.TrailingPosition) return self.editor def setEditorData(self, editor, index): self.old_data = index.data() editor.setText(self.old_data) sd = self.data_history.get(index) if not sd: sd = [] self.data_history[index] = sd if self.old_data: if not sd or sd[-1] != self.old_data: sd.append(self.old_data) def setModelData(self, editor, model, index): new_data = editor.text() if new_data != self.old_data: model.setData(index, new_data)
class Login(QDialog): def __init__(self): super(Login, self).__init__() self.setWindowIcon(QIcon('qt.ico')) self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowMinimizeButtonHint) self.setWindowTitle(u"Mod") self.setFixedSize(300, 400) self.setObjectName('principal') self.createGUI() def createGUI(self): self.frame_window = QWidget(self) self.frame_window.setGeometry(0, 0, 300, 40) self.frame_window.setObjectName('frame_window') self.title_frame = QLabel(self.frame_window) self.title_frame.setGeometry(0, 0, 300, 40) self.title_frame.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) self.title_frame.setFont(QFont("Tahoma", 20, QFont.Bold)) self.title_frame.setText(u"Mod Login") self.title_frame.setObjectName('title_frame') self.container = QWidget(self) self.container.setGeometry(0, 0, 300, 400) self.container.setObjectName('container') # buttons clsfont = self.font() or QFont() clsfont.setFamily('Webdings') self.button_close = QPushButton('r', self.container, font=clsfont) self.button_close.setGeometry(260, 0, 40, 40) self.button_close.setObjectName('button_close') self.button_login = QPushButton(self.container) self.button_login.setGeometry(20, 300, 260, 40) self.button_login.setText(u'Login') self.button_login.setObjectName('button_login') self.button_login.setCursor(QCursor(Qt.PointingHandCursor)) self.line_username = QLineEdit(self.container) self.line_username.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) self.line_username.setFont(QFont("Tahoma", 20, QFont.Bold)) self.line_username.setGeometry(20, 180, 260, 40) self.line_username.setPlaceholderText(u'Username') self.line_username.setObjectName('line_username') self.ac_username = QAction() self.ac_username.setIcon(QIcon('username.png')) self.line_username.addAction(self.ac_username, QLineEdit.LeadingPosition) self.line_password = QLineEdit(self.container) self.line_password.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) self.line_password.setFont(QFont("Tahoma", 20, QFont.Bold)) self.line_password.setGeometry(20, 230, 260, 40) self.line_password.setEchoMode(QLineEdit.Password) self.line_password.setPlaceholderText(u'Password') self.line_password.setObjectName('line_password') self.ac1_password = QAction() self.ac1_password.setIcon(QIcon('password.png')) self.ac2_password = QAction() self.ac2_password.setToolTip('Show Password') self.ac2_password.setIcon(QIcon('show_pw.png')) self.line_password.addAction(self.ac1_password, QLineEdit.LeadingPosition) self.line_password.addAction(self.ac2_password, QLineEdit.TrailingPosition) # conexiones self.button_close.clicked.connect(self.close) self.ac2_password.triggered.connect(self.show_pass) self.button_login.clicked.connect(self.handleLogin) # 初始化焦点位于哪个控件上 self.button_login.setFocus() #获取焦点 def handleLogin(self): # self.accept() # 关键 if (self.line_username.text() == 'admin' and self.line_password.text() == '123456'): self.appmain = MainWindow() # self.accept() # 关键 self.hide() self.appmain.show() else: QMessageBox.warning(self, u'Prompt', u'User or Password Error', QMessageBox.Ok) def mousePressEvent(self, event): self.offset = event.pos() def mouseMoveEvent(self, event): x = event.globalX() y = event.globalY() x_w = self.offset.x() y_w = self.offset.y() self.move(x - x_w, y - y_w) def keyPressEvent(self, event): if (event.key() == Qt.Key_Return): self.handleLogin() def show_pass(self): if self.line_password.echoMode() == QLineEdit.Password: self.line_password.setEchoMode(QLineEdit.Normal) else: self.line_password.setEchoMode(QLineEdit.Password)
class RenameDialog(QDialog): def __init__(self, parent: QWidget) -> None: super().__init__(parent) self._basename: str = "" self._build_gui() def _build_gui(self) -> None: self.resize(600, 100) self.setWindowTitle("RenameDialog") self.setWindowModality(Qt.WindowModal) # Widgets icon_label = QLabel() icon_label.setPixmap(QIcon.fromTheme("accessories-text-editor").pixmap(48)) icon_label.setAlignment(Qt.AlignTop) self.label = QLabel("Rename ...") self.label.setTextInteractionFlags(Qt.TextSelectableByMouse) self.name_edit = QLineEdit(self) self.name_reload = self.name_edit.addAction(QIcon.fromTheme("reload"), QLineEdit.TrailingPosition) self.name_reload.setShortcut("F5") self.name_reload.setToolTip("Reset the filename to it's original name") self.button_box = QDialogButtonBox(self) self.btn_rename = QPushButton(QIcon.fromTheme("document-save-as"), "Rename") self.button_box.addButton(self.btn_rename, QDialogButtonBox.AcceptRole) self.btn_cancel = self.button_box.addButton(QDialogButtonBox.Cancel) self.btn_rename.setDefault(True) # layout self.vbox = QVBoxLayout() self.vbox.addWidget(self.label) self.vbox.addWidget(self.name_edit) self.vbox.addStretch() self.vbox.addWidget(self.button_box) hbox = QHBoxLayout() hbox.addWidget(icon_label) hbox.addLayout(self.vbox) self.setLayout(hbox) # signals self.name_edit.returnPressed.connect(self.accept) self.btn_rename.clicked.connect(self._on_rename_clicked) self.btn_cancel.clicked.connect(self._on_cancel_clicked) self.name_reload.triggered.connect(self._on_name_reload) def _on_rename_clicked(self) -> None: self.accept() def _on_cancel_clicked(self) -> None: self.reject() def _on_name_reload(self) -> None: self.name_edit.setText(self._basename) root, ext = os.path.splitext(self._basename) self.name_edit.setSelection(0, len(root)) def get_old_basename(self) -> str: return self._basename def get_new_basename(self) -> str: return cast(str, self.name_edit.text()) def set_basename(self, basename: str) -> None: self._basename = basename self.setWindowTitle("Rename \"{}\"".format(basename)) self.label.setText("Rename \"{}\" to:".format(basename)) self.name_edit.setText(basename) root, ext = os.path.splitext(basename) self.name_edit.setSelection(0, len(root))
class ProjectExecution(QWidget): """Project Execution widget class""" def __init__(self, parent): super(ProjectExecution, self).__init__() self._parent = parent grid = QGridLayout(self) grid.addWidget(QLabel(translations.TR_PROJECT_MAIN_FILE), 0, 0) # Main file self.path = QLineEdit() choose_main_file_action = QAction(self) choose_main_file_action.setIcon( self.style().standardIcon(self.style().SP_FileIcon)) choose_main_file_action.setToolTip( translations.TR_PROJECT_SELECT_MAIN_FILE) self.path.addAction( choose_main_file_action, QLineEdit.TrailingPosition) clear_main_file_action = self.path.addAction( self.style().standardIcon(self.style().SP_LineEditClearButton), QLineEdit.TrailingPosition) clear_main_file_action.triggered.connect(self.path.clear) self.path.setPlaceholderText( os.path.join(os.path.expanduser("~"), 'path', 'to', 'main.py')) self.path.setText(self._parent.project.main_file) grid.addWidget(self.path, 0, 1) # this should be changed, and ALL pythonPath names to # python_custom_interpreter or something like that. this is NOT the # PYTHONPATH self.line_interpreter = QLineEdit() choose_interpreter = self.line_interpreter.addAction( self.style().standardIcon(self.style().SP_DirIcon), QLineEdit.TrailingPosition) self.line_interpreter.setText(self._parent.project.python_exec) completer = QCompleter(utils.get_python()) completer.setCaseSensitivity(Qt.CaseInsensitive) completer.setFilterMode(Qt.MatchContains) self.line_interpreter.setCompleter(completer) self.line_interpreter.setPlaceholderText("python") grid.addWidget(QLabel( translations.TR_PROJECT_PYTHON_INTERPRETER), 1, 0) grid.addWidget(self.line_interpreter, 1, 1) # PYTHONPATH grid.addWidget(QLabel(translations.TR_PROJECT_PYTHON_PATH), 2, 0) self.txt_python_path = QPlainTextEdit() # TODO : better widget self.txt_python_path.setPlainText(self._parent.project.python_path) self.txt_python_path.setToolTip(translations.TR_PROJECT_PATH_PER_LINE) grid.addWidget(self.txt_python_path, 2, 1) # Additional builtins/globals for pyflakes grid.addWidget(QLabel(translations.TR_PROJECT_BUILTINS), 3, 0) self.additional_builtins = QLineEdit() self.additional_builtins.setText( ' '.join(self._parent.project.additional_builtins)) self.additional_builtins.setToolTip( translations.TR_PROJECT_BUILTINS_TOOLTIP) grid.addWidget(self.additional_builtins, 3, 1) # Pre script self._line_pre_exec = QLineEdit() choose_pre_exec = QAction(self) choose_pre_exec.setToolTip( "Choose Script to execute before run project") choose_pre_exec.setIcon( self.style().standardIcon(self.style().SP_FileIcon)) self._line_pre_exec.addAction( choose_pre_exec, QLineEdit.TrailingPosition) clear_pre_action = self._line_pre_exec.addAction( self.style().standardIcon(self.style().SP_LineEditClearButton), QLineEdit.TrailingPosition) clear_pre_action.triggered.connect(self._line_pre_exec.clear) self._line_pre_exec.setReadOnly(True) self._line_pre_exec.setText(self._parent.project.pre_exec_script) self._line_pre_exec.setPlaceholderText( os.path.join(os.path.expanduser("~"), 'path', 'to', 'script.sh')) grid.addWidget(QLabel(translations.TR_PROJECT_PRE_EXEC), 4, 0) grid.addWidget(self._line_pre_exec, 4, 1) # Post script self._line_post_exec = QLineEdit() choose_post_exec = QAction(self) choose_post_exec.setToolTip( "Choose script to execute after run project") choose_post_exec.setIcon( self.style().standardIcon(self.style().SP_FileIcon)) self._line_post_exec.addAction( choose_post_exec, QLineEdit.TrailingPosition) clear_post_action = self._line_post_exec.addAction( self.style().standardIcon(self.style().SP_LineEditClearButton), QLineEdit.TrailingPosition) clear_post_action.triggered.connect(self._line_post_exec.clear) self._line_post_exec.setReadOnly(True) self._line_post_exec.setText(self._parent.project.post_exec_script) self._line_post_exec.setPlaceholderText( os.path.join(os.path.expanduser("~"), 'path', 'to', 'script.sh')) grid.addWidget(QLabel(translations.TR_PROJECT_POST_EXEC), 5, 0) grid.addWidget(self._line_post_exec, 5, 1) # grid.addItem(QSpacerItem(5, 10, QSizePolicy.Expanding, # QSizePolicy.Expanding), 6, 0) # Properties grid.addWidget(QLabel(translations.TR_PROJECT_PROPERTIES), 7, 0) self._line_params = QLineEdit() self._line_params.setToolTip(translations.TR_PROJECT_PARAMS_TOOLTIP) self._line_params.setText(self._parent.project.program_params) self._line_params.setPlaceholderText('verbose, debug, force') grid.addWidget(QLabel(translations.TR_PROJECT_PARAMS), 8, 0) grid.addWidget(self._line_params, 8, 1) # Widgets for virtualenv properties self.txtVenvPath = QLineEdit() # ui_tools.LineEditButton( # self.txtVenvPath, self.txtVenvPath.clear, # self.style().standardPixmap(self.style().SP_TrashIcon)) self.txtVenvPath.setText(self._parent.project.venv) self._dir_completer = QCompleter() self._dir_completer.setModel(QDirModel(self._dir_completer)) self.txtVenvPath.setCompleter(self._dir_completer) self.txtVenvPath.setPlaceholderText( os.path.join(os.path.expanduser("~"), 'path', 'to', 'virtualenv')) # self.btnVenvPath = QPushButton(QIcon(":img/open"), '') grid.addWidget(QLabel(translations.TR_PROJECT_VIRTUALENV), 9, 0) grid.addWidget(self.txtVenvPath, 9, 1) # grid.addWidget(self.btnVenvPath, 9, 2) choose_main_file_action.triggered.connect(self.select_file) choose_interpreter.triggered.connect(self._load_python_path) choose_pre_exec.triggered.connect(self.select_pre_exec_script) choose_post_exec.triggered.connect(self.select_post_exec_script) # self.connect(self.btnBrowse, SIGNAL("clicked()"), self.select_file) # self.connect(self.btnPythonPath, SIGNAL("clicked()"), # self._load_python_path) # self.connect(self.btnVenvPath, SIGNAL("clicked()"), # self._load_python_venv) # self.connect(self.btnPreExec, SIGNAL("clicked()"), # self.select_pre_exec_script) # self.connect(self.btnPostExec, SIGNAL("clicked()"), # self.select_post_exec_script) @property def main_file(self): return self.path.text() @property def interpreter(self): return self.line_interpreter.text() @property def pre_script(self): return self._line_pre_exec.text() @property def post_script(self): return self._line_post_exec.text() @property def params(self): return self._line_params.text() def _load_python_path(self): """Ask the user a python path and set its value""" path_interpreter = QFileDialog.getOpenFileName( self, translations.TR_PROJECT_SELECT_PYTHON_PATH)[0] if path_interpreter: self.line_interpreter.setText(path_interpreter) def _load_python_venv(self): """Ask the user a python venv and set its value""" venv = QFileDialog.getExistingDirectory( self, translations.TR_PROJECT_SELECT_VIRTUALENV) if sys.platform == 'win32': venv = os.path.join(venv, 'Scripts', 'python.exe') else: venv = os.path.join(venv, 'bin', 'python') # check if venv folder exists if not os.path.exists(venv): QMessageBox.information( self, translations.TR_PROJECT_SELECT_VIRTUALENV_MESSAGE_TITLE, translations.TR_PROJECT_SELECT_VIRTUALENV_MESSAGE_BODY) self.txtVenvPath.setText("") else: self.txtVenvPath.setText(venv) def select_file(self): """Ask the user a python main file and set its value""" filename, _ = QFileDialog.getOpenFileName( self, translations.TR_PROJECT_SELECT_MAIN_FILE, self._parent.project.path, 'Python Files (*.py);;Python Bytecode (*.py[codw]);;All Files(*)') if filename: filename = file_manager.convert_to_relative( self._parent.project.path, filename) self.path.setText(filename) def select_pre_exec_script(self): """Ask the user a python pre-exec script and set its value""" filename = QFileDialog.getOpenFileName( self, translations.TR_PROJECT_SELECT_PRE_SCRIPT, self._parent.project.path, '*(*.*);;Bash(*.sh);;Python PY(*.py);;Python Bytecode(*.py[codw]);;' 'Bat(*.bat);;Cmd(*.cmd);;Exe(*.exe);;Bin(*.bin);;App(*.app)')[0] if filename: filename = file_manager.convert_to_relative( self._parent.project.path, filename) self._line_pre_exec.setText(filename) def select_post_exec_script(self): """Ask the user a python post-exec script and set its value""" filename = QFileDialog.getOpenFileName( self, translations.TR_PROJECT_SELECT_POST_SCRIPT, self._parent.project.path, '*(*.*);;Bash(*.sh);;Python PY(*.py);;Python Bytecode(*.py[codw]);;' 'Bat(*.bat);;Cmd(*.cmd);;Exe(*.exe);;Bin(*.bin);;App(*.app)')[0] if filename: filename = file_manager.convert_to_relative( self._parent.project.path, filename) self._line_post_exec.setText(filename)
class RDBPDBTool(QDialog): def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle(self.tr("WinRDBI DB File to PDB")) self.setModal(True) self.setMinimumWidth(600) self._process = QProcess(self) self._process.setProgram("python") self._process.finished.connect(self._on_finished) vbox = QVBoxLayout(self) hbox = QHBoxLayout() hbox.addWidget(QLabel(self.tr("Ubicación del .rdb:"))) self._line_location = QLineEdit() self._line_location.setReadOnly(True) choose_location = self._line_location.addAction( self.style().standardIcon( self.style().SP_DirIcon), QLineEdit.TrailingPosition) hbox.addWidget(self._line_location) vbox.addLayout(hbox) aviso = QLabel( self.tr( "<b><i>El archivo será guardado en el mismo directorio " "que el original.</i></b>")) f = aviso.font() f.setPointSize(10) aviso.setFont(f) vbox.addWidget(aviso) self._check_open = QCheckBox(self.tr("Abrir la BD al finalizar")) vbox.addWidget(self._check_open) hbox = QHBoxLayout() hbox.addStretch(1) start_btn = QPushButton(self.tr("Convertir!")) hbox.addWidget(start_btn) cancel_btn = QPushButton(self.tr("Salir")) hbox.addWidget(cancel_btn) vbox.addLayout(hbox) choose_location.triggered.connect(self._select_rdb_file) start_btn.clicked.connect(self._start_convertion) cancel_btn.clicked.connect(self.close) def _start_convertion(self): rdb_filename = self._line_location.text() tool = os.path.join(settings.ROOT_DIR, "rdb_to_pdb") args = [tool, rdb_filename] self._process.setArguments(args) self._process.start() def _on_finished(self, code, status): if status == QProcess.NormalExit == code: QMessageBox.information( self, self.tr("Completado!"), self.tr("Todo ha salido muy bien!")) if self._check_open.isChecked(): central = Pireal.get_service("central") rdb = os.path.splitext(self._line_location.text())[0] pdb = rdb + ".pdb" central.open_database(pdb) self.close() else: QMessageBox.critical( self, "Error", "El proceso no se ha completado") def _select_rdb_file(self): filename = QFileDialog.getOpenFileName( self, self.tr("Selecciona el arhico RDB"), "~", "RDB Files (*.rdb)")[0] if filename: self._line_location.setText(filename)
class myEditor(QMainWindow): def __init__(self, parent=None): super(myEditor, self).__init__(parent) self.MaxRecentFiles = 5 self.windowList = [] self.recentFileActs = [] self.setAttribute(Qt.WA_DeleteOnClose) # Editor Widget ... QIcon.setThemeName('Faenza-Dark') self.editor = QPlainTextEdit() self.editor.setStyleSheet(stylesheet2(self)) self.editor.setFrameStyle(QFrame.NoFrame) self.editor.setTabStopWidth(14) self.extra_selections = [] self.fname = "" self.filename = "" # Line Numbers ... self.numbers = NumberBar(self.editor) self.createActions() # Laying out... layoutH = QHBoxLayout() layoutH.setSpacing(1.5) layoutH.addWidget(self.numbers) layoutH.addWidget(self.editor) ### begin toolbar tb = QToolBar(self) tb.setWindowTitle("File Toolbar") self.newAct = QAction("&New", self, shortcut=QKeySequence.New, statusTip="Create a new file", triggered=self.newFile) self.newAct.setIcon(QIcon.fromTheme("document-new")) self.openAct = QAction("&Open", self, shortcut=QKeySequence.Open, statusTip="open file", triggered=self.openFile) self.openAct.setIcon(QIcon.fromTheme("document-open")) self.saveAct = QAction("&Save", self, shortcut=QKeySequence.Save, statusTip="save file", triggered=self.fileSave) self.saveAct.setIcon(QIcon.fromTheme("document-save")) self.saveAsAct = QAction("&Save as ...", self, shortcut=QKeySequence.SaveAs, statusTip="save file as ...", triggered=self.fileSaveAs) self.saveAsAct.setIcon(QIcon.fromTheme("document-save-as")) self.exitAct = QAction("Exit", self, shortcut=QKeySequence.Quit, toolTip="Exit", triggered=self.handleQuit) self.exitAct.setIcon(QIcon.fromTheme("application-exit")) ### find / replace toolbar self.tbf = QToolBar(self) self.tbf.setWindowTitle("Find Toolbar") self.findfield = QLineEdit() self.findfield.addAction(QIcon.fromTheme("edit-find"), QLineEdit.LeadingPosition) self.findfield.setClearButtonEnabled(True) self.findfield.setFixedWidth(150) self.findfield.setPlaceholderText("find") self.findfield.setToolTip("press RETURN to find") self.findfield.setText("") ft = self.findfield.text() self.findfield.returnPressed.connect(self.findText) self.tbf.addWidget(self.findfield) self.replacefield = QLineEdit() self.replacefield.addAction(QIcon.fromTheme("edit-find-and-replace"), QLineEdit.LeadingPosition) self.replacefield.setClearButtonEnabled(True) self.replacefield.setFixedWidth(150) self.replacefield.setPlaceholderText("replace with") self.replacefield.setToolTip("press RETURN to replace the first") self.replacefield.returnPressed.connect(self.replaceOne) self.tbf.addSeparator() self.tbf.addWidget(self.replacefield) self.tbf.addSeparator() self.tbf.addAction("replace all", self.replaceAll) self.tbf.addSeparator() layoutV = QVBoxLayout() bar = self.menuBar() self.filemenu = bar.addMenu("File") self.separatorAct = self.filemenu.addSeparator() self.filemenu.addAction(self.newAct) self.filemenu.addAction(self.openAct) self.filemenu.addAction(self.saveAct) self.filemenu.addAction(self.saveAsAct) self.filemenu.addSeparator() for i in range(self.MaxRecentFiles): self.filemenu.addAction(self.recentFileActs[i]) self.updateRecentFileActions() self.filemenu.addSeparator() self.filemenu.addAction(self.exitAct) bar.setStyleSheet(stylesheet2(self)) editmenu = bar.addMenu("Edit") editmenu.addAction( QAction(QIcon.fromTheme('edit-copy'), "Copy", self, triggered=self.editor.copy, shortcut=QKeySequence.Copy)) editmenu.addAction( QAction(QIcon.fromTheme('edit-cut'), "Cut", self, triggered=self.editor.cut, shortcut=QKeySequence.Cut)) editmenu.addAction( QAction(QIcon.fromTheme('edit-paste'), "Paste", self, triggered=self.editor.paste, shortcut=QKeySequence.Paste)) editmenu.addAction( QAction(QIcon.fromTheme('edit-delete'), "Delete", self, triggered=self.editor.cut, shortcut=QKeySequence.Delete)) editmenu.addSeparator() editmenu.addAction( QAction(QIcon.fromTheme('edit-select-all'), "Select All", self, triggered=self.editor.selectAll, shortcut=QKeySequence.SelectAll)) layoutV.addWidget(bar) layoutV.addWidget(self.tbf) layoutV.addLayout(layoutH) ### main window mq = QWidget(self) mq.setLayout(layoutV) self.setCentralWidget(mq) # Event Filter ... self.installEventFilter(self) self.editor.setFocus() self.cursor = QTextCursor() self.editor.setPlainText("hello") self.editor.moveCursor(self.cursor.End) self.editor.document().modificationChanged.connect( self.setWindowModified) # Brackets ExtraSelection ... self.left_selected_bracket = QTextEdit.ExtraSelection() self.right_selected_bracket = QTextEdit.ExtraSelection() def createActions(self): for i in range(self.MaxRecentFiles): self.recentFileActs.append( QAction(self, visible=False, triggered=self.openRecentFile)) def openRecentFile(self): action = self.sender() if action: if (self.maybeSave()): self.openFileOnStart(action.data()) ### New File def newFile(self): if self.maybeSave(): self.editor.clear() self.editor.setPlainText("") self.filename = "" self.setModified(False) self.editor.moveCursor(self.cursor.End) ### open File def openFileOnStart(self, path=None): if path: inFile = QFile(path) if inFile.open(QFile.ReadWrite | QFile.Text): text = inFile.readAll() try: # Python v3. text = str(text, encoding='utf8') except TypeError: # Python v2. text = str(text) self.editor.setPlainText(text) self.filename = path self.setModified(False) self.fname = QFileInfo(path).fileName() self.setWindowTitle(self.fname + "[*]") self.document = self.editor.document() self.setCurrentFile(self.filename) ### open File def openFile(self, path=None): if self.maybeSave(): if not path: path, _ = QFileDialog.getOpenFileName( self, "Open File", QDir.homePath() + "/Documents/", "Text Files (*.txt *.csv *.py);;All Files (*.*)") if path: inFile = QFile(path) if inFile.open(QFile.ReadWrite | QFile.Text): text = inFile.readAll() try: # Python v3. text = str(text, encoding='utf8') except TypeError: # Python v2. text = str(text) self.editor.setPlainText(text) self.filename = path self.setModified(False) self.fname = QFileInfo(path).fileName() self.setWindowTitle(self.fname + "[*]") self.document = self.editor.document() self.setCurrentFile(self.filename) def fileSave(self): if (self.filename != ""): file = QFile(self.filename) print(self.filename) if not file.open(QFile.WriteOnly | QFile.Text): QMessageBox.warning( self, "Error", "Cannot write file %s:\n%s." % (self.filename, file.errorString())) return outstr = QTextStream(file) QApplication.setOverrideCursor(Qt.WaitCursor) outstr << self.editor.toPlainText() QApplication.restoreOverrideCursor() self.setModified(False) self.fname = QFileInfo(self.filename).fileName() self.setWindowTitle(self.fname + "[*]") self.setCurrentFile(self.filename) else: self.fileSaveAs() ### save File def fileSaveAs(self): fn, _ = QFileDialog.getSaveFileName(self, "Save as...", self.filename, "Python files (*.py)") if not fn: print("Error saving") return False lfn = fn.lower() if not lfn.endswith('.py'): fn += '.py' self.filename = fn self.fname = os.path.splitext(str(fn))[0].split("/")[-1] return self.fileSave() def closeEvent(self, e): if self.maybeSave(): e.accept() else: e.ignore() ### ask to save def maybeSave(self): if not self.isModified(): return True if self.filename.startswith(':/'): return True ret = QMessageBox.question(self, "Message", "<h4><p>The document was modified.</p>\n" \ "<p>Do you want to save changes?</p></h4>", QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) if ret == QMessageBox.Yes: if self.filename == "": self.fileSaveAs() return False else: self.fileSave() return True if ret == QMessageBox.Cancel: return False return True def findText(self): ft = self.findfield.text() if self.editor.find(ft): return else: self.editor.moveCursor(1) if self.editor.find(ft): self.editor.moveCursor(QTextCursor.Start, QTextCursor.MoveAnchor) def handleQuit(self): print("Goodbye ...") app.quit() def set_numbers_visible(self, value=True): self.numbers.setVisible(False) def match_left(self, block, character, start, found): map = {'{': '}', '(': ')', '[': ']'} while block.isValid(): data = block.userData() if data is not None: braces = data.braces N = len(braces) for k in range(start, N): if braces[k].character == character: found += 1 if braces[k].character == map[character]: if not found: return braces[k].position + block.position() else: found -= 1 block = block.next() start = 0 def match_right(self, block, character, start, found): map = {'}': '{', ')': '(', ']': '['} while block.isValid(): data = block.userData() if data is not None: braces = data.braces if start is None: start = len(braces) for k in range(start - 1, -1, -1): if braces[k].character == character: found += 1 if braces[k].character == map[character]: if found == 0: return braces[k].position + block.position() else: found -= 1 block = block.previous() start = None # ''' cursor = self.editor.textCursor() block = cursor.block() data = block.userData() previous, next = None, None if data is not None: position = cursor.position() block_position = cursor.block().position() braces = data.braces N = len(braces) for k in range(0, N): if braces[k].position == position - block_position or braces[ k].position == position - block_position - 1: previous = braces[k].position + block_position if braces[k].character in ['{', '(', '[']: next = self.match_left(block, braces[k].character, k + 1, 0) elif braces[k].character in ['}', ')', ']']: next = self.match_right(block, braces[k].character, k, 0) if next is None: next = -1 if next is not None and next > 0: if next == 0 and next >= 0: format = QTextCharFormat() cursor.setPosition(previous) cursor.movePosition(QTextCursor.NextCharacter, QTextCursor.KeepAnchor) format.setBackground(QColor('white')) self.left_selected_bracket.format = format self.left_selected_bracket.cursor = cursor cursor.setPosition(next) cursor.movePosition(QTextCursor.NextCharacter, QTextCursor.KeepAnchor) format.setBackground(QColor('white')) self.right_selected_bracket.format = format self.right_selected_bracket.cursor = cursor # ''' def paintEvent(self, event): highlighted_line = QTextEdit.ExtraSelection() highlighted_line.format.setBackground(lineHighlightColor) highlighted_line.format.setProperty(QTextFormat.FullWidthSelection, QVariant(True)) highlighted_line.cursor = self.editor.textCursor() highlighted_line.cursor.clearSelection() self.editor.setExtraSelections([ highlighted_line, self.left_selected_bracket, self.right_selected_bracket ]) def document(self): return self.editor.document def isModified(self): return self.editor.document().isModified() def setModified(self, modified): self.editor.document().setModified(modified) def setLineWrapMode(self, mode): self.editor.setLineWrapMode(mode) def clear(self): self.editor.clear() def setPlainText(self, *args, **kwargs): self.editor.setPlainText(*args, **kwargs) def setDocumentTitle(self, *args, **kwargs): self.editor.setDocumentTitle(*args, **kwargs) def set_number_bar_visible(self, value): self.numbers.setVisible(value) def replaceAll(self): print("replacing all") oldtext = self.editor.document().toPlainText() newtext = oldtext.replace(self.findfield.text(), self.replacefield.text()) self.editor.setPlainText(newtext) self.setModified(True) def replaceOne(self): print("replacing all") oldtext = self.editor.document().toPlainText() newtext = oldtext.replace(self.findfield.text(), self.replacefield.text(), 1) self.editor.setPlainText(newtext) self.setModified(True) def setCurrentFile(self, fileName): self.curFile = fileName if self.curFile: self.setWindowTitle("%s - Recent Files" % self.strippedName(self.curFile)) else: self.setWindowTitle("Recent Files") settings = QSettings('Axel Schneider', 'PTEdit') files = settings.value('recentFileList') try: files.remove(fileName) except ValueError: pass files.insert(0, fileName) del files[self.MaxRecentFiles:] settings.setValue('recentFileList', files) for widget in QApplication.topLevelWidgets(): if isinstance(widget, myEditor): widget.updateRecentFileActions() def updateRecentFileActions(self): mytext = "" settings = QSettings('Axel Schneider', 'PTEdit') files = settings.value('recentFileList') files = files if files else [] numRecentFiles = min(len(files), self.MaxRecentFiles) for i in range(numRecentFiles): text = "&%d %s" % (i + 1, self.strippedName(files[i])) self.recentFileActs[i].setText(text) self.recentFileActs[i].setData(files[i]) self.recentFileActs[i].setVisible(True) for j in range(numRecentFiles, self.MaxRecentFiles): self.recentFileActs[j].setVisible(False) self.separatorAct.setVisible((numRecentFiles > 0)) def clearRecentFileList(self, fileName): self.rmenu.clear() def strippedName(self, fullFileName): return QFileInfo(fullFileName).fileName()
class MasternodeWizard(QDialog, MessageBoxMixin, BaseWizard): accept_signal = pyqtSignal() def __init__(self, config, app, manager, parent): BaseWizard.__init__(self, config, None, None) QDialog.__init__(self, None) self.app = app self.gui = parent self.manager = manager self.setMinimumSize(600, 400) self.accept_signal.connect(self.accept) self.setWindowTitle('Electrum-AUDAX - ' + _('Masternode Wizard')) self.mn = MasternodeAnnounce() self.alias_e = None self.address_e = None self.privkey_e = None self.valid_utxo_list = None self.title = QLabel() self.main_widget = QWidget() self.back_button = QPushButton(_("Back"), self) self.back_button.setText( _('Back') if self.can_go_back() else _('Cancel')) self.next_button = QPushButton(_("Next"), self) self.next_button.setDefault(True) self.logo = QLabel() self.icon_filename = None self.loop = QEventLoop() self.rejected.connect(lambda: self.loop.exit(0)) self.back_button.clicked.connect(lambda: self.loop.exit(1)) self.next_button.clicked.connect(lambda: self.loop.exit(2)) outer_vbox = QVBoxLayout(self) inner_vbox = QVBoxLayout() inner_vbox.addWidget(self.title) inner_vbox.addWidget(self.main_widget) inner_vbox.addStretch(1) # inner_vbox.addWidget(self.please_wait) inner_vbox.addStretch(1) scroll_widget = QWidget() scroll_widget.setLayout(inner_vbox) scroll = QScrollArea() scroll.setWidget(scroll_widget) scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) scroll.setWidgetResizable(True) icon_vbox = QVBoxLayout() icon_vbox.addWidget(self.logo) icon_vbox.addStretch(1) hbox = QHBoxLayout() hbox.addLayout(icon_vbox) hbox.addSpacing(5) hbox.addWidget(scroll) hbox.setStretchFactor(scroll, 1) outer_vbox.addLayout(hbox) outer_vbox.addLayout(Buttons(self.back_button, self.next_button)) self.set_icon('electrum.png') self.show() self.raise_() self.refresh_gui() # Need for QT on MacOSX. Lame. def set_icon(self, filename): prior_filename, self.icon_filename = self.icon_filename, filename self.logo.setPixmap( QPixmap(icon_path(filename)).scaledToWidth( 60, mode=Qt.SmoothTransformation)) return prior_filename def set_layout(self, layout, title=None, next_enabled=True): self.title.setText("<b>%s</b>" % title if title else "") self.title.setVisible(bool(title)) # Get rid of any prior layout by assigning it to a temporary widget prior_layout = self.main_widget.layout() if prior_layout: QWidget().setLayout(prior_layout) self.main_widget.setLayout(layout) self.back_button.setEnabled(True) self.next_button.setEnabled(next_enabled) if next_enabled: self.next_button.setFocus() self.main_widget.setVisible(True) def exec_layout(self, layout, title=None, raise_on_cancel=True, next_enabled=True): self.set_layout(layout, title, next_enabled) result = self.loop.exec_() if not result and raise_on_cancel: raise UserCancelled if result == 1: raise GoBack from None self.title.setVisible(False) self.back_button.setEnabled(False) self.next_button.setEnabled(False) self.main_widget.setVisible(False) self.please_wait.setVisible(True) self.refresh_gui() return result def refresh_gui(self): # For some reason, to refresh the GUI this needs to be called twice self.app.processEvents() self.app.processEvents() def run(self): vbox = QVBoxLayout() self.alias_e = QLineEdit() self.alias_e.setPlaceholderText(_('Choose a name for this masternode')) self.address_e = QLineEdit() self.address_e.setPlaceholderText( _('Address of your masternode (format: ip:port)')) self.privkey_e = QLineEdit() self.privkey_e.setPlaceholderText( _('Enter your masternode private key or generate one')) self.privkey_e_action = self.privkey_e.addAction( read_QIcon('key.png'), QLineEdit.TrailingPosition) self.privkey_e_action.triggered.connect(self.create_private_key) form = QFormLayout() form.setContentsMargins(0, 0, 0, 0) form.addRow(_('Alias:'), self.alias_e) form.addRow(_('IP Address:'), self.address_e) form.addRow(_('Masternode Private Key:'), self.privkey_e) vbox.addLayout(form) self.set_layout(vbox, title=_('Electrum-AUDAX - ' + _('Masternode Configuration'))) while True: result = self.loop.exec_() if result != 2: # 2 = next return if not self.alias_e.text(): self.show_error(_("Choose a name for this masternode")) self.alias_e.setFocus() continue # TODO: Alias already exists if not self.address_e.text(): self.show_error(_("Address of your masternode")) self.address_e.setFocus() continue # Check if maternode address is valid try: addr = NetworkAddress(self.address_e.text()) except: self.show_error(_("Invalid network address")) self.address_e.setFocus() continue # check private key if not self.privkey_e.text(): self.show_error(_("Enter your masternode private key")) self.privkey_e.setFocus() continue try: deserialize_privkey('p2pkh:' + self.privkey_e.text()) except: self.show_error(_("Invalid private key")) self.privkey_e.setFocus() continue self.mn.alias = self.alias_e.text() self.mn.addr = addr self.mn.private_key = self.privkey_e.text() txin_type, privkey, compressed = deserialize_privkey( 'p2pkh:' + self.mn.private_key) self.mn.masternode_pubkey = ecc.ECPrivkey( privkey).get_public_key_hex(compressed=compressed) self.choose_utxo() break return True def choose_utxo(self): vbox = QVBoxLayout() form = QFormLayout() form.setContentsMargins(0, 0, 0, 0) title = QLabel( _('Choose a collateral payment for your masternode. A valid collateral payment is exactly 2500 AUDAX.' )) title.setWordWrap(True) form.addRow(title) self.valid_utxo_list = MasternodeOutputsWidget(self) form.addRow(self.valid_utxo_list) vbox.addLayout(form) self.valid_utxo_list.update() self.set_layout(vbox, title=_('Electrum-AUDAX - ' + _('Choose collateral'))) while True: result = self.loop.exec_() if result != 2: # 2 = next return idx = self.valid_utxo_list.currentIndex() item = self.valid_utxo_list.model().itemFromIndex( idx.sibling(idx.row(), self.valid_utxo_list.Columns.TXID)) if not item: continue txid = item.text().split(':') self.mn.vin = {'prevout_hash': txid[0], 'prevout_n': int(txid[1])} self.add_masternode() break return True def add_masternode(self): self.manager.add_masternode(self.mn) self.manager.wallet.network.trigger_callback('masternodes') def terminate(self): self.accept_signal.emit() def create_private_key(self): private_key = serialize_privkey(os.urandom(32), False, 'p2pkh', False) self.privkey_e.setText(private_key.split(':')[1])
class WebBrowser(QMainWindow): def __init__(self): super().__init__() # Create lists that will keep track of the new windows, # tabs and urls self.window_list = [] self.list_of_web_pages = [] self.list_of_urls = [] self.initializeUI() def initializeUI(self): self.setMinimumSize(300, 200) self.setWindowTitle("12.6 – Web Browser") self.setWindowIcon(QIcon(os.path.join('images', 'pyqt_logo.png'))) self.positionMainWindow() self.createMenu() self.createToolbar() self.createTabs() self.show() def createMenu(self): """ Set up the menu bar. """ new_window_act = QAction('New Window', self) new_window_act.setShortcut('Ctrl+N') new_window_act.triggered.connect(self.openNewWindow) new_tab_act = QAction('New Tab', self) new_tab_act.setShortcut('Ctrl+T') new_tab_act.triggered.connect(self.openNewTab) quit_act = QAction("Quit Browser", self) quit_act.setShortcut('Ctrl+Q') quit_act.triggered.connect(self.close) # Create the menu bar menu_bar = self.menuBar() menu_bar.setNativeMenuBar(False) # Create file menu and add actions file_menu = menu_bar.addMenu('File') file_menu.addAction(new_window_act) file_menu.addAction(new_tab_act) file_menu.addSeparator() file_menu.addAction(quit_act) self.status_bar = QStatusBar() self.setStatusBar(self.status_bar) def createToolbar(self): """ Set up the navigation toolbar. """ tool_bar = QToolBar("Address Bar") tool_bar.setIconSize(QSize(30, 30)) self.addToolBar(tool_bar) # Create toolbar actions back_page_button = QAction(QIcon(os.path.join('icons', 'back.png')), "Back", self) back_page_button.triggered.connect(self.backPageButton) forward_page_button = QAction(QIcon(os.path.join('icons', 'forward.png')), "Forward", self) forward_page_button.triggered.connect(self.forwardPageButton) refresh_button = QAction(QIcon(os.path.join('icons', 'refresh.png')), "Refresh", self) refresh_button.triggered.connect(self.refreshButton) home_button = QAction(QIcon(os.path.join('icons', 'home.png')), "Home", self) home_button.triggered.connect(self.homeButton) stop_button = QAction(QIcon(os.path.join('icons', 'stop.png')), "Stop", self) stop_button.triggered.connect(self.stopButton) # Set up the address bar self.address_line = QLineEdit() # addAction() is used here to merely display the icon in the line edit. self.address_line.addAction(QIcon('icons/search.png'), QLineEdit.LeadingPosition) self.address_line.setPlaceholderText("Enter website address") self.address_line.returnPressed.connect(self.searchForUrl) tool_bar.addAction(home_button) tool_bar.addAction(back_page_button) tool_bar.addAction(forward_page_button) tool_bar.addAction(refresh_button) tool_bar.addWidget(self.address_line) tool_bar.addAction(stop_button) def createTabs(self): """ Create the QTabWidget object and the different pages. Handle when a tab is closed. """ self.tab_bar = QTabWidget() self.tab_bar.setTabsClosable(True) # Add close buttons to tabs self.tab_bar.setTabBarAutoHide(True) # Hides tab bar when less than 2 tabs self.tab_bar.tabCloseRequested.connect(self.closeTab) # Create tab self.main_tab = QWidget() self.tab_bar.addTab(self.main_tab, "New Tab") # Call method that sets up each page self.setupTab(self.main_tab) self.setCentralWidget(self.tab_bar) def setupWebView(self): """ Create the QWebEngineView object that is used to view web docs. Set up the main page, and handle web_view signals. """ web_view = QWebEngineView() web_view.setUrl(QUrl("https://google.com")) # Create page loading progress bar that is displayed in # the status bar. self.page_load_pb = QProgressBar() self.page_load_label = QLabel() web_view.loadProgress.connect(self.updateProgressBar) # Display url in address bar web_view.urlChanged.connect(self.updateUrl) ok = web_view.loadFinished.connect(self.updateTabTitle) if ok: # Web page loaded return web_view else: print("The request timed out.") def setupTab(self, tab): """ Create individual tabs and widgets. Add the tab's url and web view to the appropriate list. Update the address bar if the user switches tabs. """ # Create the web view that will be displayed on the page. self.web_page = self.setupWebView() tab_v_box = QVBoxLayout() # Sets the left, top, right, and bottom margins to use around the layout. tab_v_box.setContentsMargins(0,0,0,0) tab_v_box.addWidget(self.web_page) # Append new web_page and url to the appropriate lists self.list_of_web_pages.append(self.web_page) self.list_of_urls.append(self.address_line) self.tab_bar.setCurrentWidget(self.web_page) # If user switches pages, update the url in the address to # reflect the current page. self.tab_bar.currentChanged.connect(self.updateUrl) tab.setLayout(tab_v_box) def openNewWindow(self): """ Create new instance of the WebBrowser class. """ new_window = WebBrowser() new_window.show() self.window_list.append(new_window) def openNewTab(self): """ Create new tabs. """ new_tab = QWidget() self.tab_bar.addTab(new_tab, "New Tab") self.setupTab(new_tab) # Update the tab_bar index to keep track of the new tab. # Load the url for the new page. tab_index = self.tab_bar.currentIndex() self.tab_bar.setCurrentIndex(tab_index + 1) self.list_of_web_pages[self.tab_bar.currentIndex()].load(QUrl("https://google.com")) def updateProgressBar(self, progress): """ Update progress bar in status bar. This provides feedback to the user that page is still loading. """ if progress < 100: self.page_load_pb.setVisible(progress) self.page_load_pb.setValue(progress) self.page_load_label.setVisible(progress) self.page_load_label.setText("Loading Page... ({}/100)".format(str(progress))) self.status_bar.addWidget(self.page_load_pb) self.status_bar.addWidget(self.page_load_label) else: self.status_bar.removeWidget(self.page_load_pb) self.status_bar.removeWidget(self.page_load_label) def updateTabTitle(self): """ Update the title of the tab to reflect the website. """ tab_index = self.tab_bar.currentIndex() title = self.list_of_web_pages[self.tab_bar.currentIndex()].page().title() self.tab_bar.setTabText(tab_index, title) def updateUrl(self): """ Update the url in the address to reflect the current page being displayed. """ url = self.list_of_web_pages[self.tab_bar.currentIndex()].page().url() formatted_url = QUrl(url).toString() self.list_of_urls[self.tab_bar.currentIndex()].setText(formatted_url) def searchForUrl(self): """ Make a request to load a url. """ url_text = self.list_of_urls[self.tab_bar.currentIndex()].text() # Append http to url url = QUrl(url_text) if url.scheme() == "": url.setScheme("http") # Request url if url.isValid(): self.list_of_web_pages[self.tab_bar.currentIndex()].page().load(url) else: url.clear() def backPageButton(self): tab_index = self.tab_bar.currentIndex() self.list_of_web_pages[tab_index].back() def forwardPageButton(self): tab_index = self.tab_bar.currentIndex() self.list_of_web_pages[tab_index].forward() def refreshButton(self): tab_index = self.tab_bar.currentIndex() self.list_of_web_pages[tab_index].reload() def homeButton(self): tab_index = self.tab_bar.currentIndex() self.list_of_web_pages[tab_index].setUrl(QUrl("https://google.com")) def stopButton(self): tab_index = self.tab_bar.currentIndex() self.list_of_web_pages[tab_index].stop() def closeTab(self, tab_index): """ This signal is emitted when the close button on a tab is clicked. The index is the index of the tab that should be removed. """ self.list_of_web_pages.pop(tab_index) self.list_of_urls.pop(tab_index) self.tab_bar.removeTab(tab_index) def positionMainWindow(self): """ Use QDesktopWidget class to access information about your screen and use it to position the application window when starting a new application. """ desktop = QDesktopWidget().screenGeometry() screen_width = desktop.width() screen_height = desktop.height() self.setGeometry(0, 0, screen_width, screen_height)
def setupUI(self): hbox = QHBoxLayout(self) hbox.setContentsMargins(22, 12, 22, 12) splitter = QSplitter(Qt.Vertical) splitter.setStyleSheet( "QSplitter::handle{border-image: url(icons/split_line.png)}") splitter.setHandleWidth(17) hbox.addWidget(splitter) left = QWidget(splitter) vbox = QVBoxLayout(left) vbox.setSpacing(0) vbox.setContentsMargins(0, 0, 0, 4) buttonsContainer1 = QWidget() vbox.addWidget(buttonsContainer1) hbox2 = QHBoxLayout(buttonsContainer1) hbox2.setContentsMargins(2, 3, 2, 10) comboWhere = QComboBox() comboWhere.setStyleSheet( "QComboBox {width:160px;min-width:20px;height:28px;border:1px solid #c7c7c7;font-size:14px;selection-background-color:#f4f4f4;}" "QComboBox QAbstractItemView {background:#ffffff;color:#333333;}" "QComboBox::drop-down{width: 21px;border-left: 0px solid #333333;}" "QComboBox::down-arrow:hover {image: url(icons/ComboBox_hover.png);}" "QComboBox::down-arrow {image: url(icons/ComboBox_default.png);}") comboWhere.currentIndexChanged.connect( self.handleComboWhereIndexChanged) hbox2.addWidget(comboWhere) self.comboWhere = comboWhere comboLang = QComboBox() comboLang.setStyleSheet( "QComboBox {width:160px;min-width:20px;height:28px;border:1px solid #c7c7c7;font-size:14px;selection-background-color:#f4f4f4;}" "QComboBox QAbstractItemView {background:#ffffff;color:#333333;}" "QComboBox::drop-down{width: 21px;border-left: 0px solid #333333;}" "QComboBox::down-arrow:hover {image: url(icons/ComboBox_hover.png);}" "QComboBox::down-arrow {image: url(icons/ComboBox_default.png);}") comboLang.currentIndexChanged.connect( self.handleComboLanguageIndexChanged) hbox2.addWidget(comboLang) self.comboLang = comboLang #addStretch hbox2.addStretch() btnInstallFont = QPushButton() btnInstallFont.setEnabled(True) btnInstallFont.clicked.connect(self.installFonts) btnInstallFont.setStyleSheet( "QPushButton{border-image: url(icons/install_default.png) 0 0 0 0;border:none;color:rgb(255, 255, 255);font-size:14px;}" "QPushButton:hover{border-image: url(icons/install_hover.png) 0 0 0 0;border:none;color:rgb(255, 255, 255);}" "QPushButton:checked{border-image: url(icons/install_click.png) 0 0 0 0;border:none;color:rgb(255, 255, 255);}" ) btnInstallFont.setFixedSize(100, 30) hbox2.addWidget(btnInstallFont) self.btnInstallFont = btnInstallFont btnUninstallFont = QPushButton() btnUninstallFont.setEnabled(False) btnUninstallFont.clicked.connect(self.uninstallFonts) btnUninstallFont.setStyleSheet( "QPushButton{border-image: url(icons/uninstall_default.png);font-size:14px;}" "QPushButton:disabled{border-image: url(icons/uninstall_forbid.png) 0 0 0 0;border:none;color:#c1c1c1;font-size:14px;}" "QPushButton:hover{border-image: url(icons/uninstall_hover.png) 0 0 0 0;border:none;color:rgb(51, 51, 51);}" "QPushButton:checked{border-image: url(icons/uninstall_click.png) 0 0 0 0;border:none;color:rgb(51, 51, 51);}" ) btnUninstallFont.setFixedSize(100, 30) hbox2.addWidget(btnUninstallFont) self.btnUninstallFont = btnUninstallFont buttonsContainer4 = QWidget() vbox.addWidget(buttonsContainer4) hbox4 = QHBoxLayout(buttonsContainer4) hbox4.setContentsMargins(0, 0, 0, 6) hbox4.setSpacing(3) #add checkBox checkCheckALL = QCheckBox() checkCheckALL.setChecked(False) checkCheckALL.setStyleSheet( "QCheckBox::indicator {width: 20px; height: 20px;}" "QCheckBox::indicator:unchecked {image:url(icons/CheckBox_uncheck_default.png);}" "QCheckBox::indicator:unchecked:hover {image:url(icons/CheckBox_uncheck_hover.png);}" "QCheckBox::indicator:checked:hover {image:url(icons/CheckBox_checked_hover.png);}" "QCheckBox::indicator:checked {image:url(icons/CheckBox_checked_default.png);}" ) checkCheckALL.stateChanged.connect(self.CheckboxChange) checkCheckALL.stateChanged.connect(self.apply) hbox4.addWidget(checkCheckALL) self.checkCheckALL = checkCheckALL #add Label textLabel = QLabel() hbox4.addWidget(textLabel) self.textLabel = textLabel textLabel3 = QLabel() hbox4.addWidget(textLabel3) self.textLabel3 = textLabel3 textLabel4 = QLabel() hbox4.addWidget(textLabel4) self.textLabel4 = textLabel4 btnExpandAll = QPushButton() btnExpandAll.setStyleSheet( "QPushButton{border-image: url(icons/ExpandAll_default.png) 0 0 0 0;border:none;color:rgb(51, 51, 51);}" "QPushButton:hover{border-image: url(icons/ExpandAll_hover.png) 0 0 0 0;border:none;color:rgb(51, 51, 51);}" "QPushButton:checked{border-image: url(icons/ExpandAll_click.png) 0 0 0 0;border:none;color:rgb(51, 51, 51);}" ) btnExpandAll.setFixedSize(87, 26) btnExpandAll.clicked.connect(self.expandORcollapse) self.btnExpandAll = btnExpandAll hbox4.addWidget(btnExpandAll) #addStretch hbox4.addStretch() tree = QTreeWidget() tree.setColumnCount(3) tree.setColumnWidth(0, 250) tree.setColumnWidth(1, 250) tree.setColumnWidth(2, 300) tree.setStyleSheet( "QTreeWidget {border:1px solid #c7c7c7;}" "QTreeWidget QHeaderView::section{padding-left:6px;height:24px;background-color:#f8f8f8;border:1px solid #dddddd;border-bottom: 0px;border-top: 0px;}" "QTreeView::branch:has-children:!has-siblings:closed,\ QTreeView::branch:closed:has-children:has-siblings{border-image: none; image: url(icons/treeArrow_right.png);}\ QTreeView::branch:open:has-children:!has-siblings,\ QTreeView::branch:open:has-children:has-siblings{border-image: none; image: url(icons/treeArrow_bottom.png);}\ QTreeWidget::indicator:checked {image: url(icons/CheckBox_checked_default.png);}\ QTreeWidget::indicator:checked:hover {image: url(icons/CheckBox_checked_hover.png);}\ QTreeWidget::indicator:unchecked {image: url(icons/CheckBox_uncheck_default.png);}\ QTreeWidget::indicator:unchecked:hover {image: url(icons/CheckBox_uncheck_hover.png);}" "QTreeView QScrollBar:vertical {border:1px solid #c7c7c7;border-left: 0px;background-color:#f1f1f1;padding-top:15px;padding-bottom:15px;}" "QTreeView QScrollBar::handle:vertical {background-color:#c7c7c7;min-height:30px;}" "QTreeView QScrollBar::handle:vertical:hover {background-color:#a6a6a6;}" "QTreeView QScrollBar::add-line:vertical {border-image: url(icons/scorllAdd_default.png);}" "QTreeView QScrollBar::add-line:vertical:hover {border-image: url(icons/scorllAdd_hover.png);}" "QTreeView QScrollBar::sub-line:vertical:hover {border-image: url(icons/scorllSub_hover.png);}" "QTreeView QScrollBar::sub-line:vertical {border-image: url(icons/scorllSub_default.png);}" ) tree.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) tree.itemChanged.connect(self.handleTreeItemChanged) vbox.addWidget(tree) self.tree = tree editSearch = QLineEdit("") editSearch.setFixedSize(210, 30) editAction = QAction(editSearch) editSearch.addAction(editAction, QLineEdit.TrailingPosition) editAction.setIcon(QIcon("icons/search.png")) editSearch.textChanged.connect(self.handleEditSearchTextChanged) editAction.triggered.connect(self.loopSearch) editSearch.setStyleSheet("QLineEdit {border:1px solid #c7c7c7;}") self.editSearch = editSearch hbox4.addWidget(editSearch) right = QWidget() splitter.addWidget(right) # splitter.setSizes([200, 200]) splitter.setStretchFactor(0, 45) splitter.setStretchFactor(1, 55) vbox2 = QVBoxLayout(right) vbox2.setSpacing(0) vbox2.setContentsMargins(0, 4, 0, 10) buttonsContainer2 = QWidget() vbox2.addWidget(buttonsContainer2) hbox3 = QHBoxLayout(buttonsContainer2) hbox3.setContentsMargins(0, 0, 0, 5) hbox3.setSpacing(7) #add Label textLabel2 = QLabel() hbox3.addWidget(textLabel2) self.textLabel2 = textLabel2 spinBox = QSpinBox() spinBox.setRange(5, 60) spinBox.setValue(14) spinBox.setSingleStep(1) spinBox.setFixedSize(150, 26) spinBox.setStyleSheet( "QSpinBox {padding-right:23px;border: 1px solid #c7c7c7;}" "QSpinBox::down-button{subcontrol-origin: padding;subcontrol-origin:border;subcontrol-position:right;image: url(icons/reduce_default.png);position:relative;right:23px;}" "QSpinBox::down-button:hover{image: url(icons/reduce_click.png);}" "QSpinBox::up-button{subcontrol-origin:border;subcontrol-position:right;image: url(icons/add_default.png);position:relative;right:2px;}" "QSpinBox::up-button:hover{image: url(icons/add_click.png);}") spinBox.valueChanged.connect(self.handleFontSizeChanged) hbox3.addWidget(spinBox) self.spinBox = spinBox lineEdit = QLineEdit() lineEdit.setStyleSheet( "QLineEdit {border:1px solid #c7c7c7;height:24px;}") hbox3.addWidget(lineEdit) self.lineEdit = lineEdit scroll = QScrollArea() #scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) #scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) scroll.setWidgetResizable(True) scroll.setStyleSheet( "QScrollArea {border:1px solid #c7c7c7;}" "QScrollArea QScrollBar {border:1px solid #c7c7c7;border-left: 0px;}" "QScrollArea QScrollBar:vertical {background-color:#f1f1f1;padding-top:15px;padding-bottom:15px;}" "QScrollArea QScrollBar::handle:vertical {background-color:#c7c7c7;min-height:30px;}" "QScrollArea QScrollBar::handle:vertical:hover {background-color:#a6a6a6;}" "QScrollArea QScrollBar::add-line:vertical {border-image: url(icons/scorllAdd_default.png);}" "QScrollArea QScrollBar::add-line:vertical:hover {border-image: url(icons/scorllAdd_hover.png);}" "QScrollArea QScrollBar::sub-line:vertical:hover {border-image: url(icons/scorllSub_hover.png);}" "QScrollArea QScrollBar::sub-line:vertical {border-image: url(icons/scorllSub_default.png);}" ) vbox2.addWidget(scroll) displayer = FontDisplayer() scroll.setWidget(displayer) self.displayer = displayer
class InitialPage(QWizardPage): def __init__(self): super().__init__() vbox = QVBoxLayout(self) frame = QFrame(self) vbox.addStretch(1) frame.setFrameShape(QFrame.StyledPanel) vbox.addWidget(frame) # Fields fields_box = QGridLayout(frame) # Project name fields_box.addWidget(QLabel(translations.TR_WIZARD_PROJECT_NAME), 0, 0) self._line_project_name = QLineEdit("untitled") self.registerField("name*", self._line_project_name) fields_box.addWidget(self._line_project_name, 0, 1) # Project location fields_box.addWidget( QLabel(translations.TR_WIZARD_PROJECT_LOCATION), 1, 0) self._line_location = QLineEdit() self._line_location.setReadOnly(True) self._line_location.setText(utils.get_home_dir()) self.registerField("path", self._line_location) choose_dir_act = self._line_location.addAction( self.style().standardIcon( self.style().SP_DirIcon), QLineEdit.TrailingPosition) fields_box.addWidget(self._line_location, 1, 1) # Project description fields_box.addWidget(QLabel(translations.TR_PROJECT_DESCRIPTION), 2, 0) self._txt_desciption = QPlainTextEdit() fields_box.addWidget(self._txt_desciption, 2, 1) self.registerField("description", self._txt_desciption) # Project license fields_box.addWidget(QLabel(translations.TR_PROJECT_LICENSE), 3, 0) combo_license = QComboBox() combo_license.addItems(LICENSES) combo_license.setCurrentIndex(12) fields_box.addWidget(combo_license, 3, 1) self.registerField("license", combo_license, property="currentText") # Project interpreter fields_box.addWidget( QLabel(translations.TR_WIZARD_PROJECT_INTERPRETER), 4, 0) combo_interpreter = QComboBox() combo_interpreter.addItems(utils.get_python()) combo_interpreter.setCurrentText(sys.executable) fields_box.addWidget(combo_interpreter, 4, 1) self.registerField("interpreter", combo_interpreter) # Connections self._line_project_name.textChanged.connect(self._on_text_changed) choose_dir_act.triggered.connect(self._choose_dir) def _choose_dir(self): dirname = QFileDialog.getExistingDirectory( self, translations.TR_WIZARD_CHOOSE_DIR, utils.get_home_dir()) if dirname: self._line_location.setText(dirname) @property def location(self): return self._line_location.text() @property def project_name(self): return self._line_project_name.text() def _on_text_changed(self): ok = self.validate() if not ok: self._line_project_name.setStyleSheet("background-color: red") else: self._line_project_name.setStyleSheet("background-color: none;") def validate(self): ok = True project_path = os.path.join(self.location, self.project_name) if file_manager.folder_exists(project_path): ok = False return ok def isComplete(self): val = super().isComplete() return val and self.validate()
class ParameterTab(QWidget): def __init__(self, options, favorites, settings, parent=None): super().__init__(parent=parent) # Building widget tab 2. # Button for selecting download location. self.browse_btn = QPushButton('Browse') self.save_profile_btn = QPushButton('Save Profile') self.save_profile_btn.resize(self.save_profile_btn.sizeHint()) self.download_label = QLabel('Download to:') self.favlabel = QLabel('Favorites:') self.optlabel = QLabel('All settings:') # LineEdit for download location. self.download_lineedit = QLineEdit() self.download_lineedit.setReadOnly(True) self.download_lineedit.setFocusPolicy(Qt.NoFocus) if settings.is_activate('Download location'): self.download_lineedit.setText('') self.download_lineedit.setToolTip(settings.get_active_setting('Download location')) else: self.download_lineedit.setText('DL') self.download_lineedit.setToolTip('Default download location.') self.download_lineedit.setContextMenuPolicy(Qt.ActionsContextMenu) # Sets up the parameter tree. self.options = ParameterTree(options, self) self.favorites = ParameterTree(favorites, self) self.favorites.favorite = True # Can only be toggled in settings manually if settings.user_options['show_collapse_arrows']: self.options.setRootIsDecorated(True) self.favorites.setRootIsDecorated(True) else: self.options.setRootIsDecorated(False) self.favorites.setRootIsDecorated(False) self.open_folder_action = QAction('Open location', parent=self.download_lineedit) self.copy_action = QAction('Copy', parent=self.download_lineedit) self.download_lineedit.addAction(self.open_folder_action) self.download_lineedit.addAction(self.copy_action) # Layout tab 2. self.QH = QHBoxLayout() # Adds widgets to the horizontal layout. label, lineedit and button. self.QH.addWidget(self.download_label) self.QH.addWidget(self.download_lineedit) self.QH.addWidget(self.browse_btn) self.QH.addWidget(self.save_profile_btn) self.QV = QVBoxLayout() self.QV.addLayout(self.QH, stretch=0) self.fav_frame = QFrame() self.opt_frame2 = QFrame() self.opt_frame2.setFrameShape(QFrame.HLine) self.fav_frame.setFrameShape(QFrame.HLine) self.fav_frame.setLineWidth(2) self.opt_frame2.setLineWidth(2) self.fav_frame.setObjectName('line') self.opt_frame2.setObjectName('line') self.fav_layout = QVBoxLayout() self.opt_layout = QVBoxLayout() self.fav_layout.setSizeConstraint(QVBoxLayout.SetMinimumSize) self.fav_layout.addWidget(self.favlabel, stretch=0) self.fav_layout.addWidget(self.fav_frame, stretch=0) self.fav_layout.addWidget(self.favorites, stretch=1, alignment=Qt.AlignTop) self.opt_layout.addWidget(self.optlabel, stretch=0) self.opt_layout.addWidget(self.opt_frame2, stretch=0) self.opt_layout.addWidget(self.options, stretch=1, alignment=Qt.AlignTop) self.parameter_layout = QHBoxLayout() self.parameter_layout.addLayout(self.fav_layout) self.parameter_layout.addLayout(self.opt_layout) self.QV.addLayout(self.parameter_layout) self.setLayout(self.QV) self.download_option = self.find_download_widget() def enable_favorites(self, enable): if not enable: self.favorites.hide() self.fav_frame.hide() self.favlabel.hide() else: self.favorites.show() self.fav_frame.show() self.favlabel.show() def find_download_widget(self): """ Finds the download widget. """ # TODO: Refactor to check the settings file/object, not the parameterTrees. for item in self.favorites.topLevelItems(): if item.data(0, DATA_SLOT) == 'Download location': self.download_option = item return item for item in self.options.topLevelItems(): if item.data(0, DATA_SLOT) == 'Download location': self.download_option = item return item raise SettingsError('No download item found in settings.')
class InitWindow(QWidget): sigOpenProject = pyqtSignal(object) sigExit = pyqtSignal() log = logging.getLogger(__name__) WIDTH = 600 HEIGHT = 400 def __init__(self, recent_projects: List[Path] = None, is_updated: bool = False): flags = Qt.WindowFlags() flags |= Qt.FramelessWindowHint super().__init__(flags=flags) self.setAttribute(Qt.WA_DeleteOnClose) self.setWindowTitle('GIWAXS analysis') self.setWindowIcon(Icon('window_icon')) self.project_name: str = 'untitled' self.project_path: Path = Path( '~/GIWAXS projects').expanduser().resolve() / self.project_name self.__init_ui(recent_projects, is_updated) self.setFixedWidth(self.WIDTH) self.setFixedHeight(self.HEIGHT) center_widget(self) self.show() def __init_ui(self, recent_projects: List[Path] or None, is_updated: bool = False): layout = QGridLayout(self) layout.setContentsMargins(40, 20, 40, 40) self.file_line = QLineEdit(str(self.project_path), self) self.file_line.textEdited.connect(self._on_text_editing) browse_action = self.file_line.addAction(Icon('folder'), QLineEdit.LeadingPosition) browse_action.triggered.connect(self._new_project_dialog) self.create_button = QPushButton( f'Create project "{self.project_name}"', self) self.create_button.clicked.connect(self._create) if is_updated: title = f'GIWAXS analysis. Updated to the latest version {__version__}!' else: title = f'GIWAXS analysis (version {__version__})' layout.addWidget(Label(title, self, 11, True), 0, 0, 1, 3, alignment=Qt.AlignHCenter) layout.addWidget(Label('New project', self, 9.5), 1, 0, 1, 3) layout.addWidget(self.file_line, 2, 0, 1, 2) layout.addWidget(self.create_button, 2, 2) if recent_projects: layout.addWidget(self._init_recent_projects_area(recent_projects), 3, 0, 1, 3) layout.addLayout(self._init_exit_button(), 4 if recent_projects else 3, 0, 1, 3) def _init_exit_button(self): e_layout = QVBoxLayout() exit_button = QPushButton('Exit') exit_button.clicked.connect(self.sigExit) e_layout.addWidget(QLabel('')) e_layout.addWidget(exit_button) return e_layout def _init_recent_projects_area(self, recent_projects): q_scroll_area = QScrollArea(self) q_scroll_area.setWidgetResizable(True) q_scroll_area.setGeometry(0, 0, self.WIDTH, self.HEIGHT // 2) projects_list_widget = QWidget(self) projects_list_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) scroll_layout = QVBoxLayout(projects_list_widget) scroll_layout.addWidget(QLabel('', self)) scroll_layout.addWidget(Label('Recent projects', self, 9.5)) for path in recent_projects: btn = QPushButton(path.name) btn.clicked.connect(lambda *x, p=path: self.sigOpenProject.emit(p)) scroll_layout.addWidget(btn) q_scroll_area.setWidget(projects_list_widget) return q_scroll_area @pyqtSlot(str, name='onTextEditing') def _on_text_editing(self, path: str): path = Path(path) folder, name = path.parent, path.name if not folder.is_dir(): folder = self.project_path.parent self.project_name = name self.project_path = folder / name self.create_button.setText(f'Create project "{self.project_name}"') @pyqtSlot(name='NewProjectDialog') def _new_project_dialog(self): folder = QFileDialog.getExistingDirectory( self, 'New project folder', options=QFileDialog.ShowDirsOnly | QFileDialog.DontUseNativeDialog) if not folder: return folder = Path(folder).resolve() if folder.is_dir(): self.project_path = folder / self.project_name self.file_line.setText(str(self.project_path)) else: color_animation(self.file_line) show_error('Invalid folder. Please, select existing folder', error_title='Wrong path') def _create(self): try: self.project_path.mkdir(parents=True, exist_ok=True) self.sigOpenProject.emit(self.project_path.resolve()) # except FileExistsError: # show_error(f'The folder {str(self.project_path.resolve())} already exists', error_title='Folder exists') # color_animation(self.file_line) except PermissionError: folder = get_folder_filepath( self, 'Permission denied, please, create a project folder manually', directory=str(Path('~').expanduser().resolve())) if folder and folder.is_dir(): self.sigOpenProject.emit(folder.resolve())
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() translator = QTranslator() print(QLocale.system().name()) translator.load('qt_' + QLocale.system().name(), QLibraryInfo.location(QLibraryInfo.TranslationsPath)) app.installTranslator(translator) self.setStyleSheet(myStyleSheet(self)) self.MaxRecentFiles = 5 self.windowList = [] self.recentFileActs = [] self.curFile = '' self.setAcceptDrops(True) self.settings = QSettings("QTextEdit", "QTextEdit") self.myeditor = QTextEdit() assert (self.locale().language() == QLocale.German) self.myeditor.setAcceptRichText(False) self.myeditor.setUndoRedoEnabled(True) self.myeditor.setStyleSheet(myStyleSheet(self)) self.myeditor.setContextMenuPolicy(Qt.CustomContextMenu) self.myeditor.customContextMenuRequested.connect( self.contextMenuRequested) self.createActions() self.createToolBars() self.createMenus() self.createStatusBar() self.setWindowIcon(QIcon.fromTheme("gnome-documents")) self.readSettings() self.myeditor.document().contentsChanged.connect( self.documentWasModified) self.setCurrentFile('') self.setCentralWidget(self.myeditor) self.myeditor.setFocus() def closeEvent(self, event): if self.maybeSave(): self.writeSettings() event.accept() else: event.ignore() def newFile(self): if self.maybeSave(): self.myeditor.clear() self.setCurrentFile('') def open(self): if self.maybeSave(): fileName, _ = QFileDialog.getOpenFileName( self, "Datei öffnen", QDir.homePath() + "/Dokumente", "Text Dateien (*.txt *.csv *.sh *.py) ;; alle Dateien (*.*)") if fileName: self.loadFile(fileName) else: self.statusBar().showMessage("abgebrochen", 3000) def save(self): if not self.myeditor.toPlainText() == "": if self.myeditor.document().isModified(): if self.curFile: return self.saveFile(self.curFile) self.setCurrentFile(fileName) else: return self.saveAs() else: self.statusBar().showMessage( "Datei '" + self.curFile + "' bereits gespeichert", 3000) else: self.statusBar().showMessage("kein Text") def saveAs(self): if not self.myeditor.toPlainText() == "": if self.curFile: fileName, _ = QFileDialog.getSaveFileName( self, "Speichern als...", self.curFile, "Text Dateien (*.txt)") else: fileName, _ = QFileDialog.getSaveFileName( self, "Speichern als...", QDir.homePath() + "/Dokumente/Unbenannt.txt", "Text Dateien (*.txt)") if fileName: return self.saveFile(fileName) return False else: self.statusBar().showMessage("kein Text") def contextMenuRequested(self, point): cmenu = QMenu() cmenu = self.myeditor.createStandardContextMenu() if not self.myeditor.textCursor().selectedText() == "": cmenu.addSeparator() cmenu.addAction(QIcon.fromTheme("edit-find-and-replace"), "alle Übereinstimmungen ersetzen", self.replaceThis) cmenu.exec_(self.myeditor.mapToGlobal(point)) def replaceThis(self): if not self.myeditor.textCursor().selectedText() == "": rtext = self.myeditor.textCursor().selectedText() dlg = QInputDialog(self, Qt.Dialog) dlg.setOkButtonText("Replace") text = dlg.getText(self, "Ersetzen", "ersetze '" + rtext + "' durch:", QLineEdit.Normal, "") oldtext = self.myeditor.document().toPlainText() if not (text[0] == ""): newtext = oldtext.replace(rtext, text[0]) self.myeditor.setPlainText(newtext) self.myeditor.document().setModified(True) def about(self): link = "<p><a title='Axel Schneider' href='http://goodoldsongs.jimdo.com' target='_blank'>Axel Schneider</a></p>" title = "über QTextEdit" message = ( "<span style='text-shadow: #2e3436 2px 2px 2px; color: #6169e1; font-size: 24pt;font-weight: bold;'><strong>QTextEdit 1.2</strong></span></p><br><br>created by<h2 >" + link + "</h2> with PyQt5" "<br><br>Copyright © 2018 The Qt Company Ltd and other contributors." "<br>Qt and the Qt logo are trademarks of The Qt Company Ltd.") msg = QMessageBox(QMessageBox.Information, title, message, QMessageBox.NoButton, self, Qt.Dialog | Qt.NoDropShadowWindowHint).show() def documentWasModified(self): self.setWindowModified(self.myeditor.document().isModified()) def createActions(self): self.newAct = QAction(QIcon.fromTheme('document-new'), "&Neu", self, shortcut=QKeySequence.New, statusTip="neue Datei erstellen", triggered=self.newFile) self.openAct = QAction(QIcon.fromTheme('document-open'), "Öffnen.", self, shortcut=QKeySequence.Open, statusTip="Datei öffnen", triggered=self.open) self.saveAct = QAction(QIcon.fromTheme('document-save'), "Speichern", self, shortcut=QKeySequence.Save, statusTip="Dokument speichern", triggered=self.save) self.saveAsAct = QAction( QIcon.fromTheme('document-save-as'), "Speichern als...", self, shortcut=QKeySequence.SaveAs, statusTip="Dokument unter neuem Namen speichern", triggered=self.saveAs) self.exitAct = QAction(QIcon.fromTheme('application-exit'), "Beenden", self, shortcut="Ctrl+Q", statusTip="Programm beenden", triggered=self.close) self.cutAct = QAction(QIcon.fromTheme('edit-cut'), "Ausschneiden", self, shortcut=QKeySequence.Cut, statusTip="Ausschneiden", triggered=self.myeditor.cut) self.copyAct = QAction(QIcon.fromTheme('edit-copy'), "Kopieren", self, shortcut=QKeySequence.Copy, statusTip="Kopieren", triggered=self.myeditor.copy) self.pasteAct = QAction(QIcon.fromTheme('edit-paste'), "Einfügen", self, shortcut=QKeySequence.Paste, statusTip="Einfügen", triggered=self.myeditor.paste) self.undoAct = QAction(QIcon.fromTheme('edit-undo'), "Rückgängig", self, shortcut=QKeySequence.Undo, statusTip="Rückgängig", triggered=self.myeditor.undo) self.redoAct = QAction(QIcon.fromTheme('edit-redo'), "Wiederholen", self, shortcut=QKeySequence.Redo, statusTip="Wiederholen", triggered=self.myeditor.redo) self.aboutAct = QAction(QIcon.fromTheme('help-about'), "Info", self, statusTip="über QTextEdit", triggered=self.about) self.aboutQtAct = QAction(QIcon.fromTheme('help-about'), "über Qt", self, statusTip="über Qt", triggered=QApplication.instance().aboutQt) self.repAllAct = QPushButton("alles ersetzen") self.repAllAct.setIcon(QIcon.fromTheme("edit-find-and-replace")) self.repAllAct.setStatusTip("alles ersetzen") self.repAllAct.clicked.connect(self.replaceAll) self.cutAct.setEnabled(False) self.copyAct.setEnabled(False) self.myeditor.copyAvailable.connect(self.cutAct.setEnabled) self.myeditor.copyAvailable.connect(self.copyAct.setEnabled) self.undoAct.setEnabled(False) self.redoAct.setEnabled(False) self.myeditor.undoAvailable.connect(self.undoAct.setEnabled) self.myeditor.redoAvailable.connect(self.redoAct.setEnabled) ### print preview self.printPreviewAct = QAction("Druckvorschau", self, shortcut=QKeySequence.Print, statusTip="Druckvorschau", triggered=self.handlePrintPreview) self.printPreviewAct.setIcon(QIcon.fromTheme("document-print-preview")) ### print self.printAct = QAction("Drucken", self, shortcut=QKeySequence.Print, statusTip="Dokument drucken", triggered=self.handlePrint) self.printAct.setIcon(QIcon.fromTheme("document-print")) for i in range(self.MaxRecentFiles): self.recentFileActs.append( QAction(self, visible=False, triggered=self.openRecentFile)) def findText(self): word = self.findfield.text() if self.myeditor.find(word): self.statusBar().showMessage("'" + word + "' gefunden", 2000) else: self.myeditor.moveCursor(QTextCursor.Start) if self.myeditor.find(word): return else: self.statusBar().showMessage("nichts gefunden", 3000) def replaceAll(self): oldtext = self.findfield.text() newtext = self.replacefield.text() if not oldtext == "": h = self.myeditor.toHtml().replace(oldtext, newtext) self.myeditor.setText(h) self.setModified(True) self.statusBar().showMessage("alles ersetzt", 3000) else: self.statusBar().showMessage("nichts zu ersetzen", 3000) def replaceOne(self): oldtext = self.findfield.text() newtext = self.replacefield.text() if not oldtext == "": h = self.myeditor.toHtml().replace(oldtext, newtext, 1) self.myeditor.setText(h) self.setModified(True) self.statusBar().showMessage("1 ersetzt", 3000) else: self.statusBar().showMessage("nichts zu ersetzen", 3000) def openRecentFile(self): action = self.sender() if action: if (self.maybeSave()): self.loadFile(action.data()) def createMenus(self): self.fileMenu = self.menuBar().addMenu("&Datei") self.separatorAct = self.fileMenu.addSeparator() self.fileMenu.addAction(self.newAct) self.fileMenu.addAction(self.openAct) self.fileMenu.addAction(self.saveAct) self.fileMenu.addAction(self.saveAsAct) self.fileMenu.addSeparator() for i in range(self.MaxRecentFiles): self.fileMenu.addAction(self.recentFileActs[i]) self.updateRecentFileActions() self.fileMenu.addSeparator() self.clearRecentAct = QAction("Liste löschen", self, triggered=self.clearRecentFiles) self.clearRecentAct.setIcon(QIcon.fromTheme("edit-clear")) self.fileMenu.addAction(self.clearRecentAct) self.fileMenu.addSeparator() self.fileMenu.addAction(self.exitAct) self.editMenu = self.menuBar().addMenu("&Bearbeiten") self.editMenu.addAction(self.undoAct) self.editMenu.addAction(self.redoAct) self.editMenu.addSeparator() self.editMenu.addAction(self.cutAct) self.editMenu.addAction(self.copyAct) self.editMenu.addAction(self.pasteAct) self.menuBar().addSeparator() self.helpMenu = self.menuBar().addMenu("&Hilfe") self.helpMenu.addAction(self.aboutAct) def createToolBars(self): self.fileToolBar = self.addToolBar("Datei") self.fileToolBar.setIconSize(QSize(16, 16)) self.fileToolBar.addAction(self.newAct) self.fileToolBar.addAction(self.openAct) self.fileToolBar.addAction(self.saveAct) self.fileToolBar.addAction(self.saveAsAct) self.fileToolBar.addSeparator() self.fileToolBar.addAction(self.printPreviewAct) self.fileToolBar.addAction(self.printAct) self.fileToolBar.setStyleSheet("QToolBar { border: 0px }") self.fileToolBar.setMovable(False) self.setContextMenuPolicy(Qt.NoContextMenu) self.editToolBar = self.addToolBar("Bearbeiten") self.editToolBar.setIconSize(QSize(16, 16)) self.editToolBar.addAction(self.undoAct) self.editToolBar.addAction(self.redoAct) self.editToolBar.addSeparator() self.editToolBar.addAction(self.cutAct) self.editToolBar.addAction(self.copyAct) self.editToolBar.addAction(self.pasteAct) self.editToolBar.setMovable(False) self.editToolBar.setStyleSheet("QToolBar { border: 0px }") ### find / replace toolbar self.addToolBarBreak() self.findToolBar = self.addToolBar("Suchen") self.findToolBar.setIconSize(QSize(16, 16)) self.findfield = QLineEdit() self.findfield.addAction(QIcon.fromTheme("edit-find"), 0) self.findfield.setClearButtonEnabled(True) self.findfield.setFixedWidth(200) self.findfield.setPlaceholderText("suchen") self.findfield.setStatusTip("drücke RETURN zum suchen") self.findfield.setText("") self.findfield.returnPressed.connect(self.findText) self.findToolBar.addWidget(self.findfield) self.replacefield = QLineEdit() self.replacefield.addAction(QIcon.fromTheme("edit-find-replace"), 0) self.replacefield.setClearButtonEnabled(True) self.replacefield.setFixedWidth(200) self.replacefield.setPlaceholderText("ersetzen durch") self.replacefield.setStatusTip( "drücke RETURN um das erste zu ersetzen") self.replacefield.returnPressed.connect(self.replaceOne) self.findToolBar.addSeparator() self.findToolBar.addWidget(self.replacefield) self.findToolBar.addSeparator() self.findToolBar.addWidget(self.repAllAct) self.findToolBar.setMovable(False) self.findToolBar.setStyleSheet("QToolBar { border: 0px }") def createStatusBar(self): self.statusBar().setStyleSheet(myStyleSheet(self)) self.statusBar().showMessage("Willkommen") self.DigitalClock = DigitalClock() self.DigitalClock.setStyleSheet( "QLCDNumber {padding: 2px, 2px 2px 2px; border: 0px solid #2e3436; color: #3465a4; background-color: transparent }" ) self.statusBar().addPermanentWidget(self.DigitalClock) def readSettings(self): pos = self.settings.value("pos", QPoint(200, 200)) size = self.settings.value("size", QSize(400, 400)) self.resize(size) self.move(pos) def writeSettings(self): self.settings.setValue("pos", self.pos()) self.settings.setValue("size", self.size()) def maybeSave(self): if self.myeditor.document().isModified(): ret = QMessageBox.warning( self, "QTextEdit Meldung", "Das Dokument wurde geändert.\nSollen die Änderungen gespeichert werden?", QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel, defaultButton=QMessageBox.Save) if ret == QMessageBox.Save: return self.save() if ret == QMessageBox.Cancel: return False return True def loadFile(self, fileName): file = QFile(fileName) if not file.open(QFile.ReadOnly | QFile.Text): QMessageBox.warning( self, "Meldung", "Cannot read file %s:\n%s." % (fileName, file.errorString())) return infile = QTextStream(file) QApplication.setOverrideCursor(Qt.WaitCursor) self.myeditor.setPlainText(infile.readAll()) QApplication.restoreOverrideCursor() self.setCurrentFile(fileName) self.statusBar().showMessage("Datei '" + fileName + "' geladen", 3000) def saveFile(self, fileName): file = QFile(fileName) if not file.open(QFile.WriteOnly | QFile.Text): QMessageBox.warning( self, "Message", "Cannot write file %s:\n%s." % (fileName, file.errorString())) return False outfile = QTextStream(file) QApplication.setOverrideCursor(Qt.WaitCursor) outfile << self.myeditor.toPlainText() QApplication.restoreOverrideCursor() self.setCurrentFile(fileName) self.statusBar().showMessage("Datei '" + fileName + "' gespeichert", 3000) return True def setCurrentFile(self, fileName): self.curFile = fileName self.myeditor.document().setModified(False) self.setWindowModified(False) if self.curFile: self.setWindowTitle(self.strippedName(self.curFile) + "[*]") else: self.setWindowTitle('Unbenannt.txt' + "[*]") files = self.settings.value('recentFileList', []) if not files == "": try: files.remove(fileName) except ValueError: pass if fileName: files.insert(0, fileName) del files[self.MaxRecentFiles:] self.settings.setValue('recentFileList', files) self.updateRecentFileActions() def updateRecentFileActions(self): mytext = "" files = self.settings.value('recentFileList', []) numRecentFiles = min(len(files), self.MaxRecentFiles) # if not files == "": for i in range(numRecentFiles): text = "&%d %s" % (i + 1, self.strippedName(files[i])) self.recentFileActs[i].setText(text) self.recentFileActs[i].setData(files[i]) self.recentFileActs[i].setVisible(True) self.recentFileActs[i].setIcon(QIcon.fromTheme("text-x-generic")) for j in range(numRecentFiles, self.MaxRecentFiles): self.recentFileActs[j].setVisible(False) self.separatorAct.setVisible((numRecentFiles > 0)) def clearRecentFiles(self, fileName): self.settings.clear() self.updateRecentFileActions() def strippedName(self, fullFileName): return QFileInfo(fullFileName).fileName() def msgbox(self, message): QMessageBox.warning(self, "Message", message) def handlePrint(self): if self.myeditor.toPlainText() == "": self.statusBar().showMessage("kein Text zum Drucken") self.msgbox("kein Text zum Drucken") else: dialog = QtPrintSupport.QPrintDialog() if dialog.exec_() == QDialog.Accepted: self.handlePaintRequest(dialog.printer()) self.statusBar().showMessage("Dokument gedruckt") def handlePrintPreview(self): if self.myeditor.toPlainText() == "": self.statusBar().showMessage("kein Text für Vorschau") self.msgbox("kein Text für Vorschau") else: dialog = QtPrintSupport.QPrintPreviewDialog() dialog.setGeometry(10, 0, self.width() - 60, self.height() - 60) dialog.paintRequested.connect(self.handlePaintRequest) dialog.exec_() self.statusBar().showMessage("Vorschau geschlossen") def handlePaintRequest(self, printer): printer.setDocName(self.curFile) document = self.myeditor.document() document.print_(printer) def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: event.ignore() def dropEvent(self, event): f = str(event.mimeData().urls()[0].toLocalFile()) self.loadFile(f)
class RenameDialog(QDialog): def __init__(self, parent: QWidget) -> None: super().__init__(parent) self._basename: str = "" self._build_gui() def _build_gui(self) -> None: self.resize(600, 100) self.setWindowTitle("RenameDialog") self.setWindowModality(Qt.WindowModal) # Widgets icon_label = QLabel() icon_label.setPixmap( QIcon.fromTheme("accessories-text-editor").pixmap(48)) icon_label.setAlignment(Qt.AlignTop) self.label = QLabel("Rename ...") self.label.setTextInteractionFlags(Qt.TextSelectableByMouse) self.name_edit = QLineEdit(self) self.name_reload = self.name_edit.addAction(QIcon.fromTheme("reload"), QLineEdit.TrailingPosition) self.name_reload.setShortcut("F5") self.name_reload.setToolTip("Reset the filename to it's original name") self.button_box = QDialogButtonBox(self) self.btn_rename = QPushButton(QIcon.fromTheme("document-save-as"), "Rename") self.button_box.addButton(self.btn_rename, QDialogButtonBox.AcceptRole) self.btn_cancel = self.button_box.addButton(QDialogButtonBox.Cancel) self.btn_rename.setDefault(True) # layout self.vbox = QVBoxLayout() self.vbox.addWidget(self.label) self.vbox.addWidget(self.name_edit) self.vbox.addStretch() self.vbox.addWidget(self.button_box) hbox = QHBoxLayout() hbox.addWidget(icon_label) hbox.addLayout(self.vbox) self.setLayout(hbox) # signals self.name_edit.returnPressed.connect(self.accept) self.btn_rename.clicked.connect(self._on_rename_clicked) self.btn_cancel.clicked.connect(self._on_cancel_clicked) self.name_reload.triggered.connect(self._on_name_reload) def _on_rename_clicked(self) -> None: self.accept() def _on_cancel_clicked(self) -> None: self.reject() def _on_name_reload(self) -> None: self.name_edit.setText(self._basename) root, ext = os.path.splitext(self._basename) self.name_edit.setSelection(0, len(root)) def get_old_basename(self) -> str: return self._basename def get_new_basename(self) -> str: return cast(str, self.name_edit.text()) def set_basename(self, basename: str) -> None: self._basename = basename self.setWindowTitle("Rename \"{}\"".format(basename)) self.label.setText("Rename \"{}\" to:".format(basename)) self.name_edit.setText(basename) root, ext = os.path.splitext(basename) self.name_edit.setSelection(0, len(root))
class GeneralConfiguration(QWidget): """General configuration class""" def __init__(self, parent): super().__init__() self._preferences = parent vbox = QVBoxLayout(self) # Groups group_box_start = QGroupBox(translations.TR_PREFERENCES_GENERAL_START) group_box_close = QGroupBox(translations.TR_PREFERENCES_GENERAL_CLOSE) group_box_workspace = QGroupBox( translations.TR_PREFERENCES_GENERAL_WORKSPACE) group_box_reset = QGroupBox(translations.TR_PREFERENCES_GENERAL_RESET) group_box_swap = QGroupBox( translations.TR_PREFERENCES_GENERAL_SWAPFILE) group_box_modification = QGroupBox( translations.TR_PREFERENCES_GENERAL_EXTERNALLY_MOD) # Group start box_start = QVBoxLayout(group_box_start) self._check_last_session = QCheckBox( translations.TR_PREFERENCES_GENERAL_LOAD_LAST_SESSION) self._check_notify_updates = QCheckBox( translations.TR_PREFERENCES_GENERAL_NOTIFY_UPDATES) box_start.addWidget(self._check_last_session) box_start.addWidget(self._check_notify_updates) # Group close box_close = QVBoxLayout(group_box_close) self._check_confirm_exit = QCheckBox( translations.TR_PREFERENCES_GENERAL_CONFIRM_EXIT) box_close.addWidget(self._check_confirm_exit) # Workspace and Project grid_workspace = QGridLayout(group_box_workspace) self._text_workspace = QLineEdit() choose_workspace_action = self._text_workspace.addAction( self.style().standardIcon(self.style().SP_DirIcon), QLineEdit.TrailingPosition) clear_workspace_action = self._text_workspace.addAction( self.style().standardIcon(self.style().SP_LineEditClearButton), QLineEdit.TrailingPosition) self._text_workspace.setReadOnly(True) grid_workspace.addWidget( QLabel(translations.TR_PREFERENCES_GENERAL_WORKSPACE), 0, 0) grid_workspace.addWidget(self._text_workspace, 0, 1) # Resetting prefences box_reset = QVBoxLayout(group_box_reset) btn_reset = QPushButton( translations.TR_PREFERENCES_GENERAL_RESET_PREFERENCES) box_reset.addWidget(btn_reset) # Swap File box_swap = QGridLayout(group_box_swap) box_swap.addWidget(QLabel( translations.TR_PREFERENCES_GENERAL_SWAPFILE_LBL), 0, 0) self._combo_swap_file = QComboBox() self._combo_swap_file.addItems([ translations.TR_PREFERENCES_GENERAL_SWAPFILE_DISABLE, translations.TR_PREFERENCES_GENERAL_SWAPFILE_ENABLE ]) self._combo_swap_file.currentIndexChanged.connect( self._change_swap_widgets_state) box_swap.addWidget(self._combo_swap_file, 0, 1) box_swap.addWidget(QLabel( translations.TR_PREFERENCES_GENERAL_SWAPFILE_SYNC_INTERVAL), 1, 0) self._spin_swap = QSpinBox() self._spin_swap.setSuffix("s") self._spin_swap.setRange(5, 600) self._spin_swap.setSingleStep(5) box_swap.addWidget(self._spin_swap, 1, 1) # Externally modification box_mod = QHBoxLayout(group_box_modification) box_mod.addWidget( QLabel(translations.TR_PREFERENCES_GENERAL_EXTERNALLY_MOD_LABEL)) self._combo_mod = QComboBox() self._combo_mod.addItems(["Ask", "Reload", "Ignore"]) box_mod.addWidget(self._combo_mod) # Add groups to main layout vbox.addWidget(group_box_start) vbox.addWidget(group_box_close) vbox.addWidget(group_box_workspace) vbox.addWidget(group_box_swap) vbox.addWidget(group_box_modification) vbox.addWidget(group_box_reset, alignment=Qt.AlignLeft) vbox.addSpacerItem( QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Expanding)) # Settings qsettings = IDE.ninja_settings() qsettings.beginGroup("ide") self._check_last_session.setChecked( qsettings.value("loadFiles", defaultValue=True, type=bool)) self._check_notify_updates.setChecked( qsettings.value("notifyUpdates", defaultValue=True, type=bool)) qsettings.endGroup() self._combo_swap_file.setCurrentIndex(settings.SWAP_FILE) self._spin_swap.setValue(settings.SWAP_FILE_INTERVAL) self._text_workspace.setText(settings.WORKSPACE) self._combo_mod.setCurrentIndex(settings.RELOAD_FILE) self._check_confirm_exit.setChecked(settings.CONFIRM_EXIT) # Connections btn_reset.clicked.connect(self._reset_preferences) choose_workspace_action.triggered.connect(self._load_workspace) clear_workspace_action.triggered.connect(self._text_workspace.clear) self._preferences.savePreferences.connect(self.save) def _change_swap_widgets_state(self, index): if index == 0: self._spin_swap.setEnabled(False) else: self._spin_swap.setEnabled(True) def _reset_preferences(self): """Reset all preferences to default values""" result = QMessageBox.question( self, translations.TR_PREFERENCES_GENERAL_RESET_TITLE, translations.TR_PREFERENCES_GENERAL_RESET_BODY, buttons=QMessageBox.Yes | QMessageBox.No ) if result == QMessageBox.Yes: qsettings = IDE.ninja_settings() qsettings.clear() self._preferences.close() def _load_workspace(self): """Ask the user for a Workspace path""" path = QFileDialog.getExistingDirectory( self, translations.TR_PREFERENCES_GENERAL_SELECT_WORKSPACE) self._text_workspace.setText(path) def save(self): """Save all preferences values""" qsettings = IDE.ninja_settings() qsettings.beginGroup("ide") settings.CONFIRM_EXIT = self._check_confirm_exit.isChecked() qsettings.setValue("confirmExit", settings.CONFIRM_EXIT) qsettings.setValue("loadFiles", self._check_last_session.isChecked()) qsettings.setValue("notifyUpdates", self._check_notify_updates.isChecked()) settings.WORKSPACE = self._text_workspace.text() qsettings.setValue("workspace", settings.WORKSPACE) settings.RELOAD_FILE = self._combo_mod.currentIndex() qsettings.setValue("reloadSetting", settings.RELOAD_FILE) settings.SWAP_FILE = self._combo_swap_file.currentIndex() qsettings.setValue("swapFile", settings.SWAP_FILE) settings.SWAP_FILE_INTERVAL = self._spin_swap.value() qsettings.setValue("swapFileInterval", settings.SWAP_FILE_INTERVAL) qsettings.endGroup()
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.setGeometry(0, 0, 700, 400) self.setContentsMargins(6, 6, 6, 6) self.setStyleSheet(myStyleSheet(self)) self.setWindowTitle("Radio Stations - searching with pyradios") self.genreList = genres.splitlines() self.findfield = QLineEdit() self.findfield.setFixedWidth(250) self.findfield.addAction(QIcon.fromTheme("edit-find"), 0) self.findfield.setPlaceholderText("type search term and press RETURN ") self.findfield.returnPressed.connect(self.findStations) self.findfield.setClearButtonEnabled(True) self.field = QPlainTextEdit() self.field.setContextMenuPolicy(Qt.CustomContextMenu) self.field.customContextMenuRequested.connect( self.contextMenuRequested) self.field.cursorPositionChanged.connect(self.selectLine) self.field.setWordWrapMode(QTextOption.NoWrap) ### volume slider self.volSlider = QSlider() self.volSlider.setFixedWidth(100) self.volSlider.setOrientation(Qt.Horizontal) self.volSlider.valueChanged.connect(self.setVolume) self.volSlider.setMinimum(0) self.volSlider.setMaximum(100) ### genre box self.combo = QComboBox() self.combo.currentIndexChanged.connect(self.comboSearch) self.combo.addItem("choose Genre") for m in self.genreList: self.combo.addItem(m) self.combo.addItem("Country") self.combo.setFixedWidth(150) ### toolbar ### self.tb = self.addToolBar("tools") self.tb.setContextMenuPolicy(Qt.PreventContextMenu) self.tb.setMovable(False) self.saveButton = QPushButton("Save as txt") self.saveButton.setIcon(QIcon.fromTheme("document-save")) self.saveButton.clicked.connect(self.saveStations) self.savePlaylistButton = QPushButton("Save as m3u") self.savePlaylistButton.setIcon(QIcon.fromTheme("document-save")) self.savePlaylistButton.clicked.connect(self.savePlaylist) self.setCentralWidget(self.field) self.tb.addWidget(self.findfield) self.tb.addWidget(self.saveButton) self.tb.addWidget(self.savePlaylistButton) self.tb.addSeparator() self.tb.addWidget(self.combo) ### player ### self.player = QMediaPlayer() self.player.metaDataChanged.connect(self.metaDataChanged) self.startButton = QPushButton("Play") self.startButton.setIcon(QIcon.fromTheme("media-playback-start")) self.startButton.clicked.connect(self.getURLtoPlay) self.stopButton = QPushButton("Stop") self.stopButton.setIcon(QIcon.fromTheme("media-playback-stop")) self.stopButton.clicked.connect(self.stopPlayer) self.statusBar().addPermanentWidget(self.volSlider) self.statusBar().addPermanentWidget(self.startButton) self.statusBar().addPermanentWidget(self.stopButton) ## actions self.getNameAction = QAction(QIcon.fromTheme("edit-copy"), "copy Station Name", self, triggered=self.getName) self.getUrlAction = QAction(QIcon.fromTheme("edit-copy"), "copy Station URL", self, triggered=self.getURL) self.getNameAndUrlAction = QAction(QIcon.fromTheme("edit-copy"), "copy Station Name,URL", self, triggered=self.getNameAndUrl) self.getURLtoPlayAction = QAction( QIcon.fromTheme("media-playback-start"), "play Station", self, shortcut="F6", triggered=self.getURLtoPlay) self.addAction(self.getURLtoPlayAction) self.stopPlayerAction = QAction(QIcon.fromTheme("media-playback-stop"), "stop playing", self, shortcut="F7", triggered=self.stopPlayer) self.addAction(self.stopPlayerAction) self.helpAction = QAction(QIcon.fromTheme("help-info"), "Help", self, shortcut="F1", triggered=self.showHelp) self.addAction(self.helpAction) self.getForWebAction = QAction(QIcon.fromTheme("browser"), "copy for WebPlayer", self, triggered=self.getForWeb) self.volSlider.setValue(60) self.statusBar().showMessage("Welcome", 0) def setVolume(self): self.player.setVolume(self.volSlider.value()) def comboSearch(self): if self.combo.currentIndex() > 0: self.findfield.setText(self.combo.currentText()) self.findStations() def getName(self): t = self.field.textCursor().selectedText().partition(",")[0] clip = QApplication.clipboard() clip.setText(t) def getURL(self): t = self.field.textCursor().selectedText().partition(",")[2] clip = QApplication.clipboard() clip.setText(t) def getNameAndUrl(self): t = self.field.textCursor().selectedText() clip = QApplication.clipboard() clip.setText(t) def getForWeb(self): t = self.field.textCursor().selectedText() name = t.partition(",")[0] url = t.partition(",")[2] result = f"<li><a class='chlist' href='{url}'>{name}</a></li>" clip = QApplication.clipboard() clip.setText(result) def selectLine(self): tc = self.field.textCursor() tc.select(QTextCursor.LineUnderCursor) tc.movePosition(QTextCursor.StartOfLine, QTextCursor.MoveAnchor) ##, tc.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor) self.field.setTextCursor(tc) def showHelp(self): QMessageBox.information( self, "Information", "F6 -> play Station (from line where cursor is)\nF7 -> stop playing" ) def stopPlayer(self): self.player.stop() self.statusBar().showMessage("Player stopped", 0) ### QPlainTextEdit contextMenu def contextMenuRequested(self, point): cmenu = QMenu() if not self.field.toPlainText() == "": cmenu.addAction(self.getNameAction) cmenu.addAction(self.getUrlAction) cmenu.addAction(self.getNameAndUrlAction) cmenu.addSeparator() cmenu.addAction(self.getURLtoPlayAction) cmenu.addAction(self.stopPlayerAction) cmenu.addSeparator() cmenu.addAction(self.helpAction) cmenu.addAction(self.getForWebAction) cmenu.exec_(self.field.mapToGlobal(point)) def getURLtoPlay(self): url = "" tc = self.field.textCursor() rtext = tc.selectedText().partition(",")[2] stext = tc.selectedText().partition(",")[0] url = rtext print("stream url=", url) self.player.setMedia(QMediaContent(QUrl(url))) self.player.play() self.statusBar().showMessage("%s %s" % ("playing", stext), 0) def metaDataChanged(self): if self.player.isMetaDataAvailable(): trackInfo = (self.player.metaData("Title")) trackInfo2 = (self.player.metaData("Comment")) if not trackInfo == None: self.statusBar().showMessage(trackInfo, 0) if not trackInfo2 == None: self.statusBar().showMessage("%s %s" % (trackInfo, trackInfo2)) def findStations(self): self.field.setPlainText("") my_value = self.findfield.text() self.statusBar().showMessage("searching ...") base_url = "https://de1.api.radio-browser.info/xml/stations/byname/" url = f"{base_url}{my_value}" xml = requests.get(url).content.decode() if xml: root = ET.fromstring(xml) for child in root: ch_name = child.attrib["name"] ch_url = child.attrib["url"] self.field.appendPlainText(f"{ch_name},{ch_url}") self.copyToClipboard() tc = self.field.textCursor() tc.movePosition(QTextCursor.Start, QTextCursor.MoveAnchor) tc.select(QTextCursor.LineUnderCursor) tc.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor) self.field.setTextCursor(tc) else: self.statusBar().showMessage("nothing found", 0) self.field.verticalScrollBar().triggerAction( QScrollBar.SliderToMinimum) self.field.horizontalScrollBar().triggerAction( QScrollBar.SliderToMinimum) def saveStations(self): if not self.field.toPlainText() == "": path, _ = QFileDialog.getSaveFileName( None, "RadioStations", self.findfield.text() + ".txt", "Text Files (*.txt)") if path: s = self.field.toPlainText() with open(path, 'w') as f: f.write(s) f.close() self.statusBar().showMessage("saved!", 0) def savePlaylist(self): if not self.field.toPlainText() == "": path, _ = QFileDialog.getSaveFileName( None, "RadioStations", self.findfield.text() + ".m3u", "Playlist Files (*.m3u)") if path: result = "" s = self.field.toPlainText() st = [] for line in s.splitlines(): st.append(line) result += "#EXTM3U" result += '\n' for x in range(len(st)): result += "#EXTINF:" + str(x) + "," + st[x].partition( ",")[0] result += '\n' result += st[x].partition(",")[2] result += '\n' with open(path, 'w') as f: f.write(result) f.close() self.statusBar().showMessage("saved!", 0) def copyToClipboard(self): clip = QApplication.clipboard() if not self.field.toPlainText() == "": clip.setText(self.field.toPlainText())
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.webfile = f"{QFileInfo.path(QFileInfo(app.arguments()[0]))}/myradio.html" print(self.webfile) self.setGeometry(0, 0, 700, 800) self.setMaximumWidth(700) self.setContentsMargins(6, 6, 6, 6) self.setStyleSheet(myStyleSheet(self)) self.setWindowTitle("Radio Stations - searching with pyradios") self.genreList = genres.splitlines() self.findfield = QLineEdit() self.findfield.setFixedWidth(250) self.findfield.addAction(QIcon.fromTheme("edit-find"), 0) self.findfield.setPlaceholderText("type search term and press RETURN ") self.findfield.returnPressed.connect(self.findStations) self.findfield.setClearButtonEnabled(True) self.field = "" ### genre box self.combo = QComboBox() self.combo.currentIndexChanged.connect(self.comboSearch) self.combo.addItem("choose Genre") for m in self.genreList: self.combo.addItem(m) self.combo.addItem("Country") self.combo.setFixedWidth(150) ### toolbar ### self.tb = self.addToolBar("tools") self.tb.setContextMenuPolicy(Qt.PreventContextMenu) self.tb.setMovable(False) self.saveButton = QPushButton("Save as txt") self.saveButton.setIcon(QIcon.fromTheme("document-save")) self.saveButton.clicked.connect(self.saveStations) self.savePlaylistButton = QPushButton("Save as m3u") self.savePlaylistButton.setIcon(QIcon.fromTheme("document-save")) self.savePlaylistButton.clicked.connect(self.savePlaylist) self.tb.addWidget(self.findfield) self.tb.addWidget(self.saveButton) self.tb.addWidget(self.savePlaylistButton) self.tb.addSeparator() self.tb.addWidget(self.combo) self.statusBar().showMessage("Welcome", 0) self.view = QWebEngineView() if QFileInfo(self.webfile).exists: self.view.load(QUrl.fromLocalFile(self.webfile)) self.setCentralWidget(self.view) def comboSearch(self): if self.combo.currentIndex() > 0: self.findfield.setText(self.combo.currentText()) self.findStations() def findStations(self): html_content = html_top self.field = "" my_value = self.findfield.text() self.statusBar().showMessage("searching ...") base_url = "https://de1.api.radio-browser.info/xml/stations/byname/" url = f"{base_url}{my_value}" xml = requests.get(url).content.decode() if xml: root = ET.fromstring(xml) for child in root: ch_name = child.attrib["name"] ch_url = child.attrib["url"] self.field += (f"{ch_name},{ch_url}") self.field += '\n' # mysearch = self.findfield.text() # self.statusBar().showMessage("searching ...") # rb = RadioBrowser() # myparams = {'name': 'search', 'nameExact': 'false', 'bitrateMin': 64} # # for key in myparams.keys(): # if key == "name": # myparams[key] = mysearch # # r = rb.station_search(params=myparams) # # n = "" # m = "" # for i in range(len(r)): # for key,value in r[i].items(): # if str(key) == "name": # n = value.replace(",", " ") # if str(key) == "url_resolved": # m = value # if not n == "" and not m == "": # self.field += ("%s,%s" % (n, m.replace('\n', ''))) # self.field += '\n' # text = linesep.join([s for s in self.field.splitlines() if s]).splitlines() if not len(text) == 0: self.statusBar().showMessage("found " + str(len(text)) + " '" + self.findfield.text() + "' Stations") for line in text: ch = line.split(",") if len(ch) > 1: name = ch[0] url = ch[1] html_content += f"\t\t<li><a class='chlist' href='{url}'>{name}</a></li>" html_content += html_end with open(self.webfile, 'w') as f: f.write(html_content) f.close() self.view.load(QUrl.fromLocalFile(self.webfile)) else: self.statusBar().showMessage("nothing found", 0) def saveStations(self): if not self.field == "": path, _ = QFileDialog.getSaveFileName( None, "RadioStations", self.findfield.text() + ".txt", "Text Files (*.txt)") if path: s = self.field with open(path, 'w') as f: f.write(s) f.close() self.statusBar().showMessage("saved!", 0) def savePlaylist(self): if not self.field == "": path, _ = QFileDialog.getSaveFileName( None, "RadioStations", self.findfield.text() + ".m3u", "Playlist Files (*.m3u)") if path: result = "" s = self.field st = [] for line in s.splitlines(): st.append(line) result += "#EXTM3U" result += '\n' for x in range(len(st)): result += "#EXTINF:" + str(x) + "," + st[x].partition( ",")[0] result += '\n' result += st[x].partition(",")[2] result += '\n' with open(path, 'w') as f: f.write(result) f.close() self.statusBar().showMessage("saved!", 0)
class View(QWidget): send_data = pyqtSignal(object) baudrate_src_changed = pyqtSignal(object) baudrate_pump_changed = pyqtSignal(object) baudrate_temp_changed = pyqtSignal(object) #eol_changed = pyqtSignal(object) port_changed = pyqtSignal(object) seedPulseChanged = pyqtSignal(object) seedFreValueChanged = pyqtSignal(object) seedPulseFreChanged = pyqtSignal(object) firstPumpChanged = pyqtSignal(object) secondPumpChanged = pyqtSignal(object) startSrcModel = pyqtSignal(object) startPumpModel = pyqtSignal(object) startTempModel = pyqtSignal(object) beginTime = pyqtSignal(object) emitUsername = pyqtSignal(object) def __init__(self): super(QWidget,self).__init__() QWidget.__init__(self) self.queue = Queue() self.end_cmd = None self.autoscroll = True self.msg_sent = False self.timer = QTimer() self.timer.timeout.connect(self.update_gui) self.timer.start(100) self.srcModelstarted = False self.pumpModelstarted = False self.tempModelstarted = False self.currentValueList =list() self.currentTimeList = list() self.buttonMinimumWidth = 100 # self.topSeedCurrent = 700 # self.topPumpCurrent = 1000 self.canClosePort = True self.initSeedPulse = 0 self.initSeedFre = 0 self.init1stCurrent = 0 self.init2stCurrent = 0 self.initSeedCurrent =0 # get the lastsave record self.last = LastLog() self.lastpick = self.last.loadLast() uslast = self.lastpick.get('user',False) print('uslast',uslast) if uslast is False: self.user = User() else: self.user = uslast #init down machine status self.__init__slaveStatus() self.__initUI() def __init__slaveStatus(self): self.isSeedOpen = False self.seedcurrentre = False self.seedpulsere = False self.seedfrequecere = False self.seedcurrent = 0 self.seedpulse = 0 self.seedfrequece = 0 self.firstcurrent = 0 self.secondcurrent = 0 self.isFirstPumpOpen = False self.isSecondPumpOpen = False self.isLEDOpen = False def __initUI(self): '''main window box''' self.mainBox = QVBoxLayout(self)#使用垂直布局类 self.showBox = QHBoxLayout() self.setWindowState(Qt.WindowMaximized) ### #command area: push button, plain text edit and line edit ### cmd_btn = QPushButton('Send Command (ctrl+Q)') cmd_btn.setMinimumWidth(self.buttonMinimumWidth) cmd_btn.clicked.connect(self.emit_send_data) #import cmd strl+enter cmdEnterAction = QAction(self) cmdEnterAction.setShortcut('ctrl+Q') cmdEnterAction.setStatusTip(' press ctrl+Q to send command') cmdEnterAction.triggered.connect(self.emit_send_data) self.cmd_edit = QLineEdit() self.cmd_edit.addAction(cmdEnterAction) cmdBox = QVBoxLayout() #message box self.editer = QPlainTextEdit() self.editer.setReadOnly(True) # <<<<<<< HEAD self.editer.setMaximumSize(300,2000) # ======= cmdBox = QVBoxLayout() # cmdBox.addWidget(self.cmd_edit) # cmdBox.addWidget(cmd_btn) self.powerShow = PowerShow() cmdBox.addWidget(self.powerShow) # >>>>>>> a45e80ec77a4a8729fa4205165faae001fd09cab cmdBox.addWidget(self.editer) # cmd_btn.setMaximumSize(300,400) # self.cmd_edit.setMaximumSize(300,100) ### #paint area use matplotlib ### self.paintwidget = QWidget(self) self.painter = MyDynamicMplCanvas(self.paintwidget, width=5, height=4, dpi=100) # self.showBox.addLayout(self.powerShowUI()) self.showBox.addLayout(cmdBox) self.showBox.addWidget(self.painter) self.toolBoxUI() self.mainBox.addWidget(self.toolBox) self.mainBox.addLayout(self.showBox) self.setLayout(self.mainBox) self.setWindowTitle("光子暗化平台软件") def toolBoxUI(self): '''use a tab widget to organize set area ''' ### #QTabWidget() layout ### gbox1 = QGroupBox() gbox1.setStyleSheet("QGroupBox{border:None;}") self.useBox = QHBoxLayout(gbox1) self.useBox.setGeometry(QRect( 0, 0, 300,100)) gbox2 = QGroupBox() gbox2.setStyleSheet("QGroupBox{border:None;}") self.portUI = PortGBUI() self.portUI.setupUi(gbox2) # self.portUI.widget.setGeometry(QRect( 0, 0, 450,200)) gbox3 = QGroupBox() gbox3.setStyleSheet("QGroupBox{border:None;}") self.pumpUI = PumpUI() self.pumpUI.setupUi(gbox3) self.pumpUI.groupBox.setTitle(' ') # self.pumpUI.widget.setGeometry(QRect( 0, 0, 400,200)) gbox4 = QGroupBox() gbox4.setStyleSheet("QGroupBox{border:None;}") gbox5 = QGroupBox() gbox5.setStyleSheet("QGroupBox{border:None;}") #self.menuBox = QHBoxLayout() # self.setBox = QHBoxLayout(gbox2) self.pumpBox = QGridLayout(gbox3) self.powerRecordBox = QHBoxLayout(gbox4) self.toolBox = QTabWidget() # self.toolBox.setStyleSheet("QTabWidget.pane{background: transparent;}\ # ") self.toolBox.addTab(gbox1,'用户登录') self.toolBox.addTab(gbox2,'串口设置') self.toolBox.addTab(gbox3,'泵浦开关') self.toolBox.addTab(gbox4,'功率计') self.toolBox.addTab(gbox5,'帮助') # self.toolBox. self.toolBox.setTabEnabled(1,False) self.toolBox.setTabEnabled(2,False) self.toolBox.setTabEnabled(3,False) self.toolBox.setMaximumSize(10000,200) # self.toolBox.resize(1200,200) userbox = UserView() userbox.usersignal.connect(self.setUser) self.useBox.addWidget(userbox) # self.useBox.addStretch() self.powerRecord = PowerRecord() self.powerRecord.getNowFig(self.painter) self.powerRecord.timeStateSignal.connect(self.painter.getLogTimeState) self.powerRecord.logStateSignal.connect(self.painter.getStartLog) self.powerRecord.plotlist.connect(self.painter.XYaxitList) self.powerRecordBox.addWidget(self.powerRecord) # #port set # menuItem = ['300 baud','1200 baud', '2400 baud','4800 baud','9600 baud', '19200 baud','38400 baud','57600 baud', '115200 baud','230400 baud','250000 baud'] self.portUI.baundrateSource.addItems(menuItem) self.portUI.baundratePump.addItems(menuItem) # self.portUI.baundrateTemp.addItems(menuItem) #source port set #source portItem = ['com1','com2','com3','com4', 'com5','com6','com7','com8','com9', 'com10','com11','com12','com13', 'com14','com15','com16','com17', 'com18','com19','com20'] self.portUI.portSource.addItems(portItem) self.portUI.portPump.addItems(portItem) self.setPortButton = self.portUI.openportSource self.closePortButton = self.portUI.closeportSource self.baundrateMenu = self.portUI.baundrateSource self.portEdit = self.portUI.portSource self.baundrateMenu.currentIndexChanged.connect(self.emit_br_src_changed) baudindex = self.lastpick.get('srcBaud',False) if baudindex is not False : self.baundrateMenu.setCurrentIndex(baudindex) else: self.baundrateMenu.setCurrentIndex(4) portindex = self.lastpick.get('srcPort',False) if baudindex is not False : self.portEdit.setCurrentIndex(portindex) else: self.portEdit.setCurrentIndex(1) baudindex = self.lastpick.get('pumpBaud',False) if baudindex is not False : self.portUI.baundratePump.setCurrentIndex(baudindex) else: self.portUI.baundratePump.setCurrentIndex(4) portindex = self.lastpick.get('pumpPort',False) if baudindex is not False : self.portUI.portPump.setCurrentIndex(portindex) else: self.portUI.portPump.setCurrentIndex(2) ### #pump set ### self.openSeedButton = self.pumpUI.sourceSet self.setSeedPulse = self.pumpUI.pulseSpin self.openSeedButton.clicked.connect(self.emitSeedPulseAndFre) self.setSeedPulse.setValue(self.initSeedPulse) self.setSeedFreValue = self.pumpUI.frequencySpin self.setSeedCurrent = self.pumpUI.currentSpin self.setSeedCurrent.setValue(self.initSeedCurrent) self.openAll = self.pumpUI.sourceOpen self.sendfirst = self.pumpUI.firstPumpSet self.sendfirst.clicked.connect(self.emitFirstPumpCurrent) self.sendsecond = self.pumpUI.secondPumpSet self.sendsecond.clicked.connect(self.emitSecondPumpCurrent) self.setFirstpump = self.pumpUI.firstpumpSpin self.setFirstpump.setValue(self.init1stCurrent) self.setSecondpump = self.pumpUI.secondpumpSpin self.setSecondpump.setValue(self.init2stCurrent) self.closeAll = self.pumpUI.sourceClose self.pumpUI.firstpumpSpin.setMaximum(1000) self.pumpUI.secondpumpSpin.setMaximum(10000) self.pumpUI.secondpumpSpin.setSingleStep(500) def enableClosePort(self): if self.setSeedPulse.text()[:-2] > self.initSeedPulse : self.canClosePort = False print(self.canClosePort) if self.setSeedFreValue.texttext()[:-3] > self.initSeedFre : self.canClosePort = False print(self.canClosePort) if self.setSeedCurrent.text()[:-2] > self.initSeedCurrent: self.canClosePort = False print(self.canClosePort) if self.setFirstpump.text()[:-2] > self.init1stCurrent : self.canClosePort = False print(self.canClosePort) if self.setSecondpump.text()[:-2] > self.init2stCurrent : self.canClosePort = False print(self.canClosePort) def seedSignalSet(self, seedcurrent, seedpulse, seedfrequece): self.seedcurrent = seedcurrent self.setSeedCurrent.setValue(self.seedcurrent) self.seedpulse = seedpulse self.setSeedPulse.setValue(self.seedpulse) self.seedfrequece = seedfrequece self.setSeedFreValue.setValue(self.seedfrequece) def firstCurrentSet(self,value): self.firstcurrent = value self.setFirstpump.setValue(self.firstcurrent) def secondCurrentSet(self,value): self.secondcurrent = value self.setSecondpump.setValue(self.secondcurrent) #============================================================================== # Get, set #============================================================================== def setPowerShowList(self,lst): self.powerShow.powerList = lst self.powerShow.updateFigure() def set_queue(self, queue): self.queue = queue def set_end_cmd(self, end_cmd): self.end_cmd = end_cmd # def set_autoscroll(self, value): # self.autoscroll = value def set_port(self, value): self.portEdit.clear() self.portEdit.insert(value) def getSrcPort(self): self.lastpick['srcPort'] = self.portEdit.currentIndex() return self.portEdit.currentText() def getSrcBaudrate(self): self.lastpick['srcBaud'] = self.baundrateMenu.currentIndex() return self.baundrateMenu.currentText()[:-5] def getPumpPort(self): self.lastpick['pumpPort'] = self.portUI.portPump.currentIndex() return self.portUI.portPump.currentText() def getPumpBaudrate(self): self.lastpick['pumpBaud'] = self.portUI.baundratePump.currentIndex() return self.portUI.baundratePump.currentText()[:-5] def get_cmd(self): return self.cmd_edit.text() def setCurrentValue(self, currentValue,timeValue): if currentValue is not None: self.currentValueList = currentValue self.currentTimeList = timeValue def Button2Plot(self): self.painter.update_figure() def closeEvent(self, event): self.last.saveLast(self.lastpick) self.end_cmd() QWidget.closeEvent(self, event) print('exit') def beginGui(self): self.update() def update_gui(self): self.process_incoming() self.update() def updataFigure(self,newtime,power): # self.setCurrentValue(currentValue, timeValue) self.painter.XYaxit(newtime,power) self.painter.update_figure() # print('update?') # self.update() def process_incoming(self): while self.queue.qsize(): try: msg = self.queue.get(0) self.editer.appendPlainText(str(msg)) #show to the textplain? #if self.autoscroll: self.editer.ensureCursorVisible() self.scroll_down() except Queue.empty: print('=== empty queue ===') def scroll_down(self): sb = self.editer.verticalScrollBar() sb.setValue(sb.maximum()) def changePort(self): if not self.msg_sent: self.msg_sent = True self.emit_port_changed() else: self.msg_sent = False return None #============================================================================== # Signals #============================================================================== def emit_send_data(self): self.send_data.emit(self.get_cmd()) self.cmd_edit.clear() def emit_send_command(self,command): self.send_data.emit(command) self.cmd_edit.clear() def emit_br_src_changed(self, value): baudrate = self.baundrateMenu.itemText(value)[:-5] self.baudrate_src_changed.emit(baudrate) def emit_br_pump_changed(self, value): baudrate = self.baundrateMenu.itemText(value)[:-5] self.baudrate_pump_changed.emit(baudrate) # def emit_br_temp_changed(self, value): # baudrate = self.baundrateMenu.itemText(value)[:-5] # self.baudrate_temp_changed.emit(baudrate) def emit_port_changed(self): self.port_changed.emit(self.portEdit.text()) self.portEdit.clear() def emitWriteSeedPulse(self): self.seedPulseChanged.emit(self.setSeedPulse.text()[:-2]) def emitWriteSeedFre(self): self.seedFreValueChanged.emit(self.setSeedFreValue.text()[:-3]) def emitFirstPumpCurrent(self): self.firstPumpChanged.emit(self.setFirstpump.text()[:-2]) def emitSecondPumpCurrent(self): self.secondPumpChanged.emit(self.setSecondpump.text()[:-2]) def emitSeedPulseAndFre(self): seedPulseAndFre = [self.setSeedPulse.text()[:-2], self.setSeedFreValue.text()[:-3],self.setSeedCurrent.text()[:-2]] # print(self.setSeedPulse.text()[:-2], # self.setSeedFreValue.text()[:-2],self.setSeedCurrent.text()[:-2]) self.seedPulseFreChanged.emit(seedPulseAndFre) def setUser(self,value): self.user = value if value.getName() is not False: self.toolBox.setTabEnabled(1,True) self.toolBox.setTabEnabled(2,True) self.toolBox.setTabEnabled(3,True) self.powerRecord.setUserID(self.user.getName()) self.startSrcModel.emit(self.srcModelstarted) self.srcModelstarted = True self.startPumpModel.emit(self.pumpModelstarted) self.pumpModelstarted = True # self.startTempModel.emit(self.tempModelstarted) # self.tempModelstarted = True self.emitUsername.emit(self.user.getName()) print('emit username:'******'NoneUser') print('use in view:',self.user.getName()) def lastLogSave(self): self.last.saveLast(self.lastpick)
class SearchPanel(QWidget): searched = pyqtSignal(str, QWebEnginePage.FindFlag) def __init__(self, parent=None): """ Args: parent: """ super(SearchPanel, self).__init__(parent) self.setContentsMargins(0, 0, 0, 0) self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) fh = QFile( '/home/alexandr/PycharmProjects/Pocket/pocket_articles/css/searchpanel.qss' ) # fh = QFile(':/css/searchpanel.qss') if fh.open(QIODevice.ReadOnly): self.setStyleSheet(fh.readAll().data().decode()) # self.setStyleSheet(_QSS) hbox = QHBoxLayout(self) hbox.setContentsMargins(0, 0, 0, 0) icon_close = QIcon( QPixmap(':/images/window-close.png').scaledToWidth(16)) icon_back = QIcon(':/images/back.png') icon_forward = QIcon(':/images/forward.png') self.nextBtn = QPushButton(icon_forward, 'Следующее') self.nextBtn.clicked.connect(self.search) self.nextBtn.setFixedHeight(20) self.prevBtn = QPushButton(icon_back, 'Предыдущее') self.prevBtn.clicked.connect( lambda: self.search(QWebEnginePage.FindBackward)) self.prevBtn.setFixedHeight(20) self.caseSensitively = QCheckBox('Учитывать регистр') self.search_le = QLineEdit() self.search_le.addAction(QIcon(':/images/search-50.svg'), QLineEdit.LeadingPosition) self.search_le.setClearButtonEnabled(True) self.closeBtn = QPushButton(icon_close, '') self.closeBtn.clicked.connect(self.hide_widget) self.closeBtn.setFixedHeight(20) hbox.addStretch(1) hbox.addWidget(self.closeBtn) hbox.addWidget(self.search_le, 1) hbox.addWidget(self.prevBtn) hbox.addWidget(self.nextBtn) hbox.addWidget(self.caseSensitively) QShortcut(Qt.Key_Escape, self, self.hide_widget) QShortcut(Qt.Key_F3, self, self.search) QShortcut(QKeySequence.FindNext, self, self.search) QShortcut(QKeySequence.FindPrevious, self, lambda: self.search(QWebEnginePage.FindBackward)) QShortcut(QKeySequence(Qt.SHIFT + Qt.Key_F3), self, lambda: self.search(QWebEnginePage.FindBackward)) # ставим фокус на строку ввода self.setFocusProxy(self.search_le) self.search_le.returnPressed.connect(self.search) self.search_le.textChanged.connect(self.search) @pyqtSlot() def hide_widget(self): self.search_le.clear() self.hide() @pyqtSlot() def search(self, flag: QWebEnginePage.FindFlag = None): """ Args: flag (QWebEnginePage.FindFlag): """ if not flag: flag = QWebEnginePage.FindFlag() if self.caseSensitively.isChecked(): flag |= QWebEnginePage.FindCaseSensitively self.searched.emit(self.search_le.text(), flag) def showEvent(self, a0: QShowEvent) -> None: """ Args: a0 (QShowEvent): """ super(SearchPanel, self).showEvent(a0) self.setFocus(Qt.ShortcutFocusReason)
class SideDock(QDockWidget): """ Side Dock/Panel, named "Navy Base Overview", displays all important data of the user. This is the first coded QWidget of WGViewer (even before LoginForm). """ sig_resized = pyqtSignal() sig_closed = pyqtSignal() def __init__(self, parent, realrun: bool): super(SideDock, self).__init__(parent) self.is_realrun = realrun _, self.user_screen_h = wgv_utils.get_user_resolution() self.qsettings = QSettings(wgv_data.get_qsettings_file(), QSettings.IniFormat) if self.qsettings.contains(QKEYS.EXP_AUTO) and self.qsettings.value(QKEYS.EXP_AUTO, type=bool): logger.debug("Auto expedition is on") self.is_exp_auto = True else: logger.debug("Auto expedition is off") self.is_exp_auto = False self.equipment_names = wgv_data.get_shipEquipmnt() self.ship_names = wgv_data.get_processed_userShipVo() # index 0 for daily, 1 for weekly, 2+ for tasks/events self.task_counter_desc_labels = [] self.task_counter_labels = [] self.task_counter_timers = [] self.task_counters = [] self.name_layout_widget = QWidget(self) self.name_layout = QHBoxLayout(self.name_layout_widget) self.name_label = QLabel(self.name_layout_widget) self.lvl_label = QLabel(self.name_layout_widget) self.ship_count_label = QLabel(self.name_layout_widget) self.equip_count_label = QLabel(self.name_layout_widget) self.collect_count_label = QLabel(self.name_layout_widget) self.sign_widget = QLineEdit(self) self.table_model = ResourceTableModel() self.table_view = QTableView(self) self.bath_list_view = BathListView() self.bath_list_view_widget = QWidget(self) self.bath_list_view_layout = QVBoxLayout(self.bath_list_view_widget) self.triple_list_view_widget = QWidget(self) self.triple_list_view = QHBoxLayout(self.triple_list_view_widget) self.build_list_view = BuildListView() self.dev_list_view = DevListView() self.exp_list_view = ExpListView(parent.main_tabs) self.task_list_view = TaskListView() self.task_panel_widget = QWidget(self) self.task_panel_view = QHBoxLayout(self.task_panel_widget) self.countdowns_layout_widget = QWidget(self) self.countdowns_layout = QVBoxLayout(self.countdowns_layout_widget) self.sig_resized.connect(self.update_geometry) self.sig_closed.connect(parent.on_dock_closed) self._init_ui() self.set_data() def set_data(self) -> None: d = wgv_data.get_api_initGame() self.on_received_lists(d) self.on_received_resource(d) self.on_received_name(d) self.on_received_tasks(d) def _init_ui(self) -> None: self.setFloating(False) self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.setMinimumWidth(int(0.4 * self.user_screen_h)) self.setWindowTitle("Navy Base Overview") self._init_name_info() self._init_sign_info() self._init_resource_info() self._init_bath_info() self._init_triple_list() self._init_task_panel() def _init_name_info(self) -> None: self.name_layout.setContentsMargins(0, 0, 0, 0) self.name_layout.addWidget(self.name_label) self.name_layout.addWidget(self.lvl_label) self.name_layout.addWidget(self.ship_count_label) self.name_layout.addWidget(self.equip_count_label) self.name_layout.addWidget(self.collect_count_label) def _init_sign_info(self) -> None: icon_path = get_data_path('assets/icons/sign_16.png') self.sign_widget.addAction(QIcon(icon_path), QLineEdit.LeadingPosition) def _init_resource_info(self) -> None: self.table_view.setModel(self.table_model) x = 0.03 * self.user_screen_h self.table_view.setIconSize(QSize(x, x)) self.table_view.verticalHeader().hide() self.table_view.horizontalHeader().hide() self.table_view.setShowGrid(False) self.table_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.table_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.table_view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table_view.setFocusPolicy(Qt.NoFocus) self.table_view.setSelectionMode(QAbstractItemView.NoSelection) self.table_view.horizontalScrollBar().setEnabled(False) self.table_view.verticalScrollBar().setEnabled(False) def _init_bath_info(self) -> None: self.bath_list_view_layout.setContentsMargins(0, 0, 0, 0) self.bath_list_view_layout.addWidget(self.bath_list_view) def _init_triple_list(self) -> None: self.triple_list_view.setContentsMargins(0, 0, 0, 0) self.triple_list_view.addWidget(self.build_list_view) self.triple_list_view.addWidget(self.dev_list_view) self.triple_list_view.addWidget(self.exp_list_view) def _init_task_panel(self) -> None: self.task_panel_view.setContentsMargins(0, 0, 0, 0) self._init_countdowns() self.task_panel_view.addWidget(self.task_list_view) self.task_panel_view.addWidget(self.countdowns_layout_widget) def _init_countdowns(self) -> None: # TODO? design problem now the most suitable count is 4, 5 would be max # although MoeFantasy opens mostly 1 event at a time, rarely 2. self.countdowns_layout.setContentsMargins(0, 0, 0, 0) l1 = QLabel(self.countdowns_layout_widget) l1.setToolTip("Refreshing daily at 0300 UTC+8") # Intel' server also use CN time l1.setText("Next daily:") l1.adjustSize() self.task_counter_desc_labels.append(l1) l2 = QLabel(self.countdowns_layout_widget) l2.setText("Next weekly:") l2.setToolTip("Refreshing weekly at 0400 UTC+8 or New Year") l2.adjustSize() self.task_counter_desc_labels.append(l2) self.task_counter_labels.append(QLabel(self.countdowns_layout_widget)) self.task_counter_labels.append(QLabel(self.countdowns_layout_widget)) self.countdowns_layout.addWidget(l1) self.countdowns_layout.addWidget(self.task_counter_labels[0]) self.countdowns_layout.addWidget(l2) self.countdowns_layout.addWidget(self.task_counter_labels[1]) _, _, d_counter, w_counter = get_tasks_countdowns() self.task_counters.append(d_counter) self.task_counters.append(w_counter) self._init_task_counters() # ================================ # Getter / Setter # ================================ def add_task_countdown(self, text: str, _time: int, idx: int) -> None: l1 = QLabel(self.countdowns_layout_widget) l1.setText(text) l1.adjustSize() self.task_counter_desc_labels.append(l1) self.countdowns_layout.addWidget(l1) l2 = QLabel(self.countdowns_layout_widget) self.task_counter_labels.append(l2) self.task_counters.append(_time) self.countdowns_layout.addWidget(l2) self.start_new_timer(self.task_counters, self.task_counter_labels, self.task_counter_timers, idx) def get_ship_name(self, _id): return self.ship_names[str(_id)]['Name'] def get_equip_name(self, cid: int) -> str: return next((i for i in self.equipment_names if i['cid'] == cid), {'title': '?'})['title'] @staticmethod def get_ship_type(_id: int) -> str: return wgv_utils.get_build_type(_id) @staticmethod def _remove_widget(parent, widget: [QLayout, QWidget]) -> None: logger.warning("Deleting widget") parent.removeWidget(widget) widget.deleteLater() widget = None return def get_exp_list_view(self) -> ExpListView: return self.exp_list_view # ================================ # Timer Related # ================================ def count_down(self, counters: list, labels: list, timers: list, idx: int) -> None: # TODO? refactor; each list view has its own countdown method? counters[idx] -= 1 if counters[idx] > 0: pass else: if counters == self.task_counters: if idx < 2: # refreshing daily/weekly timers _, _, d, w = get_tasks_countdowns() counters[0] = d counters[1] = w else: counters[idx] = 0 timers[idx].stop() self._remove_widget(self.countdowns_layout, labels[idx]) self._remove_widget(self.countdowns_layout, self.task_counter_desc_labels[idx]) return elif counters == self.bath_list_view.get_counters(): counters[idx] = 0 timers[idx].stop() self.bath_list_view.update_item(idx, 0, "Repairing Dock Unused") self.bath_list_view.update_item(idx, 1, "--:--:--") elif counters == self.exp_list_view.get_counters(): counters[idx] = 0 timers[idx].stop() # To avoid "Idling" (uninitialized) issue labels[idx].setText(str(timedelta(seconds=counters[idx]))) if self.is_realrun and self.is_exp_auto: self.exp_list_view.auto_restart(idx) else: # otherwise will cause problem pass else: counters[idx] = 0 timers[idx].stop() labels[idx].setText(str(timedelta(seconds=counters[idx]))) def start_new_timer(self, counters: list, labels: list, timers: list, idx: int) -> None: """ Creates a QTimer() object and auto connects to 1 sec count down. Then auto start """ tr = QTimer() tr.setInterval(1000) tr.timeout.connect(lambda: self.count_down(counters, labels, timers, idx)) if counters == self.task_counters: timers.append(tr) else: timers[idx] = tr tr.start() def _init_task_counters(self) -> None: self.start_new_timer(self.task_counters, self.task_counter_labels, self.task_counter_timers, 0) self.start_new_timer(self.task_counters, self.task_counter_labels, self.task_counter_timers, 1) def _process_timer_data(self, _data, view, func, item_id, counters, labels, timers) -> None: for i, v in enumerate(_data): if v["locked"] == 0: if "endTime" in v: _left_time = _calc_left_time(v["endTime"]) counters[i] = _left_time self.start_new_timer(counters, labels, timers, i) val1 = func(v[item_id]) view.update_item(i, 0, val1) else: view.update_item(i, 0, "Unused") view.update_item(i, 1, "--:--:--") else: pass # ================================ # Signals # ================================ @pyqtSlot(dict) def on_received_resource(self, data: dict) -> None: if data is not None: def _get_item_by_id(item_id: int) -> int: return next((i for i in x if i["itemCid"] == item_id), {"num": 0})["num"] u = data["userVo"] x = data["packageVo"] self.table_model.update_fuel(u["oil"]) self.table_model.update_ammo(u["ammo"]) self.table_model.update_steel(u["steel"]) self.table_model.update_bauxite(u["aluminium"]) self.table_model.update_gold(u["gold"]) self.table_model.update_repair(_get_item_by_id(541)) self.table_model.update_build(_get_item_by_id(141)) self.table_model.update_bp_construct(_get_item_by_id(241)) self.table_model.update_bp_dev(_get_item_by_id(741)) self.table_model.update_revive(_get_item_by_id(66641)) self.table_model.update_DD(_get_item_by_id(10441)) self.table_model.update_CA(_get_item_by_id(10341)) self.table_model.update_BB(_get_item_by_id(10241)) self.table_model.update_CV(_get_item_by_id(10141)) self.table_model.update_SS(_get_item_by_id(10541)) self.table_model.write_csv() @pyqtSlot(dict) def update_lvl_label(self, x: dict) -> None: # userLevelVo if x is not None: self.lvl_label.setText("Lv. " + str(x["level"])) lvl_tooltip = str(x["exp"]) + " / " + str(x["nextLevelExpNeed"]) self.lvl_label.setToolTip(lvl_tooltip) @pyqtSlot(dict) def on_received_name(self, data: dict) -> None: if data is not None: x = data["userVo"]["detailInfo"] self.name_label.setText(x["username"]) name_tooltip = "resource soft cap = " + str(data["userVo"]["resourcesTops"][0]) self.name_label.setToolTip(name_tooltip) self.update_lvl_label(x) ship_icon = get_data_path('assets/icons/ship_16.png') ship_str = f"<html><img src='{ship_icon}'></html> " + str(x["shipNum"]) + " / " + str(x["shipNumTop"]) self.ship_count_label.setText(ship_str) equip_icon = get_data_path('assets/icons/equip_16.png') equip_str = f"<html><img src='{equip_icon}'></html> " + str(x["equipmentNum"]) + " / " + str(x["equipmentNumTop"]) self.equip_count_label.setText(equip_str) collect_icon = get_data_path('assets/icons/collect_16.png') collect_str = f"<html><img src='{collect_icon}'></html> " + str(len(data["unlockShip"])) + " / " + str(x["basicShipNum"]) self.collect_count_label.setText(collect_str) self.sign_widget.setText(data["friendVo"]["sign"]) def update_one_expedition(self, data: dict) -> None: # Input = pveExploreVo['levels'][_idx] _idx = int(data['fleetId'])-5 _exp_counters = self.exp_list_view.get_counters() _exp_counters[_idx] = _calc_left_time(data["endTime"]) self.start_new_timer(_exp_counters, self.exp_list_view.get_counter_labels(), self.exp_list_view.get_counter_timers(), _idx) n = "Fleet #" + data["fleetId"] + " " + data["exploreId"].replace("000", "-") self.exp_list_view.update_item(_idx, 0, n) def cancel_one_expedition(self, fleet_idx: int) -> None: self.exp_list_view.update_item(fleet_idx, 0, EXP_LABEL_L) self.exp_list_view.update_item(fleet_idx, 1, EXP_LABEL_R) self.exp_list_view.get_counters()[fleet_idx] = 0 self.exp_list_view.get_counter_timers()[fleet_idx].stop() def update_expeditions(self, data: dict) -> None: if data is not None: p = sorted(data["levels"], key=lambda x: int(x['fleetId']), reverse=False) for _, val in enumerate(p): self.update_one_expedition(val) @pyqtSlot(dict) def on_received_lists(self, data: dict) -> None: if data is not None: self._process_timer_data(data["repairDockVo"], self.bath_list_view, self.get_ship_name, "shipId", self.bath_list_view.get_counters(), self.bath_list_view.get_counter_labels(), self.bath_list_view.get_counter_timers()) self._process_timer_data(data["dockVo"], self.build_list_view, self.get_ship_type, "shipType", self.build_list_view.get_counters(), self.build_list_view.get_counter_labels(), self.build_list_view.get_counter_timers()) self._process_timer_data(data["equipmentDockVo"], self.dev_list_view, self.get_equip_name, "equipmentCid", self.dev_list_view.get_counters(), self.bath_list_view.get_counter_labels(), self.dev_list_view.get_counter_timers()) self.update_expeditions(data["pveExploreVo"]) @pyqtSlot(dict) def on_received_tasks(self, data: dict) -> None: if data is not None: t = data["taskVo"] for i in t: stat = str(i["condition"][0]["finishedAmount"]) + " / " + str(i["condition"][0]["totalAmount"]) desc = wgv_utils.clear_desc(i["desc"]) if '#' in desc: # TODO: (lowest priority) how to find `#s10030711#n` ? looks like not the same ID in docks desc = re.sub(r'\[[^]]*\]', i["title"], desc) else: pass if i['end_time'] != "": desc += "\nEvent End On: " + i['end_time'] lim_flag = True else: lim_flag = False prefix = TASK_TYPE[i['type']] title = f"{prefix}\t{i['title']}" self.task_list_view.add_item(title, stat, desc, lim_flag) m = data["marketingData"]["activeList"] for i in m: self.add_task_countdown(i["title"], i["left_time"], len(self.task_counters)) # ================================ # Events # ================================ def resizeEvent(self, event: QResizeEvent) -> None: # overriding resizeEvent() method self.sig_resized.emit() return super(SideDock, self).resizeEvent(event) def closeEvent(self, event: QCloseEvent) -> None: cb = QCheckBox('show on start-up') if self.qsettings.contains(QKEYS.UI_SIDEDOCK) is True: cb.setChecked(self.qsettings.value(QKEYS.UI_SIDEDOCK, type=bool) is True) else: pass box = QMessageBox(QMessageBox.Question, "INFO", "Do you want to close side dock?\n(Can re-open in View menu)", QMessageBox.Yes | QMessageBox.No, self) box.setStyleSheet(wgv_utils.get_color_scheme()) box.setDefaultButton(QMessageBox.No) box.setCheckBox(cb) if box.exec() == QMessageBox.Yes: event.accept() self.sig_closed.emit() else: event.ignore() self.qsettings.setValue(QKEYS.UI_SIDEDOCK, cb.isChecked()) def update_geometry(self) -> None: y = int(0.03 * self.user_screen_h) h = int(0.05 * self.user_screen_h) gap = int(0.01 * self.user_screen_h) self.name_layout_widget.setGeometry(0, y, self.geometry().width(), h) self.sign_widget.setGeometry(0, y + h, self.geometry().width(), y) y = int(2 * y + h + gap) h = int(0.09 * self.user_screen_h) self.table_view.setGeometry(0, y, self.geometry().width(), h) for i in range(5): self.table_view.setColumnWidth(i, self.geometry().width() / 5) for i in range(3): self.table_view.setRowHeight(i, h / 3) y = y + h + gap self.bath_list_view_widget.setGeometry(0, y, self.geometry().width(), h) y = y + h + gap self.triple_list_view_widget.setGeometry(0, y, self.geometry().width(), h) y = y + h + gap h = int(0.19 * self.user_screen_h) self.task_panel_widget.setGeometry(0, y, self.geometry().width(), h)
class InitialPage(QWizardPage): def __init__(self): super().__init__() vbox = QVBoxLayout(self) frame = QFrame(self) vbox.addStretch(1) frame.setFrameShape(QFrame.StyledPanel) vbox.addWidget(frame) # Fields fields_box = QGridLayout(frame) # Project name fields_box.addWidget(QLabel(translations.TR_WIZARD_PROJECT_NAME), 0, 0) self._line_project_name = QLineEdit("untitled") self.registerField("name*", self._line_project_name) fields_box.addWidget(self._line_project_name, 0, 1) # Project location fields_box.addWidget(QLabel(translations.TR_WIZARD_PROJECT_LOCATION), 1, 0) self._line_location = QLineEdit() self._line_location.setReadOnly(True) self._line_location.setText(utils.get_home_dir()) self.registerField("path", self._line_location) choose_dir_act = self._line_location.addAction( self.style().standardIcon(self.style().SP_DirIcon), QLineEdit.TrailingPosition) fields_box.addWidget(self._line_location, 1, 1) # Project description fields_box.addWidget(QLabel(translations.TR_PROJECT_DESCRIPTION), 2, 0) self._txt_desciption = QPlainTextEdit() fields_box.addWidget(self._txt_desciption, 2, 1) self.registerField("description", self._txt_desciption) # Project license fields_box.addWidget(QLabel(translations.TR_PROJECT_LICENSE), 3, 0) combo_license = QComboBox() combo_license.addItems(LICENSES) combo_license.setCurrentIndex(12) fields_box.addWidget(combo_license, 3, 1) self.registerField("license", combo_license, property="currentText") # Project interpreter fields_box.addWidget( QLabel(translations.TR_WIZARD_PROJECT_INTERPRETER), 4, 0) combo_interpreter = QComboBox() combo_interpreter.addItems(utils.get_python()) combo_interpreter.setCurrentText(sys.executable) fields_box.addWidget(combo_interpreter, 4, 1) self.registerField("interpreter", combo_interpreter) # Connections self._line_project_name.textChanged.connect(self._on_text_changed) choose_dir_act.triggered.connect(self._choose_dir) def _choose_dir(self): dirname = QFileDialog.getExistingDirectory( self, translations.TR_WIZARD_CHOOSE_DIR, utils.get_home_dir()) if dirname: self._line_location.setText(dirname) @property def location(self): return self._line_location.text() @property def project_name(self): return self._line_project_name.text() def _on_text_changed(self): ok = self.validate() if not ok: self._line_project_name.setStyleSheet("background-color: red") else: self._line_project_name.setStyleSheet("background-color: none;") def validate(self): ok = True project_path = os.path.join(self.location, self.project_name) if file_manager.folder_exists(project_path): ok = False return ok def isComplete(self): val = super().isComplete() return val and self.validate()
class MainWindow(CenterWindow): """ Displays list with tasks assigned to current user in JIRA """ def __init__(self, controller): super().__init__() self.setStyleSheet(QSS) self.controller = controller self.resize(1000, 600) self.setWindowTitle('JIRA Quick Reporter') self.setWindowIcon(QIcon(LOGO_PATH)) self.center() self.current_item = None self.vbox = QVBoxLayout() self.save_btn_box = QHBoxLayout() self.filter_name_label = QLabel() self.filter_name_label.setObjectName('filter_name_label') self.filter_name_label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.filter_name_label.setAlignment(Qt.AlignLeft) self.filter_edited_label = QLabel('-> edited') self.filter_edited_label.setObjectName('filter_edited_label') self.filter_edited_label.hide() self.filter_edited_label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.save_filter_btn = QPushButton('Save as') self.save_filter_btn.setObjectName('save_filter_btn') self.save_filter_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.save_filter_btn.clicked.connect(self.controller.save_filter) self.overwrite_filter_button = QPushButton('Save') self.overwrite_filter_button.setToolTip('You need to edit filter query first') self.overwrite_filter_button.setObjectName('save_filter_btn') self.overwrite_filter_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.overwrite_filter_button.clicked.connect(lambda: self.controller.save_filter(True)) self.delete_filter_btn = QPushButton() self.delete_filter_btn.setObjectName('delete_filter_btn') self.delete_filter_btn.clicked.connect(self.delete_filter) self.delete_filter_btn.setIcon(QIcon(DELETE_FILTER_ICON)) self.delete_filter_btn.setIconSize( QSize( self.delete_filter_btn.sizeHint().height(), self.delete_filter_btn.sizeHint().height() ) ) self.delete_filter_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.delete_filter_btn.setToolTip('Delete filter') self.save_btn_box.addWidget(self.filter_name_label, Qt.AlignLeft) self.save_btn_box.addWidget(self.filter_edited_label, Qt.AlignLeft) self.save_btn_box.addWidget(self.save_filter_btn, Qt.AlignLeft) self.save_btn_box.addWidget(self.overwrite_filter_button, Qt.AlignLeft) self.save_btn_box.addStretch() self.save_btn_box.addWidget(self.delete_filter_btn, Qt.AlignRight) self.create_filter_box = QHBoxLayout() self.query_field = QLineEdit() self.query_field.setObjectName('query_field') self.query_field.setPlaceholderText('You need to write a query here') self.action_help = QAction() self.action_help.setIcon(self.style().standardIcon(QStyle.SP_MessageBoxQuestion)) self.help_filter_url = QUrl(FILTER_FIELD_HELP_URL) self.action_help.triggered.connect(self.filter_field_help) self.query_field.addAction(self.action_help, QLineEdit.TrailingPosition) self.query_field.installEventFilter(self) self.search_issues_button = QPushButton('Search') self.search_issues_button.setObjectName('search_issues_button') self.search_issues_button.clicked.connect(self.controller.search_issues_by_query) self.create_filter_box.addWidget(self.query_field) self.create_filter_box.addWidget(self.search_issues_button) self.list_box = QVBoxLayout() self.issue_list_widget = QListWidget() self.issue_list_widget.setObjectName('issue_list') self.label_info = QLabel('You have no issues.') self.label_info.setAlignment(Qt.AlignCenter) self.list_box.addWidget(self.issue_list_widget) self.list_box.addWidget(self.label_info) self.label_info.hide() self.vbox.addLayout(self.save_btn_box) self.vbox.addLayout(self.create_filter_box) self.vbox.addLayout(self.list_box) self.filters_frame = QFrame() self.filters_frame.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) self.filters_frame.setFrameShape(QFrame.StyledPanel) self.filters_frame.setObjectName('filters_frame') self.filters_box = QVBoxLayout(self.filters_frame) self.filters_box_label = QLabel('Issues and filters') self.filters_box_label.setObjectName('filters_box_label') self.filters_box.addWidget(self.filters_box_label) self.filters_list = QListWidget() self.filters_list.installEventFilter(self) self.filters_list.itemClicked.connect(self.on_filter_selected) self.filters_list.setObjectName('filters_list') self.filters_list.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.filters_box.addWidget(self.filters_list) self.add_filter_button = QPushButton('+') self.add_filter_button.clicked.connect(self.add_filter_btn_click) self.add_filter_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.filters_box.addWidget(self.add_filter_button, alignment=Qt.AlignRight) self.btn_box = QHBoxLayout() self.refresh_btn = QPushButton('Refresh') self.refresh_btn.clicked.connect(self.controller.refresh_issue_list) self.btn_box.addWidget(self.refresh_btn, alignment=Qt.AlignRight) self.vbox.addLayout(self.btn_box) self.toggle_frame_filters_btn = QPushButton('<') self.toggle_frame_filters_btn.clicked.connect(self.toggle_frame_filters) self.toggle_frame_filters_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.toggle_frame_filters_btn.setObjectName('toggle_filters_btn') self.main_box = QHBoxLayout() self.main_box.addWidget(self.filters_frame) self.main_box.addWidget(self.toggle_frame_filters_btn, alignment=Qt.AlignTop) self.main_box.addLayout(self.vbox) self.setLayout(self.main_box) self.tray_icon = QSystemTrayIcon(self) self.tray_icon.setIcon(QIcon(LOGO_PATH)) self.tray_menu = QMenu() self.action_open = QAction('Open JQR', self) self.action_quit = QAction('Quit JQR', self) self.tray_menu.addAction(self.action_open) self.action_open.triggered.connect(self.show_jqr_from_tray) self.tray_menu.addAction(self.action_quit) self.action_quit.triggered.connect(self.controller.quit_app) self.tray_icon.setContextMenu(self.tray_menu) self.tray_icon.show() self.timer_log_work = QTimer() self.timer_log_work.timeout.connect(self.notification_to_log_work) self.timer_log_work.start(LOG_TIME) self.timer_refresh = QTimer() self.timer_refresh.timeout.connect(self.controller.auto_refresh_issue_list) def show_jqr_from_tray(self): self.hide() self.setWindowFlags(self.windowFlags() & ~Qt.WindowStaysOnTopHint) self.activateWindow() self.show() def keyPressEvent(self, event): if event.key() == Qt.Key_Return: self.controller.search_issues_by_query() def notification_to_log_work(self): QSound.play(RING_SOUND_PATH) self.tray_icon.showMessage( '1 hour had passed', 'Don\'t forget to log your work!', msecs=2000 ) self.timer_log_work.start(LOG_TIME) def update_issues(self, update_list): for issue in update_list: item = self.issue_list_widget.findItems( issue['key'], Qt.MatchExactly )[0] item.setText(issue['key']) issue_widget = self.issue_list_widget.itemWidget(item) issue_widget.set_issue_key(issue['key'], issue['link']) issue_widget.set_issue_title(issue['title']) issue_widget.set_time( issue['estimated'], issue['logged'], issue['remaining'] ) issue_widget.set_workflow.clear() issue_widget.set_workflow.addItems(self.controller.get_possible_workflows(issue)) issue_widget.set_workflow.setCurrentIndex(0) issue_widget.set_workflow.activated[str].disconnect() issue_widget.set_workflow.activated[str].connect( partial( self.controller.change_workflow, issue['workflow'], issue['issue_obj'], ) ) def delete_issues(self, delete_list): for issue in delete_list: item = self.issue_list_widget.findItems( issue['key'], Qt.MatchExactly )[0] self.issue_list_widget.takeItem( self.issue_list_widget.row(item) ) def insert_issues(self, new_issues_list): for issue in new_issues_list: issue_widget = QCustomWidget() issue_widget.set_issue_key(issue['key'], issue['link']) issue_widget.set_issue_title(issue['title']) issue_widget.set_time( issue['estimated'], issue['logged'], issue['remaining'] ) issue_widget.quick_log_btn.clicked.connect( partial( self.controller.log_work_from_list, issue['key'] ) ) issue_widget.log_work_btn.clicked.connect( partial( self.controller.open_time_log, issue['key'] ) ) issue_widget.open_pomodoro_btn.clicked.connect( partial( self.controller.open_pomodoro_window, issue['key'], issue['title'] ) ) # add workflow statuses to dropdown possible_workflows = self.controller.get_possible_workflows(issue) issue_widget.set_workflow.addItems(possible_workflows) issue_widget.set_workflow.setCurrentIndex(0) issue_widget.set_workflow.activated[str].connect( partial( self.controller.change_workflow, issue['workflow'], issue['issue_obj'], ) ) # add issue item to list issue_list_widget_item = QListWidgetItem() issue_list_widget_item.setText(issue['key']) issue_list_widget_item.setSizeHint(issue_widget.sizeHint()) self.issue_list_widget.insertItem(issue['index'], issue_list_widget_item) self.issue_list_widget.setItemWidget( issue_list_widget_item, issue_widget ) self.set_size_hint() def set_size_hint(self): self.issue_list_widget.setMinimumWidth( self.issue_list_widget.sizeHintForColumn(0) + 50 ) self.issue_list_widget.setMinimumHeight( self.issue_list_widget.sizeHintForRow(0) * 2 ) def show_filters(self, filters_dict): for index, key in enumerate(filters_dict): if key == SEARCH_ITEM_NAME: self.filters_list.insertItem(0, key) else: self.filters_list.addItem(key) self.filters_list.item(index).setToolTip(key) self.filters_list.item(0).setText(self.filters_list.item(0).text().capitalize()) # add separator after first item separator = QFrame() separator.setFrameShape(QFrame.HLine) separator.setObjectName('separator') item_separator = QListWidgetItem() item_separator.setFlags(Qt.NoItemFlags) self.filters_list.insertItem(1, item_separator) self.filters_list.setItemWidget(item_separator, separator) self.filters_list.setCurrentItem( self.filters_list.findItems( MY_ISSUES_ITEM_NAME, Qt.MatchExactly )[0]) self.filters_list.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents) self.on_filter_selected(self.filters_list.currentItem()) def filter_field_help(self): QDesktopServices.openUrl(self.help_filter_url) def on_filter_selected(self, item): if not item.text(): return self.current_item = item if len(self.current_item.text()) > 50: set_text = '{}...'.format(self.current_item.text()[:50]) else: set_text = self.current_item.text() self.issue_list_widget.scrollToTop() self.controller.search_issues_by_filter_name(item.text()) self.filter_name_label.setText(set_text) self.filter_edited_label.hide() if self.filters_list.currentItem().text() == MY_ISSUES_ITEM_NAME: self.save_filter_btn.hide() self.overwrite_filter_button.hide() self.filter_edited_label.hide() self.delete_filter_btn.hide() elif self.filters_list.currentItem().text() == SEARCH_ITEM_NAME.capitalize(): # activate save button self.overwrite_filter_button.hide() self.save_filter_btn.show() self.delete_filter_btn.hide() else: # activate overwrite button self.overwrite_filter_button.show() self.overwrite_filter_button.setEnabled(False) self.save_filter_btn.hide() self.delete_filter_btn.show() def toggle_frame_filters(self): if self.toggle_frame_filters_btn.text() == '<': self.toggle_frame_filters_btn.setText('>') self.filters_frame.hide() else: self.toggle_frame_filters_btn.setText('<') self.filters_frame.show() def add_filter_btn_click(self): self.overwrite_filter_button.hide() self.save_filter_btn.show() self.delete_filter_btn.hide() self.filter_edited_label.hide() self.filters_list.setCurrentItem(None) self.query_field.setText('') self.filter_name_label.setText('Add new filter') self.controller.current_issues.clear() self.show_no_issues() def eventFilter(self, obj, event): # if user started typing in filter field if obj is self.query_field and event.type() == QEvent.KeyRelease: if not self.filters_list.currentItem(): return super().eventFilter(obj, event) current_filter_name = self.filters_list.currentItem().text().lower() # if current filter is not 'Search issues' or 'my open issues' if current_filter_name not in (SEARCH_ITEM_NAME, MY_ISSUES_ITEM_NAME): # if query of current filter has not changed if self.controller.filters_handler.get_filter_by_name( current_filter_name ) != self.query_field.text(): # show that filter has been edited self.filter_edited_label.show() self.overwrite_filter_button.setEnabled(True) else: self.filter_edited_label.hide() self.overwrite_filter_button.setEnabled(False) return super().eventFilter(obj, event) def set_current_filter(self, filter_name): items = self.filters_list.findItems( filter_name, Qt.MatchExactly ) self.filters_list.setCurrentItem(items[0]) self.on_filter_selected(items[0]) def add_filter(self, filter_name): self.filters_list.addItem(filter_name) self.set_current_filter(filter_name) def delete_filter(self): filter_name = self.filters_list.currentItem().text() reply = QMessageBox.question( self, 'Delete filter', "Are you sure you want to delete " "'{}' filter?".format(filter_name), QMessageBox.Yes | QMessageBox.Cancel ) if reply == QMessageBox.Yes: self.controller.filters_handler.delete_filter(filter_name) self.filters_list.takeItem( self.filters_list.currentRow() ) self.filters_list.setCurrentItem( self.filters_list.findItems( MY_ISSUES_ITEM_NAME, Qt.MatchExactly )[0]) self.on_filter_selected(self.filters_list.currentItem()) def show_no_issues(self, error_text=None): self.issue_list_widget.clear() self.issue_list_widget.hide() if error_text: self.label_info.setText(error_text) self.label_info.show() def set_workflow_current_state(self, issue_key): item = self.issue_list_widget.findItems( issue_key, Qt.MatchExactly )[0] custom_item = self.issue_list_widget.itemWidget(item) custom_item.set_workflow.setCurrentIndex(0) def wheelEvent(self, event): # top left corner coordinates of the issue list list_pos = self.issue_list_widget.pos() # check if cursor position is on the issue list if event.pos().x() >= list_pos.x() and event.pos().y() >= list_pos.y(): if event.angleDelta().y() < 0: self.controller.refresh_issue_list(True) event.accept() def closeEvent(self, event): event.ignore() self.hide()
class PasswordDialog(QDialog): def __init__(self, parent=None, help_text='', show_stats=True): super(PasswordDialog, self).__init__(parent) self.setMinimumWidth(400) self.label = QLabel("Password:"******"Toggle visibility") self.action.triggered.connect(self.toggle_visibility) self.lineedit.addAction(self.action, QLineEdit.TrailingPosition) self.lineedit.returnPressed.connect(self.accept) layout = QGridLayout(self) layout.addWidget(self.label, 1, 1) layout.addWidget(self.lineedit, 2, 1) if show_stats: self.progressbar = QProgressBar() self.progressbar.setMaximum(4) self.progressbar.setTextVisible(False) self.progressbar.setFixedHeight(5) self.progressbar.setStyleSheet( 'QProgressBar { background-color: transparent }' 'QProgressBar::chunk { background-color: gray }' ) self.rating_label = QLabel() self.rating_label.setAlignment(Qt.AlignRight) self.time_label = QLabel() self.time_label.setStyleSheet('color: gray') layout.addWidget(self.progressbar, 3, 1) layout.addWidget(self.time_label, 4, 1) layout.addWidget(self.rating_label, 4, 1) self.lineedit.textChanged.connect(self.update_stats) self.update_color('transparent') if help_text: gbox = QGroupBox() gbox_layout = QGridLayout() gbox_label = QLabel(help_text) gbox_label.setWordWrap(True) gbox_label.setAlignment(Qt.AlignCenter) gbox_label.setStyleSheet('color: gray') gbox_layout.addWidget(gbox_label) gbox.setLayout(gbox_layout) layout.addWidget(gbox, 5, 1) layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 6, 1) def update_color(self, color): self.rating_label.setStyleSheet( 'QLabel {{ color: {} }}'.format(color)) self.progressbar.setStyleSheet( 'QProgressBar {{ background-color: transparent }}' 'QProgressBar::chunk {{ background-color: {} }}'.format(color)) def toggle_visibility(self): if self.lineedit.echoMode() == QLineEdit.Password: self.lineedit.setEchoMode(QLineEdit.Normal) else: self.lineedit.setEchoMode(QLineEdit.Password) def update_stats(self, text): # noqa: max-complexity=11 XXX if not text: self.time_label.setText('') self.rating_label.setText('') self.progressbar.setValue(0) return res = zxcvbn(text) t = res['crack_times_display']['offline_slow_hashing_1e4_per_second'] self.time_label.setText("Time to crack: {}".format(t)) s = res['crack_times_seconds']['offline_slow_hashing_1e4_per_second'] seconds = int(s) if seconds == 0: self.rating_label.setText("Very weak") self.update_color('lightgray') self.rating_label.setStyleSheet('QLabel { color: gray }') self.progressbar.setValue(1) elif seconds < 86400: # 1 day self.rating_label.setText("Weak") self.update_color('red') self.progressbar.setValue(1) elif seconds < 2592000: # 1 month self.rating_label.setText("Alright") self.update_color('orange') self.progressbar.setValue(2) elif seconds < 3153600000: # 100 years self.rating_label.setText("Good") self.update_color('#9CC259') self.progressbar.setValue(3) else: # > 100 years self.rating_label.setText("Excellent") self.update_color('#00B400') self.progressbar.setValue(4) warning = res['feedback']['warning'] try: suggestion = "Suggestion: " + res['feedback']['suggestions'][0] except IndexError: suggestion = None if warning and suggestion: self.rating_label.setToolTip(warning + '\n\n' + suggestion) elif warning: self.rating_label.setToolTip(warning) elif suggestion: self.rating_label.setToolTip(suggestion) else: self.rating_label.setToolTip(None) def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: self.reject() @staticmethod def get_password(parent=None, label=None, help_text='', show_stats=True): dialog = PasswordDialog(parent, help_text, show_stats) if label: dialog.label.setText(label) result = dialog.exec_() return (dialog.lineedit.text(), result)
class MyWindow(QMainWindow): def __init__(self, parent=None): super(MyWindow, self).__init__() self.setObjectName("MediathekQuery") self.root = QFileInfo(__file__).absolutePath() self.setAttribute(Qt.WA_DeleteOnClose) self.settings = QSettings('Axel Schneider', self.objectName()) self.viewer = QTableWidget() self.horizontalHeader = self.viewer.horizontalHeader() icon = self.root + "/icon.png" self.titleList = [] self.topicList = [] self.urlList = [] self.urlKleinList = [] self.beschreibungList = [] self.idList = [] self.chList = [] self.lengthList = [] self.results = "" self.myurl = "" self.fname = "" self.viewer.setSelectionBehavior(QAbstractItemView.SelectRows) self.viewer.SelectionMode(QAbstractItemView.SingleSelection) self.viewer.setSortingEnabled(False) self.viewer.verticalHeader().setStretchLastSection(False) self.viewer.horizontalHeader().setStretchLastSection(True) self.viewer.setColumnCount(7) self.viewer.setColumnWidth(0, 48) self.viewer.setColumnWidth(1, 130) self.viewer.setColumnWidth(2, 160) self.viewer.setColumnWidth(3, 60) self.viewer.hideColumn(4) self.viewer.hideColumn(5) self.viewer.setHorizontalHeaderLabels(["Sender", "Thema", "Titel", "Länge", "HD", "SD", "Beschreibung"]) self.viewer.verticalHeader().setVisible(True) self.viewer.horizontalHeader().setVisible(True) self.setStyleSheet(stylesheet(self)) self.viewer.selectionModel().selectionChanged.connect(self.getCellText) self.layout = QGridLayout() self.layout.addWidget(self.viewer,0, 0, 1, 7) self.findfield = QLineEdit() self.fAction = QAction(QIcon.fromTheme("edit-clear"), "", triggered = self.findfieldAction) self.findfield.addAction(self.fAction, 1) self.findfield.returnPressed.connect(self.myQuery) self.findfield.setFixedWidth(200) self.findfield.setPlaceholderText("suchen ...") self.findfield.setToolTip("ENTER to find") self.layout.addWidget(self.findfield,1, 0) self.chCombo = QComboBox() self.chCombo.setFixedWidth(80) self.chCombo.addItems(['ARD', 'ZDF', 'MDR', 'PHOENIX', 'RBB', 'BR', 'HR', 'SR', \ 'SWR', 'NDR', 'DW', 'WDR', 'ARTE', '3SAT', 'KIKA', 'ORF', 'SRF']) self.chCombo.addItem("alle") self.chCombo.setToolTip("Sender wählen") self.chCombo.currentIndexChanged.connect(self.myQuery) self.layout.addWidget(self.chCombo,1, 1) self.btnPlay = QPushButton("Play") self.btnPlay.setFixedWidth(80) self.btnPlay.setIcon(QIcon.fromTheme("media-playback-start")) self.layout.addWidget(self.btnPlay,1, 2) self.btnPlay.clicked.connect(self.playVideo) self.btnDownload = QPushButton("Download") self.btnDownload.setFixedWidth(100) self.btnDownload.setIcon(QIcon.fromTheme("download")) self.layout.addWidget(self.btnDownload,1, 3) self.btnDownload.clicked.connect(self.downloadVideo) self.chBox = QPushButton("SD") self.chBox.setToolTip("umschalten HD / SD") self.chBox.setStyleSheet("background: #729fcf;") self.chBox.setFixedWidth(44) self.chBox.clicked.connect(self.toggleQuality) self.layout.addWidget(self.chBox,1, 4) self.lbl = QLabel("Info") self.layout.addWidget(self.lbl,1, 5) self.chkbox = QCheckBox("nach Filmlänge sortieren") self.layout.addWidget(self.chkbox,1, 6) self.chkbox.setCheckState(0) self.chkbox.setToolTip("Standard-Sortierung ist nach Erscheinungsdatum") self.chkbox.stateChanged.connect(self.myQuery) self.myWidget = QWidget() self.myWidget.setLayout(self.layout) self.msg("Ready") self.setCentralWidget(self.myWidget) self.setWindowIcon(QIcon(icon)) self.setGeometry(20,20,600,450) self.setWindowTitle("Mediathek Suche") self.readSettings() self.msg("Ready") self.findfield.setFocus() self.player = MediathekPlayer.VideoPlayer('') self.player.hide() wildcards = "Wildcards: + Titel # Thema * Beschreibung\n '<xx Suchbegriff' kleiner als xx Minuten '>xx Suchbegriff' grösser als xx Minuten " help_label = QLabel(wildcards) help_label.setToolTip("ohne Wildcard werden alle Felder durchsucht") help_label.setStyleSheet("font-size: 8pt; color: #1a2334;") self.statusBar().addPermanentWidget(help_label) self.statusBar().showMessage("Ready") def toggleQuality(self): if self.chBox.text() == "SD": self.chBox.setText("HD") self.chBox.setStyleSheet("background: #8ae234;") self.getCellText() else: self.chBox.setText("SD") self.chBox.setStyleSheet("background: #729fcf;") self.getCellText() def myQuery(self): if not self.findfield.text() == "": self.viewer.setRowCount(0) self.viewer.clearContents() self.titleList = [] self.topicList = [] self.urlList = [] self.urlKleinList = [] self.beschreibungList = [] self.idList = [] self.chList = [] self.lengthList = [] channels = [self.chCombo.currentText()] if channels == ["alle"]: channels = ["ard", "zdf", "mdr", "phoenix", "rbb", "br", "hr", "sr", "swr", "ndr",\ "dw", "wdr", "arte", "3sat", "kika", "orf", "srf"] print("suche", self.findfield.text(), "in", ','.join(channels).upper()) if self.findfield.text().startswith("*"): ### nur Beschreibung for ch in channels: r = self.makeQueryBeschreibung(ch, self.findfield.text()[1:]) elif self.findfield.text().startswith("#"): ### nur Thema for ch in channels: r = self.makeQueryTopic(ch, self.findfield.text()[1:]) elif self.findfield.text().startswith("+"): ### nur Titel for ch in channels: r = self.makeQueryTitle(ch, self.findfield.text()[1:]) elif self.findfield.text().startswith(">"): ### Zeit grösser for ch in channels: r = self.makeQueryBigger(ch, self.findfield.text()) elif self.findfield.text().startswith("<"): ### Zeit kleiner for ch in channels: r = self.makeQuerySmaller(ch, self.findfield.text()) else: ### alle Felder for ch in channels: r = self.makeQuery(ch, self.findfield.text()) for b in range(len(self.titleList)): self.idList.append(str(b)) self.viewer.setSortingEnabled(False) for x in range(len(self.titleList)): self.viewer.insertRow(x) self.viewer.setItem(x, 0, QTableWidgetItem(self.chList[x])) self.viewer.setItem(x, 1, QTableWidgetItem(self.topicList[x])) self.viewer.setItem(x, 2, QTableWidgetItem(self.titleList[x])) self.viewer.setItem(x, 3, QTableWidgetItem(self.lengthList[x])) self.viewer.setItem(x, 4, QTableWidgetItem(self.urlList[x])) self.viewer.setItem(x, 5, QTableWidgetItem(self.urlKleinList[x])) self.viewer.setItem(x, 6, QTableWidgetItem(self.beschreibungList[x])) for x in range(len(self.titleList)): self.viewer.resizeRowToContents(x) def makeQuery(self, channel, myquery): headers = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0', 'Accept': '*/*', 'Accept-Language': 'de-DE,en;q=0.5', 'Content-Type': 'text/plain;charset=UTF-8', 'Connection': 'keep-alive', } if self.chkbox.checkState() == 2: data = {"future":"true", "size":"500", "sortBy":"duration", "sortOrder":"desc", \ "queries":[{"fields":["title", "topic", "description"], "query":"" + myquery + ""},{"fields":["channel"], "query":"" + channel + ""}]} else: data = {"future":"true", "size":"500", "sortBy":"timestamp", "sortOrder":"asc", \ "queries":[{"fields":["title", "topic", "description"], "query":"" + myquery + ""},{"fields":["channel"], "query":"" + channel + ""}]} response = requests.post('https://mediathekviewweb.de/api/query', headers=headers, json=data) response_json = response.json() count = int(response_json['result']['queryInfo']['resultCount']) for x in range(count): topic = response_json['result']['results'][x]['topic'] title = response_json['result']['results'][x]['title'] url = response_json['result']['results'][x]['url_video'] url_klein = response_json['result']['results'][x]['url_video_low'] beschreibung = response_json['result']['results'][x]['description'] l = response_json['result']['results'][x]['duration'] if not l == "": length = time.strftime('%H:%M:%S', time.gmtime(l)) self.lengthList.append(length) else: self.lengthList.append("") ch = response_json['result']['results'][x]['channel'] if not ch == "": self.chList.append(ch) else: self.chList.append("") if not title == "": self.titleList.append(title) else: self.titleList.append("") if not topic == "": self.topicList.append(topic) else: self.topicList.append("") if not url == "": self.urlList.append(url) else: self.urlList.append("") if not url_klein == "": self.urlKleinList.append(url_klein) else: self.urlKleinList.append("") if not beschreibung == "": self.beschreibungList.append(beschreibung) else: self.beschreibungList.append("") print(count, "Beiträge gefunden") self.lbl.setText(f"{count} Beiträge gefunden") def makeQueryBeschreibung(self, channel, myquery): headers = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0', 'Accept': '*/*', 'Accept-Language': 'de-DE,en;q=0.5', 'Content-Type': 'text/plain;charset=UTF-8', 'Connection': 'keep-alive', } data = {"future":"true", "size":"500", "sortBy":"timestamp", "sortOrder":"desc", \ "queries":[{"fields":["description"], "query":"" + myquery + ""},{"fields":["channel"], "query":"" + channel + ""}]} response = requests.post('https://mediathekviewweb.de/api/query', headers=headers, json=data) response_json = response.json() count = int(response_json['result']['queryInfo']['resultCount']) for x in range(count): topic = response_json['result']['results'][x]['topic'] title = response_json['result']['results'][x]['title'] url = response_json['result']['results'][x]['url_video'] url_klein = response_json['result']['results'][x]['url_video_low'] beschreibung = response_json['result']['results'][x]['description'] l = response_json['result']['results'][x]['duration'] if not l == "": length = time.strftime('%H:%M:%S', time.gmtime(l)) self.lengthList.append(length) else: self.lengthList.append("") ch = response_json['result']['results'][x]['channel'] if not ch == "": self.chList.append(ch) else: self.chList.append("") if not title == "": self.titleList.append(title) else: self.titleList.append("") if not topic == "": self.topicList.append(topic) else: self.topicList.append("") if not url == "": self.urlList.append(url) else: self.urlList.append("") if not url_klein == "": self.urlKleinList.append(url_klein) else: self.urlKleinList.append("") if not beschreibung == "": self.beschreibungList.append(beschreibung) else: self.beschreibungList.append("") print(count, "Beiträge gefunden") self.lbl.setText(f"{count} Beiträge gefunden") def makeQueryTopic(self, channel, myquery): headers = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0', 'Accept': '*/*', 'Accept-Language': 'de-DE,en;q=0.5', 'Content-Type': 'text/plain;charset=UTF-8', 'Connection': 'keep-alive', } data = {"future":"true", "size":"500", "sortBy":"timestamp", "sortOrder":"desc", \ "queries":[{"fields":["topic"], "query":"" + myquery + ""},{"fields":["channel"], "query":"" + channel + ""}]} response = requests.post('https://mediathekviewweb.de/api/query', headers=headers, json=data) response_json = response.json() count = int(response_json['result']['queryInfo']['resultCount']) for x in range(count): topic = response_json['result']['results'][x]['topic'] title = response_json['result']['results'][x]['title'] url = response_json['result']['results'][x]['url_video'] url_klein = response_json['result']['results'][x]['url_video_low'] beschreibung = response_json['result']['results'][x]['description'] l = response_json['result']['results'][x]['duration'] if not l == "": length = time.strftime('%H:%M:%S', time.gmtime(l)) self.lengthList.append(length) else: self.lengthList.append("") ch = response_json['result']['results'][x]['channel'] if not ch == "": self.chList.append(ch) else: self.chList.append("") if not title == "": self.titleList.append(title) else: self.titleList.append("") if not topic == "": self.topicList.append(topic) else: self.topicList.append("") if not url == "": self.urlList.append(url) else: self.urlList.append("") if not url_klein == "": self.urlKleinList.append(url_klein) else: self.urlKleinList.append("") if not beschreibung == "": self.beschreibungList.append(beschreibung) else: self.beschreibungList.append("") print(count, "Beiträge gefunden") self.lbl.setText(f"{count} Beiträge gefunden") def makeQueryTitle(self, channel, myquery): headers = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0', 'Accept': '*/*', 'Accept-Language': 'de-DE,en;q=0.5', 'Content-Type': 'text/plain;charset=UTF-8', 'Connection': 'keep-alive', } data = {"future":"true", "size":"500", "sortBy":"timestamp", "sortOrder":"desc", \ "queries":[{"fields":["title"], "query":"" + myquery + ""},{"fields":["channel"], "query":"" + channel + ""}]} response = requests.post('https://mediathekviewweb.de/api/query', headers=headers, json=data) response_json = response.json() count = int(response_json['result']['queryInfo']['resultCount']) for x in range(count): topic = response_json['result']['results'][x]['topic'] title = response_json['result']['results'][x]['title'] url = response_json['result']['results'][x]['url_video'] url_klein = response_json['result']['results'][x]['url_video_low'] beschreibung = response_json['result']['results'][x]['description'] l = response_json['result']['results'][x]['duration'] if not l == "": length = time.strftime('%H:%M:%S', time.gmtime(l)) self.lengthList.append(length) else: self.lengthList.append("") ch = response_json['result']['results'][x]['channel'] if not ch == "": self.chList.append(ch) else: self.chList.append("") if not title == "": self.titleList.append(title) else: self.titleList.append("") if not topic == "": self.topicList.append(topic) else: self.topicList.append("") if not url == "": self.urlList.append(url) else: self.urlList.append("") if not url_klein == "": self.urlKleinList.append(url_klein) else: self.urlKleinList.append("") if not beschreibung == "": self.beschreibungList.append(beschreibung) else: self.beschreibungList.append("") print(count, "Beiträge gefunden") self.lbl.setText(f"{count} Beiträge gefunden") ####################################################################### def makeQueryBigger(self, channel, myquery): headers = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0', 'Accept': '*/*', 'Accept-Language': 'de-DE,en;q=0.5', 'Content-Type': 'text/plain;charset=UTF-8', 'Connection': 'keep-alive', } if self.chkbox.checkState() == 2: data = {"future":"true", "size":"500", "sortBy":"duration", "sortOrder":"desc", \ "queries":[{"fields":["duration"], "query":"" + myquery[1:].partition(" ")[2] + ""},{"fields":["channel"], "query":"" + channel + ""}]} else: data = {"future":"true", "size":"500", "sortBy":"timestamp", "sortOrder":"asc", \ "queries":[{"fields":["title", "topic", "description"], "query":"" + myquery[1:].partition(" ")[2] + ""},{"fields":["channel"], "query":"" + channel + ""}]} response = requests.post('https://mediathekviewweb.de/api/query', headers=headers, json=data) response_json = response.json() count = int(response_json['result']['queryInfo']['resultCount']) for x in range(count): topic = response_json['result']['results'][x]['topic'] title = response_json['result']['results'][x]['title'] url = response_json['result']['results'][x]['url_video'] url_klein = response_json['result']['results'][x]['url_video_low'] beschreibung = response_json['result']['results'][x]['description'] l = response_json['result']['results'][x]['duration'] if not l == "": length = time.strftime('%H:%M:%S', time.gmtime(l)) mydur = myquery[1:].partition(" ")[0] hour = time.strftime('%H', time.gmtime(l)) minute = time.strftime('%M', time.gmtime(l)) dur = int(hour) * 60 + int(minute) if dur > int(mydur) - 1: self.lengthList.append(length) ch = response_json['result']['results'][x]['channel'] if not ch == "": self.chList.append(ch) else: self.chList.append("") if not title == "": self.titleList.append(title) else: self.titleList.append("") if not topic == "": self.topicList.append(topic) else: self.topicList.append("") if not url == "": self.urlList.append(url) else: self.urlList.append("") if not url_klein == "": self.urlKleinList.append(url_klein) else: self.urlKleinList.append("") if not beschreibung == "": self.beschreibungList.append(beschreibung) else: self.beschreibungList.append("") print(count, "Beiträge gefunden") self.lbl.setText(f"{count} Beiträge gefunden") ####################################################################### def makeQuerySmaller(self, channel, myquery): headers = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0', 'Accept': '*/*', 'Accept-Language': 'de-DE,en;q=0.5', 'Content-Type': 'text/plain;charset=UTF-8', 'Connection': 'keep-alive', } if self.chkbox.checkState() == 2: data = {"future":"true", "size":"500", "sortBy":"duration", "sortOrder":"desc", \ "queries":[{"fields":["duration"], "query":"" + myquery[1:].partition(" ")[2] + ""},{"fields":["channel"], "query":"" + channel + ""}]} else: data = {"future":"true", "size":"500", "sortBy":"timestamp", "sortOrder":"asc", \ "queries":[{"fields":["title", "topic", "description"], "query":"" + myquery[1:].partition(" ")[2] + ""},{"fields":["channel"], "query":"" + channel + ""}]} response = requests.post('https://mediathekviewweb.de/api/query', headers=headers, json=data) response_json = response.json() count = int(response_json['result']['queryInfo']['resultCount']) for x in range(count): topic = response_json['result']['results'][x]['topic'] title = response_json['result']['results'][x]['title'] url = response_json['result']['results'][x]['url_video'] url_klein = response_json['result']['results'][x]['url_video_low'] beschreibung = response_json['result']['results'][x]['description'] l = response_json['result']['results'][x]['duration'] if not l == "": length = time.strftime('%H:%M:%S', time.gmtime(l)) mydur = myquery[1:].partition(" ")[0] hour = time.strftime('%H', time.gmtime(l)) minute = time.strftime('%M', time.gmtime(l)) dur = int(hour) * 60 + int(minute) if dur < int(mydur): self.lengthList.append(length) ch = response_json['result']['results'][x]['channel'] if not ch == "": self.chList.append(ch) else: self.chList.append("") if not title == "": self.titleList.append(title) else: self.titleList.append("") if not topic == "": self.topicList.append(topic) else: self.topicList.append("") if not url == "": self.urlList.append(url) else: self.urlList.append("") if not url_klein == "": self.urlKleinList.append(url_klein) else: self.urlKleinList.append("") if not beschreibung == "": self.beschreibungList.append(beschreibung) else: self.beschreibungList.append("") print(count, "Beiträge gefunden") self.lbl.setText(f"{count} Beiträge gefunden") ####################################################################### def findfieldAction(self): self.findfield.setText("") def downloadVideo(self): if not self.url == "": self.downloader = Downloader.Downloader() self.downloader.setWindowTitle("Downloader") self.downloader.url = self.url item = self.viewer.selectedIndexes()[2] if not item == "": filename = str(item.data()) self.downloader.fname = filename + self.url[-4:] self.downloader.fname = self.downloader.fname.replace(' (', '_').replace(') ', '_')\ .replace(')', '_').replace('/', '_') if '_.' in self.downloader.fname: self.downloader.fname = self.downloader.fname.replace('_.', '.') self.downloader.lbl.setText("speichern als: " + self.downloader.homepath + self.downloader.fname) self.downloader.move(self.x() + 2, self.y() + 28) self.downloader.show() else: print("keine URL") self.msg("keine URL") def getCellText(self): if self.viewer.selectionModel().hasSelection(): row = self.selectedRow() if not self.chBox.text() == "SD": item = self.urlList[row] else: item = self.urlKleinList[row] if not item == "": name = item self.url = str(item) QApplication.clipboard().setText(self.url) print(self.url) infotext = f"{self.chList[row]}: {self.topicList[row]} - {self.titleList[row]} \ ({self.chBox.text()}) Dauer: {self.lengthList[row]}" self.msg(infotext) self.fname = str(self.viewer.selectedIndexes()[1].data()) def playVideo(self): if self.viewer.selectionModel().hasSelection(): row = self.selectedRow() if not self.chBox.text() == "SD": item = item = self.urlList[row] print("play HD") else: item = self.urlKleinList[row] print("play SD") if not item == "": self.url = item if not self.url == "": print("url =", self.url) self.player.show() self.player.playMyURL(self.url) else: print("keine URL vorhanden") self.msg("keine URL vorhanden") else: print("keine URL vorhanden") else: print("keine URL vorhanden") def selectedRow(self): if self.viewer.selectionModel().hasSelection(): row = self.viewer.selectionModel().selectedIndexes()[0].row() return int(row) def closeEvent(self, e): self.writeSettings() self.player.close() e.accept() def readSettings(self): print("lese Fensterposition") if self.settings.contains('geometry'): self.setGeometry(self.settings.value('geometry')) def writeSettings(self): print("Fensterposition gespeichert") self.settings.setValue('geometry', self.geometry()) def msg(self, message): self.statusBar().showMessage(message, 0)