class SourceViewer(QDialog): def __init__(self, browser): super(SourceViewer, self).__init__(browser.parentWidget()) layout = QVBoxLayout() layout.setContentsMargins(4, 4, 4, 4) self.setLayout(layout) self.urlLabel = QLabel(wordWrap=True) layout.addWidget(self.urlLabel) self.textbrowser = QTextBrowser() layout.addWidget(self.textbrowser) self.urlLabel.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.textbrowser.setLineWrapMode(QTextBrowser.NoWrap) app.settingsChanged.connect(self.readSettings) self.readSettings() app.translateUI(self) qutil.saveDialogSize(self, "helpbrowser/sourceviewer/size", QSize(400, 300)) def translateUI(self): self.setWindowTitle(app.caption(_("LilyPond Source"))) def readSettings(self): data = textformats.formatData('editor') self.textbrowser.setPalette(data.palette()) self.textbrowser.setFont(data.font) highlighter.highlight(self.textbrowser.document()) def showReply(self, reply): reply.setParent(self) self.urlLabel.setText(reply.url().toString()) self._reply = reply reply.finished.connect(self.loadingFinished) self.textbrowser.clear() self.show() def loadingFinished(self): data = self._reply.readAll() self._reply.close() self._reply.deleteLater() del self._reply self.textbrowser.clear() self.textbrowser.setText(str(data, 'utf-8', 'replace')) highlighter.highlight(self.textbrowser.document())
class MyApp(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.le = QLineEdit() self.le.returnPressed.connect(self.append_text) # 키보드에 엔터를 눌렀는지 확인해주는 이벤트 # 엔터를 누르면 append_text를 받아와서 입력값 자동 저장 self.tb = QTextBrowser() #QTextBrowser() 클래스를 이용해서 텍스트 브라우저 객체 생성 self.tb.setAcceptRichText(True) # 서식 있는 텍스트(Rich text)를 사용할 수 있음 # 디폴트로 True이기 때문에 없어도 되는 부분! self.tb.setOpenExternalLinks(True) # 외부 링크로의 연결 가능 self.clear_btn = QPushButton('Clear') # 버튼을 클릭하면 self.clear_btn.pressed.connect(self.clear_text) # Clear_text 메소드 호출 vbox = QVBoxLayout() # 레이아웃 해주기 위한 vbox 객체 생성! vbox.addWidget(self.le, 0) # .addWidget() 순서 정해줄 수 있음! vbox.addWidget(self.tb, 1) vbox.addWidget(self.clear_btn, 2) self.setLayout(vbox) self.setWindowTitle('QTextBrowser') self.setGeometry(300, 300, 300, 300) self.show() def append_text(self): text = self.le.text() self.tb.append(text) self.le.clear() # 입력값 초기화 시켜주는 함수! def clear_text(self): self.tb.clear()
class CheckInputWidget(QWidget, MooseWidget): """ Runs the executable with "--check-input" on the input file and stores the results. Signals: needInputFile: Emitted when we need the input file. Argument is the path where the input file will be written. """ needInputFile = pyqtSignal(str) def __init__(self, **kwds): super(CheckInputWidget, self).__init__(**kwds) self.input_file = "peacock_check_input.i" self.top_layout = WidgetUtils.addLayout(vertical=True) self.setLayout(self.top_layout) self.output = QTextBrowser(self) self.output.setStyleSheet( "QTextBrowser { background: black; color: white; }") self.output.setReadOnly(True) self.top_layout.addWidget(self.output) self.button_layout = WidgetUtils.addLayout() self.top_layout.addLayout(self.button_layout) self.hide_button = WidgetUtils.addButton(self.button_layout, self, "Hide", lambda: self.hide()) self.check_button = WidgetUtils.addButton(self.button_layout, self, "Check", self._check) self.resize(800, 500) self.setup() self.path = None def cleanup(self): try: os.remove(self.input_file) except: pass def check(self, path): """ Runs the executable with "--check-input" and adds the output to the window Input: path[str]: Path to the executable """ self.path = path self._check() def _check(self): """ Runs the executable with "--check-input" and adds the output to the window """ input_file = os.path.abspath(self.input_file) self.needInputFile.emit(input_file) self.output.clear() try: args = ["-i", input_file, "--check-input"] output = ExeLauncher.runExe(self.path, args, print_errors=False) output_html = TerminalUtils.terminalOutputToHtml(output) self.output.setHtml("<pre>%s</pre>" % output_html) except Exception as e: output_html = TerminalUtils.terminalOutputToHtml(str(e)) self.output.setHtml("<pre>%s</pre>" % output_html) self.cleanup()
class MyApp(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.le = QLineEdit() self.le.returnPressed.connect(self.append_text) self.tb = QTextBrowser() self.tb.setAcceptRichText(True) self.tb.setOpenExternalLinks(True) self.clear_btn = QPushButton('Clear') self.clear_btn.pressed.connect(self.clear_text) vbox = QVBoxLayout() vbox.addWidget(self.le, 0) vbox.addWidget(self.tb, 1) vbox.addWidget(self.clear_btn, 2) self.setLayout(vbox) self.setWindowTitle('QTextBrowser') self.setGeometry(300, 300, 300, 300) self.show() def append_text(self): text = self.le.text() self.tb.append(text) self.le.clear() def clear_text(self): self.tb.clear()
def showPointsCharacteristics(characteristics: dict, textBrowser: QTextBrowser): textBrowser.clear() textBrowser.append( "АНАЛІЗ ДВОВИМІРНОГО ОБ'ЄКТУ\n \t\t\t|---Точкові статистичні оцінки---|\n" ) textBrowser.append(getPointCharacteristicsTable(characteristics))
class MyApp(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.le = QLineEdit() self.le.setPlaceholderText('기본 값 유윈스 학사공') self.le.returnPressed.connect(self.get_url_subject) self.btn = QPushButton('Start') self.btn.clicked.connect(self.get_url_subject) self.lbl = QLabel('과를 입력하세요.') self.tb = QTextBrowser() self.tb.setAcceptRichText(True) self.tb.setOpenExternalLinks(True) grid = QGridLayout() grid.addWidget(self.le, 0, 0, 1, 3) grid.addWidget(self.btn, 0, 3, 1, 1) grid.addWidget(self.lbl, 1, 0, 1, 4) grid.addWidget(self.tb, 2, 0, 1, 4) self.setLayout(grid) self.setWindowTitle('Web Crawler') self.setGeometry(100, 100, 450, 650) self.show() def get_url_subject(self): urls = [] subjects = [] major = self.le.text() if not major: self.lbl.setText('학사 공지사항입니다.') self.tb.clear() req = requests.get( 'https://uwins.ulsan.ac.kr/JBGJ/B/MIB01S.aspx?MenuID=MIB01S!1') html = req.text soup = BeautifulSoup(html, 'html.parser') id_links = soup.select('td:nth-child(1)') subject_links = soup.select('td.textWrap.Left') for id_link in id_links: id = id_link.text.strip() url = 'https://uwins.ulsan.ac.kr/JBGJ/B/MIB02S.aspx?MenuID=MIB01S!1&board_gb=A38002&seq=' + id + '&Grade=3¤t_page=1' urls.append(url) for subject_link in subject_links: subject = subject_link.text.strip() subjects.append(subject) for i in range(10): self.tb.append( str(i + 1) + '. ' + subjects[i] + ' (' + '<a href="' + urls[i] + '">링크</a>' + ')')
class Demo(QWidget): def __init__(self): super(Demo, self).__init__() self.setWindowTitle('IndeedCrawler') self.url_line = QLineEdit(self) # Get start url self.ua_line = QLineEdit(self) # Input USER_AGENT self.obey_combo = QComboBox(self) # Decide ROBOTSTXT_OBEY self.job_num = QLineEdit(self) self.obey_combo.addItems(['Yes', 'No']) self.log_browser = QTextBrowser(self) # Log output self.crawl_btn = QPushButton('Start Crawling', self) # Start Crawling self.crawl_btn.clicked.connect(self.crawl_slot) # Layout self.h_layout = QHBoxLayout() self.v_layout = QVBoxLayout() self.v_layout.addWidget(QLabel('Input start url')) self.v_layout.addWidget(self.url_line) self.h_layout.addWidget( QLabel('Iinput total job numbers to be crawled')) self.h_layout.addWidget(self.job_num) self.h_layout.addWidget(QLabel('Input User-Agent')) self.h_layout.addWidget(self.ua_line) self.h_layout.addWidget(QLabel('Obey Robot.txt')) self.h_layout.addWidget(self.obey_combo) self.v_layout.addLayout(self.h_layout) self.v_layout.addWidget(QLabel('Output')) self.v_layout.addWidget(self.log_browser) self.v_layout.addWidget(self.crawl_btn) self.setLayout(self.v_layout) self.Q = Manager().Queue() self.log_thread = LogThread(self) def crawl_slot(self): if self.crawl_btn.text() == 'Start Crawling': self.log_browser.clear() self.crawl_btn.setText('Stop Crawling') start_url = self.url_line.text() ua = self.ua_line.text().strip() try: job_num = int(self.job_num.text()) except: print('Jobs number must be a integer') is_obey = True if self.obey_combo.currentText() == 'Yes' else False self.p = Process(target=crawl, args=(self.Q, ua, is_obey, start_url, job_num)) self.p.start() self.log_thread.start() else: self.crawl_btn.setText('Start Crawling') self.p.terminate() self.log_thread.terminate() def closeEvent(self, event): self.p.terminate() self.log_thread.terminate()
class SummaryWidget(QWidget): def __init__(self, parent=None): super().__init__() self.parent = parent self.setWindowTitle(self.tr("Installation Information")) self.setLayout(QVBoxLayout()) label1 = QLabel() label1.setText(self.tr("<h3>Take a look at the summary of your choices for the installation.</h3>")) self.layout().addWidget(label1) label2 = QLabel() label2.setText(self.tr("<h1>System Location</h1>")) self.layout().addWidget(label2) self.textbrowser1 = QTextBrowser() self.layout().addWidget(self.textbrowser1) label3 = QLabel() label3.setText(self.tr("<h1>Keyboard Layout</h1>")) self.layout().addWidget(label3) self.textbrowser2 = QTextBrowser() self.layout().addWidget(self.textbrowser2) label4 = QLabel() label4.setText(self.tr("<h1>Disk Partition</h1>")) self.layout().addWidget(label4) self.textbrowser3 = QTextBrowser() self.layout().addWidget(self.textbrowser3) def showEvent(self, event): self.textbrowser1.setText(self.tr("System time will be set to {}.\nSystem language will be set to {}.") .format(self.parent.lilii_settings["timezone"], self.parent.lilii_settings["lang"])) variant = None if self.parent.lilii_settings["keyboard_variant"] != None: variant = self.parent.lilii_settings["keyboard_variant"][-1] else: variant = "Default" self.textbrowser2.setText(self.tr("Keyboard model is choosen as {}.\nKeyboard kind is choosen as {}/{}.") .format(self.parent.lilii_settings["keyboard_model"][-1], self.parent.lilii_settings["keyboard_layout"][-1], variant)) self.textbrowser3.clear() if self.parent.lilii_settings["/"]: self.textbrowser3.append(self.tr("Root directory is {}.").format(self.parent.lilii_settings["/"])) if self.parent.lilii_settings["/home"]: self.textbrowser3.append(self.tr("Home directory is {}.").format(self.parent.lilii_settings["/home"])) if is_efi() and self.parent.lilii_settings["/boot/efi"]: self.textbrowser3.append(self.tr("Bootloader installation directory is {}.").format(self.parent.lilii_settings["/boot/efi"])) else: self.textbrowser3.append(self.tr("Bootloader installation disk: {}").format(self.parent.lilii_settings["bootloader"]))
def showProtocol(characteristics: dict, textBrowser: QTextBrowser): textBrowser.clear() textBrowser.append( "АНАЛІЗ ОДНОВИМІРНОГО ОБ'ЄКТУ\n \t\t\t\t\t|---Точкові статистичні оцінки---|\n" ) textBrowser.append(getPointCharacteristicsTable(characteristics['point'])) textBrowser.append("\t\t\t\t\t|---Інтервальні статистичні оцінки---|\n") textBrowser.append( getIntervalCharacteristicsTable(characteristics['interval']))
class CheckInputWidget(QWidget, MooseWidget): """ Runs the executable with "--check-input" on the input file and stores the results. Signals: needInputFile: Emitted when we need the input file. Argument is the path where the input file will be written. """ needInputFile = pyqtSignal(str) def __init__(self, **kwds): super(CheckInputWidget, self).__init__(**kwds) self.input_file = "peacock_check_input.i" self.top_layout = WidgetUtils.addLayout(vertical=True) self.setLayout(self.top_layout) self.output = QTextBrowser(self) self.output.setStyleSheet("QTextBrowser { background: black; color: white; }") self.output.setReadOnly(True) self.top_layout.addWidget(self.output) self.button_layout = WidgetUtils.addLayout() self.top_layout.addLayout(self.button_layout) self.hide_button = WidgetUtils.addButton(self.button_layout, self, "Hide", lambda: self.hide()) self.check_button = WidgetUtils.addButton(self.button_layout, self, "Check", self._check) self.resize(800, 500) self.setup() self.path = None def cleanup(self): try: os.remove(self.input_file) except: pass def check(self, path): """ Runs the executable with "--check-input" and adds the output to the window Input: path[str]: Path to the executable """ self.path = path self._check() def _check(self): """ Runs the executable with "--check-input" and adds the output to the window """ input_file = os.path.abspath(self.input_file) self.needInputFile.emit(input_file) self.output.clear() try: args = ["-i", input_file, "--check-input"] output = ExeLauncher.runExe(self.path, args, print_errors=False) output_html = TerminalUtils.terminalOutputToHtml(output) self.output.setHtml("<pre>%s</pre>" % output_html) except Exception as e: output_html = TerminalUtils.terminalOutputToHtml(str(e)) self.output.setHtml("<pre>%s</pre>" % output_html) self.cleanup()
class MyApp(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.le = QLineEdit() self.le.setPlaceholderText('기본 값 유윈스 학사공') self.le.returnPressed.connect(self.ulsan_urls_subjects) self.btn = QPushButton('Start') self.btn.clicked.connect(self.ulsan_urls_subjects) self.lbl = QLabel('과를 입력하세요.') self.tb = QTextBrowser() self.tb.setAcceptRichText(True) self.tb.setOpenExternalLinks(True) grid = QGridLayout() grid.addWidget(self.le, 0, 0, 1, 3) grid.addWidget(self.btn, 0, 3, 1, 1) grid.addWidget(self.lbl, 1, 0, 1, 4) grid.addWidget(self.tb, 2, 0, 1, 4) self.setLayout(grid) self.setWindowTitle('Web Crawler') self.setGeometry(100, 100, 450, 650) self.show() def ulsan_urls_subjects(self): ulsan_urls = [] ulsan_subjects = [] ulsan_ major = self.le.text() if not major: self.lbl.setText('울산대 홈페이지 공지사항입니다.') self.tb.clear() req = requests.get('http://www.ulsan.ac.kr/unews/news/notice.aspx?o=L') html = req.text soup = BeautifulSoup(html, 'html.parser') id_links = soup.select('tr > td.no') subject_links = soup.select('tr > td.title') for id_link in id_links: id = id_link.text.strip() url = 'http://www.ulsan.ac.kr/unews/news/notice.aspx?o=R&a_no='+str(int(id)+2468) urls.append(url) for subject_link in subject_links: subject = subject_link.text.strip() subjects.append(subject) for i in range(10): self.tb.append(str(i + 1) + '. ' + subjects[i] + ' (' + '<a href="' + urls[i] + '">링크</a>' + ')')
class PushButton(QWidget): def __init__(self, func): self.func = func self.res = None super(PushButton,self).__init__() self.initUI() def initUI(self): self.syncButton = QPushButton('Sync EMEA Pacfile') self.logButton = QPushButton('Show Status') self.clearButton = QPushButton('Clear Status') self.closeButton = QPushButton('Close Window') self.lcd = QTextBrowser() self.lcd.setFixedHeight(90) self.lcd.setFont(QFont("Microsoft YaHei", 10)) self.syncButton.clicked.connect(self.sync) self.closeButton.clicked.connect(self.close) self.clearButton.clicked.connect(self.clearText) self.logButton.clicked.connect(self.showLog) buttonLayout = QHBoxLayout() buttonLayout.addWidget(self.syncButton) buttonLayout.addWidget(self.logButton) buttonLayout.addWidget(self.clearButton) buttonLayout.addWidget(self.closeButton) mainLayout = QVBoxLayout() mainLayout.addLayout(buttonLayout) mainLayout.addWidget(self.lcd) self.setLayout(mainLayout) self.setWindowTitle("PushButton_test") self.show() def sync(self): self.res = 'process' self.res = self.func() logger.warning('End: Sync process finish') def clearText(self): self.lcd.clear() def showLog(self): res_mesg = { 'fail': 'Fail to sync, please check log file', 'success': 'Sync finish, please verify', 'process': 'Sync is in process, please wait', None: 'Sync has not start, please click "Sync EMEA Pacfile"' } self.lcd.setText(res_mesg[self.res])
class MyApp(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.le = QLineEdit() self.le.returnPressed.connect(self.append_text) self.tb = QTextBrowser() self.tb.setAcceptRichText(True) self.tb.setOpenExternalLinks(True) self.clear_btn = QPushButton('Clear') self.clear_btn.pressed.connect(self.clear_text) self.lbl1 = QLabel('Enter your sentence:') self.te = QTextEdit() self.te.setAcceptRichText(False) self.lbl2 = QLabel('The number of words is 0') self.te.textChanged.connect(self.text_changed) layout = QHBoxLayout() vbox1 = QVBoxLayout() vbox1.addWidget(self.lbl1) vbox1.addWidget(self.te) vbox1.addWidget(self.lbl2) vbox1.addStretch() vbox = QVBoxLayout() vbox.addWidget(self.le, 0) vbox.addWidget(self.tb, 1) vbox.addWidget(self.clear_btn, 2) layout.addLayout(vbox) layout.addLayout(vbox1) self.setLayout(layout) self.setWindowTitle('으에에ㅔ') self.setGeometry(300, 300, 700, 800) self.show() def append_text(self): text = self.le.text() self.tb.append(text) self.le.clear() def clear_text(self): self.tb.clear() def text_changed(self): text = self.te.toPlainText() self.lbl2.setText('The number of words is ' + str(len(text.split())))
class MyApp(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.le = QLineEdit() self.le.setPlaceholderText('yymmdd') self.le.returnPressed.connect(self.crawl_news) self.btn = QPushButton('Start') self.btn.clicked.connect(self.crawl_news) self.lbl = QLabel('날짜를 입력하세요.') self.tb = QTextBrowser() self.tb.setAcceptRichText(True) self.tb.setOpenExternalLinks(True) grid = QGridLayout() grid.addWidget(self.le, 0, 0, 1, 3) grid.addWidget(self.btn, 0, 3, 1, 1) grid.addWidget(self.lbl, 1, 0, 1, 4) grid.addWidget(self.tb, 2, 0, 1, 4) self.setLayout(grid) self.setWindowTitle('Web Crawler') self.setGeometry(100, 100, 450, 650) self.show() def crawl_news(self): date = self.le.text() if date: self.lbl.setText('[20' + str(date) + '] 많이 본 뉴스입니다.') self.tb.clear() url_news = 'https://news.naver.com' url = url_news + '/main/ranking/popularDay.nhn?rankingType=popular_day&date=20' + date r = requests.get(url) html = r.content soup = BeautifulSoup(html, 'html.parser') titles_html = soup.select( '.ranking_section > ol > li > dl > dt > a') for i in range(len(titles_html)): title = titles_html[i].text link = url_news + titles_html[i].get('href') self.tb.append( str(i + 1) + '. ' + title + ' (' + '<a href="' + link + '">링크</a>' + ')')
class ImportTab(QWidget): def __init__(self, parent=None): super(self.__class__, self).__init__(parent) self.left = 10 self.top = 10 self.width = STANDARD_W self.height = STANDARD_H self.setGeometry(self.left, self.top, self.width, self.height) self.setUI() def setUI(self): self.setWindowTitle('Import Data') self.vbox_layout = QVBoxLayout() self.firstrade_CSV_import_btn = QPushButton( "Import Firstrade standard account CSV file") self.text_browser = QTextBrowser() self.vbox_layout.addWidget(self.firstrade_CSV_import_btn) self.vbox_layout.addWidget(self.text_browser) self.setLayout(self.vbox_layout) # finally self.firstrade_CSV_import_btn.clicked.connect( partial( self._import_data, title="Import Firstrade standard account history CSV file")) def _import_data(self, title): self.text_browser.clear() filepath = self._file_selector(title) self.text_browser.append( "Ready to import data, source from '{}'".format(filepath)) try: success_count = FTDB.importFTStandardCSV(filepath, self.text_browser) self.text_browser.append( "Successful importing: {}".format(success_count)) self.text_browser.append("Import done.".format()) except (TypeError, FileNotFoundError) as err: self.text_browser.append( "Invalid filepath (given: '{}'), please select again. (error msg: {})" .format(filepath, err)) except Exception as err: self.text_browser.append("Import Error: {}".format(err)) self.text_browser.append("{}".format(traceback.format_exc())) def _file_selector(self, title): fp = FileHandler(title) filepath = fp.openFileNameDialog() fp.show() fp.deleteLater() return filepath
class CrawlWindows(QWidget): def __init__(self): super(CrawlWindows, self).__init__() self.resize(600, 300) self.setWindowIcon(QIcon(':icons/favicon.ico')) self.setWindowTitle('Books to scrape (http://books.toscrape.com)') self.ua_line = QLineEdit(self) self.obey_combo = QComboBox(self) self.obey_combo.addItems(['Yes', 'No']) # self.save_location = QLineEdit(self) self.log_browser = QTextBrowser(self) self.crawl_button = QPushButton('Start crawl', self) self.crawl_button.clicked.connect( lambda: self.crawl_slot(self.crawl_button)) self.h_layout = QHBoxLayout() self.v_layout = QVBoxLayout() self.h_layout.addWidget(QLabel('Input User-Agent:')) self.h_layout.addWidget(self.ua_line) # self.h_layout.addWidget(QLabel('Save path')) # self.h_layout.addWidget(self.save_location) self.h_layout.addWidget(QLabel('Robot protocol:')) self.h_layout.addWidget(self.obey_combo) self.v_layout.addLayout(self.h_layout) self.v_layout.addWidget(QLabel('Output log box:')) self.v_layout.addWidget(self.log_browser) self.v_layout.addWidget(self.crawl_button) self.setLayout(self.v_layout) self.p = None self.Q = Manager().Queue() self.log_thread = LogThread(self) def crawl_slot(self, button): if button.text() == 'Start crawl': self.log_browser.clear() self.crawl_button.setText('Stop crawl') ua = self.ua_line.text().strip() is_obey = True if self.obey_combo.currentText() == 'Yes' else False # save_location = self.save_location.text().strip() self.p = Process(target=crawl_run, args=(self.Q, ua, is_obey)) self.log_browser.setText('The collection process is starting...') self.p.start() self.log_thread.start() else: self.crawl_button.setText('Start crawl') self.p.terminate() self.log_thread.terminate()
class MyApp(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.le = QLineEdit() self.le.returnPressed.connect(self.append_text) # 줄편집기 하나를 만들었습니다. # # Enter키를 누르면 append_text 메서드가 호출됩니다. self.tb = QTextBrowser() self.tb.setAcceptRichText(True) self.tb.setOpenExternalLinks(True) # QTextBrowser() 클래스를 이용해서 텍스트 브라우저를 하나 만들었습니다. # # setAcceptRichText()를 True로 설정해주면, 서식 있는 텍스트 # (Rich text)를 사용할 수 있습니다. # # 디폴트로 True이기 때문에 없어도 되는 부분입니다. # # setOpenExternalLinks()를 True로 설정해주면, 외부 링크로의 연결이 가능합니다. self.clear_btn = QPushButton('Clear') self.clear_btn.pressed.connect(self.clear_text) # clear_btn을 클릭하면, clear_text 메서드가 호출됩니다. vbox = QVBoxLayout() vbox.addWidget(self.le, 0) vbox.addWidget(self.tb, 1) vbox.addWidget(self.clear_btn, 2) self.setLayout(vbox) self.setWindowTitle('QTextBrowser') self.setGeometry(300, 300, 300, 300) self.show() def append_text(self): text = self.le.text() self.tb.append(text) self.le.clear() # append_text 메서드는 줄편집기에 작성된 텍스트 # (self.le.text())를 텍스트 브라우저 (self.tb)에 append 해주는 기능을 합니다. # # 텍스트가 텍스트 브라우저에 추가되면, clear 메서드를 이용해서 줄편집기에 있던 # 텍스트는 없애줍니다. def clear_text(self): self.tb.clear()
class DebugInfo(QDockWidget): def __init__(self, parent=None): super(DebugInfo, self).__init__() self.head_info = None self.setWindowTitle('日志') self.setFeatures(QDockWidget.NoDockWidgetFeatures | QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable) self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.dock_widget_contents = QWidget() self.setWidget(self.dock_widget_contents) self.info_text_browser = QTextBrowser(self.dock_widget_contents) self.info_text_browser.setReadOnly(True) self.horizontal_spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.clear_button = QPushButton("清除记录", self.dock_widget_contents) self.hLayout = QHBoxLayout() self.hLayout.addItem(self.horizontal_spacer) self.hLayout.addWidget(self.clear_button) self.vLayout = QVBoxLayout(self.dock_widget_contents) self.vLayout.setSpacing(4) self.vLayout.setContentsMargins(4, 4, 4, 4) self.vLayout.addWidget(self.info_text_browser) self.vLayout.addLayout(self.hLayout) self.clear_button.clicked.connect(self.clear) # self.dock_widget_contents.setMinimumWidth(300) def set_head_info(self, head_info): self.head_info = head_info self.clear() def set_text_browser(self, text_info): pass def clear(self): self.info_text_browser.clear() if self.head_info is not None: self.info_text_browser.append(self.head_info) h = self.height() w = self.width() self.resize(w, 10) self.resize(w, h)
class MyApp(QWidget): def __init__(self): super().__init__() self.icon = dir_icon + 'icon_qt.png' self.title = 'Ex5.19_QTextBrowser' self.posXY = (600, 45) self.windowSize = (300, 300) self.initUI() self.showBasic() def initUI(self): lb1 = QLabel('TEXT HISTORY :') lb2 = QLabel('TYPE & ENTER to Store ABOVE!') self.le = QLineEdit() self.le.returnPressed.connect(self.append_text) self.tb = QTextBrowser() self.tb.setAcceptRichText(True) self.tb.setOpenExternalLinks(True) clear_btn = QPushButton('Clear') clear_btn.pressed.connect(self.clear_text) vbox = QVBoxLayout() vbox.addWidget(lb1) vbox.addWidget(self.tb, 1) vbox.addWidget(lb2) vbox.addWidget(self.le, 0) vbox.addWidget(clear_btn, 2) self.setLayout(vbox) def showBasic(self): """Basci Attribution & Geometry display""" self.setWindowIcon(QIcon(self.icon)) self.setWindowTitle(self.title) self.setGeometry(*self.posXY, *self.windowSize) self.show() def append_text(self): """CallBack() When le.returnPressed.connect""" text = self.le.text() self.tb.append(text) self.le.clear() def clear_text(self): """CallBack() When clear_btn.pressed.connect""" self.tb.clear()
class LogWidget(QWidget, MooseWidget): """ A widget that shows the log. This ties into mooseutils.message.mooseMessage which will emit a signal on mooseutils.message.messageEmitter This widget listens to messageEmitter and puts the text in the widget. Color text is supported. """ def __init__(self, **kwds): """ Constructor. """ super(LogWidget, self).__init__(**kwds) self.top_layout = WidgetUtils.addLayout(vertical=True) self.setLayout(self.top_layout) self.log = QTextBrowser(self) self.log.setStyleSheet( "QTextBrowser { background: black; color: white; }") self.log.setReadOnly(True) message.messageEmitter.message.connect(self._write) self.button_layout = WidgetUtils.addLayout() self.hide_button = WidgetUtils.addButton(self.button_layout, self, "Hide", lambda: self.hide()) self.clear_button = WidgetUtils.addButton(self.button_layout, self, "Clear", lambda: self.log.clear()) self.top_layout.addWidget(self.log) self.top_layout.addLayout(self.button_layout) self.resize(800, 500) @pyqtSlot(str, str) def _write(self, msg, color): """ This is the slot that will write the message to the widget. Inputs: msg: The message to write color: The color to write the text in. """ if not msg: return msg = msg.encode( 'utf-8' ) # make sure if there are bad characters in the message that we can show them. if not color or color == "None": color = "white" else: color = str(color) if msg.find("\n") >= 0: self.log.insertHtml( '<div style="color:%s"><pre><code>%s</code></pre></div><br>' % (color.lower(), escape(msg))) else: self.log.insertHtml('<div style="color:%s">%s</div><br>' % (color.lower(), escape(msg)))
class ConsoleWidget(QDialog): _close_single = pyqtSignal() _send_command = pyqtSignal(str) def __init__(self, *args, **kwargs): super(ConsoleWidget, self).__init__(*args, **kwargs) self.width_height = 300, 700 self.resize(*self.width_height) self.setFixedSize(*self.width_height) self.setWindowTitle('Super Continent Console') self.text_browser = QTextBrowser(parent=self) self.line_edit = QLineEdit(parent=self) self.line_edit.returnPressed.connect(self.command) self.init() self.connect_slot() self.show() def closeEvent(self, a0: QCloseEvent) -> None: self._close_single.emit() def init(self): layout = QVBoxLayout(self) layout.addWidget(self.text_browser) layout.addWidget(self.line_edit) self.setLayout(layout) def connect_slot(self): parent = self.parent() self._close_single.connect(parent.close_console_dialog) self._send_command.connect(parent.print_command) def command(self): cmd = self.line_edit.text() self.line_edit.clear() match cmd: case 'clear': self.text_browser.clear() case 'close': self.close() case _: self.text_browser.append(cmd) self._send_command.emit(cmd)
class MyTextBrowser(QGroupBox): def __init__(self): super().__init__() self.setTitle('QTextBrowser') self.init_ui() def init_ui(self): self.le = QLineEdit() self.le.returnPressed.connect(self.append_text) self.tb = QTextBrowser() self.tb.setAcceptRichText(True) self.tb.setOpenExternalLinks(True) self.clear_btn = QPushButton('Clear') self.clear_btn.pressed.connect(self.clear_text) self.init_text() layout = QVBoxLayout() layout.addWidget(self.le) layout.addWidget(self.tb) layout.addWidget(self.clear_btn) self.setLayout(layout) def init_text(self): texts = [ '<i>Italic</i>', '<p style="color: red">Red</p>', '<p style="font-size: 20px">20px</p>', '<a href="https://www.naver.com">Naver</a>' ] for t in texts: self.tb.append(t) def append_text(self): text = self.le.text() self.tb.append(text) self.le.clear() def clear_text(self): self.tb.clear()
class MyApp(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.le = QLineEdit() # QLineEdit() : HTML 태그형태로 입력할 수 있는 한 줄 짜리 입력창 self.le.returnPressed.connect( self.append_text ) # 키보드에 엔터가 눌렸는지 안눌렸는지 알아내는 returnPressed.엔터를 누르면 값을 append_text로 전달 self.tb = QTextBrowser() # 태그를 해석해서 출력시켜줄 텍스트브라우저 객체 생성 self.tb.setAcceptRichText( True ) # 텍스트 브라우저에 출력된 글씨들을 복사한다던지, 이와 같이 해당 글자를 접근 가능하게 할거면 True, 막을거면 False self.tb.setOpenExternalLinks( True) # 외부 브라우저로 접속해야 하기 때문에 외부링크 허용 True, 허용하지 않으면 False self.clear_btn = QPushButton('Clear') # 버튼 생성(버튼에 쓰일 값은 Clear) self.clear_btn.pressed.connect( self.clear_text) # 버튼이 눌려지면 clear_text 함수 호출 vbox = QVBoxLayout() # 박스 객체 생성 vbox.addWidget(self.le, 0) # 0행에 위젯 달기 vbox.addWidget(self.tb, 1) # 1행에 위젯 달기 vbox.addWidget(self.clear_btn, 2) # 2행에 버튼 달기 self.setLayout(vbox) self.setWindowTitle('QTextBrowser') self.setGeometry(300, 300, 300, 300) self.show() def append_text(self): #텍스트 브라우저에 추가시킬 함수 text = self.le.text() # 입력받은 self의 text값을 얻어내서 text 변수에 저장 self.tb.append(text) # 텍스트박스에 append 시킨다.(text값을 append) self.le.clear() # 라인 데이터에 쓰여진 있는 값은 클리어시킨다. def clear_text(self): # 버튼눌렀을 때 모두 clear해줄 함수 self.tb.clear() # tb, le 모두, te 에도 clear 함수가 있다.
class 확장된글편집기(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.line_edit = QLineEdit() self.line_edit.returnPressed.connect(self.addText) self.btn_add = QPushButton('입력') self.btn_add.clicked.connect(self.addText) self.tb = QTextBrowser() self.tb.setAcceptRichText(True) self.tb.setOpenExternalLinks(True) self.tb.append('일반 플래인 텍스트입니다.') self.tb.setAlignment(Qt.AlignCenter) self.btn_clear = QPushButton('지우기') self.btn_clear.clicked.connect(self.clearText) vbox = QVBoxLayout() vbox.addWidget(self.line_edit) vbox.addWidget(self.tb) vbox.addWidget(self.btn_add) vbox.addWidget(self.btn_clear) self.setLayout(vbox) self.setWindowTitle('QTextBrowser') self.setGeometry(300, 300, 300, 400) self.show() def addText(self): text = self.line_edit.text() self.tb.append(text) self.line_edit.clear() def clearText(self): self.tb.clear()
class PythonLyrics(QWidget): def __init__(self): super(PythonLyrics, self).__init__() self.lyrics = Lyrics() self.init_ui() def init_ui(self): self.text = QTextBrowser(self) self.text.setText(self.lyrics.get_lyrics()) self.text.setLineWrapMode(QTextBrowser.NoWrap) self.text.setReadOnly(True) self.text.setOpenExternalLinks(True) self.info = QLabel(self) self.info.setText(self.lyrics.get_artist() + ' ' + self.lyrics.get_song()) vbox = QVBoxLayout() vbox.addWidget(self.info) vbox.addWidget(self.text) self.setWindowTitle('PythonLyrics') self.setGeometry(700, 200, 605, 700) self.setLayout(vbox) self.show() def refresh(self): if self.lyrics.update(): self.text.clear() self.text.setText(self.lyrics.get_lyrics()) self.info.clear() self.info.setText(self.lyrics.get_artist() + ' ' + self.lyrics.get_song())
class MyApp(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.le = QLineEdit() #태그포함 한줄 입력 받기위한 매머드 self.le.returnPressed.connect(self.append_text) # 엔터키를 눌렀을때(returnPressed) 함수 호출 및 값 자동 전달 self.tb = QTextBrowser() #html 해석할수 있는 객체 생성 self.tb.setAcceptRichText(True) #글자들을 접근 가능하게 서식있는 텍스트 (RichText) 를 사용 self.tb.setOpenExternalLinks(True) #링크를 눌렀을떄 외부와 연결되야 하기때문에 True self.clear_btn = QPushButton('Clear') # 클릭했을때 목록을 다 지워주기 위한 버튼 생성 self.clear_btn.pressed.connect(self.clear_text) # 버튼이 눌려지면 clear_text함수 호출 vbox = QVBoxLayout() # 한줄씩 차곡차곡 내려주기 위해 VBoxLayout 객체 생성 vbox.addWidget(self.le, 0) # addWidget만 쓰면 하나씩 차곡차곡 쌓이는데 vbox.addWidget(self.tb, 1) # 2번쨰 인자로 위치값을 수동으로 지정 해 줄 수 도 있다. vbox.addWidget(self.clear_btn, 2) self.setLayout(vbox) self.setWindowTitle('QTextBrowser') self.setGeometry(300, 300, 300, 300) self.show() def append_text(self): #한줄 입력을 하면 텍스트 브라우저에 보여주고 라인은 지운다. text = self.le.text() self.tb.append(text) self.le.clear() #.clear() 은 TestLine, TextBorwser, TextEdit 모두 있다. def clear_text(self): #버튼 클릭했을때 텍스트 브라우저에있는 입력값 초기화 self.tb.clear()
class Widget(QWidget): def __init__(self, panel): super(Widget, self).__init__(panel) layout = QVBoxLayout() self.setLayout(layout) layout.setSpacing(0) self.searchEntry = SearchLineEdit() self.treeView = QTreeView(contextMenuPolicy=Qt.CustomContextMenu) self.textView = QTextBrowser() applyButton = QToolButton(autoRaise=True) editButton = QToolButton(autoRaise=True) addButton = QToolButton(autoRaise=True) self.menuButton = QPushButton(flat=True) menu = QMenu(self.menuButton) self.menuButton.setMenu(menu) splitter = QSplitter(Qt.Vertical) top = QHBoxLayout() layout.addLayout(top) splitter.addWidget(self.treeView) splitter.addWidget(self.textView) layout.addWidget(splitter) splitter.setSizes([200, 100]) splitter.setCollapsible(0, False) top.addWidget(self.searchEntry) top.addWidget(applyButton) top.addSpacing(10) top.addWidget(addButton) top.addWidget(editButton) top.addWidget(self.menuButton) # action generator for actions added to search entry def act(slot, icon=None): a = QAction(self, triggered=slot) self.addAction(a) a.setShortcutContext(Qt.WidgetWithChildrenShortcut) icon and a.setIcon(icons.get(icon)) return a # hide if ESC pressed in lineedit a = act(self.slotEscapePressed) a.setShortcut(QKeySequence(Qt.Key_Escape)) # import action a = self.importAction = act(self.slotImport, 'document-open') menu.addAction(a) # export action a = self.exportAction = act(self.slotExport, 'document-save-as') menu.addAction(a) # apply button a = self.applyAction = act(self.slotApply, 'edit-paste') applyButton.setDefaultAction(a) menu.addSeparator() menu.addAction(a) # add button a = self.addAction_ = act(self.slotAdd, 'list-add') a.setShortcut(QKeySequence(Qt.Key_Insert)) addButton.setDefaultAction(a) menu.addSeparator() menu.addAction(a) # edit button a = self.editAction = act(self.slotEdit, 'document-edit') a.setShortcut(QKeySequence(Qt.Key_F2)) editButton.setDefaultAction(a) menu.addAction(a) # set shortcut action a = self.shortcutAction = act( self.slotShortcut, 'preferences-desktop-keyboard-shortcuts') menu.addAction(a) # delete action a = self.deleteAction = act(self.slotDelete, 'list-remove') a.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_Delete)) menu.addAction(a) # restore action a = self.restoreAction = act(self.slotRestore) menu.addSeparator() menu.addAction(a) # help button a = self.helpAction = act(self.slotHelp, 'help-contents') menu.addSeparator() menu.addAction(a) self.treeView.setSelectionBehavior(QTreeView.SelectRows) self.treeView.setSelectionMode(QTreeView.ExtendedSelection) self.treeView.setRootIsDecorated(False) self.treeView.setAllColumnsShowFocus(True) self.treeView.setModel(model.model()) self.treeView.setCurrentIndex(QModelIndex()) # signals self.searchEntry.returnPressed.connect(self.slotReturnPressed) self.searchEntry.textChanged.connect(self.updateFilter) self.treeView.doubleClicked.connect(self.slotDoubleClicked) self.treeView.customContextMenuRequested.connect(self.showContextMenu) self.treeView.selectionModel().currentChanged.connect(self.updateText) self.treeView.model().dataChanged.connect(self.updateFilter) # highlight text self.highlighter = highlight.Highlighter(self.textView.document()) # complete on snippet variables self.searchEntry.setCompleter( QCompleter([ ':icon', ':indent', ':menu', ':name', ':python', ':selection', ':set', ':symbol', ':template', ':template-run' ], self.searchEntry)) self.readSettings() app.settingsChanged.connect(self.readSettings) app.translateUI(self) self.updateColumnSizes() self.setAcceptDrops(True) def dropEvent(self, ev): if not ev.source() and ev.mimeData().hasUrls(): filename = ev.mimeData().urls()[0].toLocalFile() if filename: ev.accept() from . import import_export import_export.load(filename, self) def dragEnterEvent(self, ev): if not ev.source() and ev.mimeData().hasUrls(): ev.accept() def translateUI(self): try: self.searchEntry.setPlaceholderText(_("Search...")) except AttributeError: pass # not in Qt 4.6 shortcut = lambda a: a.shortcut().toString(QKeySequence.NativeText) self.menuButton.setText(_("&Menu")) self.addAction_.setText(_("&Add...")) self.addAction_.setToolTip( _("Add a new snippet. ({key})").format( key=shortcut(self.addAction_))) self.editAction.setText(_("&Edit...")) self.editAction.setToolTip( _("Edit the current snippet. ({key})").format( key=shortcut(self.editAction))) self.shortcutAction.setText(_("Configure Keyboard &Shortcut...")) self.deleteAction.setText(_("&Remove")) self.deleteAction.setToolTip(_("Remove the selected snippets.")) self.applyAction.setText(_("A&pply")) self.applyAction.setToolTip(_("Apply the current snippet.")) self.importAction.setText(_("&Import...")) self.importAction.setToolTip(_("Import snippets from a file.")) self.exportAction.setText(_("E&xport...")) self.exportAction.setToolTip(_("Export snippets to a file.")) self.restoreAction.setText(_("Restore &Built-in Snippets...")) self.restoreAction.setToolTip( _("Restore deleted or changed built-in snippets.")) self.helpAction.setText(_("&Help")) self.searchEntry.setToolTip( _("Enter text to search in the snippets list.\n" "See \"What's This\" for more information.")) self.searchEntry.setWhatsThis(''.join( map("<p>{0}</p>\n".format, ( _("Enter text to search in the snippets list, and " "press Enter to apply the currently selected snippet."), _("If the search text fully matches the value of the '{name}' variable " "of a snippet, that snippet is selected.").format( name="name"), _("If the search text starts with a colon ':', the rest of the " "search text filters snippets that define the given variable. " "After a space a value can also be entered, snippets will then " "match if the value of the given variable contains the text after " "the space."), _("E.g. entering {menu} will show all snippets that are displayed " "in the insert menu.").format(menu="<code>:menu</code>"), )))) def sizeHint(self): return self.parent().mainwindow().size() / 4 def readSettings(self): data = textformats.formatData('editor') self.textView.setFont(data.font) self.textView.setPalette(data.palette()) def showContextMenu(self, pos): """Called when the user right-clicks the tree view.""" self.menuButton.menu().popup(self.treeView.viewport().mapToGlobal(pos)) def slotReturnPressed(self): """Called when the user presses Return in the search entry. Applies current snippet.""" name = self.currentSnippet() if name: view = self.parent().mainwindow().currentView() insert.insert(name, view) self.parent().hide() # make configurable? view.setFocus() def slotEscapePressed(self): """Called when the user presses ESC in the search entry. Hides the panel.""" self.parent().hide() self.parent().mainwindow().currentView().setFocus() def slotDoubleClicked(self, index): name = self.treeView.model().name(index) view = self.parent().mainwindow().currentView() insert.insert(name, view) def slotAdd(self): """Called when the user wants to add a new snippet.""" edit.Edit(self, None) def slotEdit(self): """Called when the user wants to edit a snippet.""" name = self.currentSnippet() if name: edit.Edit(self, name) def slotShortcut(self): """Called when the user selects the Configure Shortcut action.""" from widgets import shortcuteditdialog name = self.currentSnippet() if name: collection = self.parent().snippetActions action = actions.action(name, None, collection) default = collection.defaults().get(name) mgr = actioncollectionmanager.manager(self.parent().mainwindow()) cb = mgr.findShortcutConflict dlg = shortcuteditdialog.ShortcutEditDialog( self, cb, (collection, name)) if dlg.editAction(action, default): mgr.removeShortcuts(action.shortcuts()) collection.setShortcuts(name, action.shortcuts()) self.treeView.update() def slotDelete(self): """Called when the user wants to delete the selected rows.""" rows = sorted(set(i.row() for i in self.treeView.selectedIndexes()), reverse=True) if rows: for row in rows: name = self.treeView.model().names()[row] self.parent().snippetActions.setShortcuts(name, []) self.treeView.model().removeRow(row) self.updateFilter() def slotApply(self): """Called when the user clicks the apply button. Applies current snippet.""" name = self.currentSnippet() if name: view = self.parent().mainwindow().currentView() insert.insert(name, view) def slotImport(self): """Called when the user activates the import action.""" filetypes = "{0} (*.xml);;{1} (*)".format(_("XML Files"), _("All Files")) caption = app.caption(_("dialog title", "Import Snippets")) filename = None filename = QFileDialog.getOpenFileName(self, caption, filename, filetypes)[0] if filename: from . import import_export import_export.load(filename, self) def slotExport(self): """Called when the user activates the export action.""" allrows = [ row for row in range(model.model().rowCount()) if not self.treeView.isRowHidden(row, QModelIndex()) ] selectedrows = [ i.row() for i in self.treeView.selectedIndexes() if i.column() == 0 and i.row() in allrows ] names = self.treeView.model().names() names = [names[row] for row in selectedrows or allrows] filetypes = "{0} (*.xml);;{1} (*)".format(_("XML Files"), _("All Files")) n = len(names) caption = app.caption( _("dialog title", "Export {num} Snippet", "Export {num} Snippets", n).format(num=n)) filename = QFileDialog.getSaveFileName(self, caption, None, filetypes)[0] if filename: from . import import_export try: import_export.save(names, filename) except (IOError, OSError) as e: QMessageBox.critical( self, _("Error"), _("Can't write to destination:\n\n{url}\n\n{error}"). format(url=filename, error=e.strerror)) def slotRestore(self): """Called when the user activates the Restore action.""" from . import restore dlg = restore.RestoreDialog(self) dlg.setWindowModality(Qt.WindowModal) dlg.populate() dlg.show() dlg.finished.connect(dlg.deleteLater) def slotHelp(self): """Called when the user clicks the small help button.""" userguide.show("snippets") def currentSnippet(self): """Returns the name of the current snippet if it is visible.""" row = self.treeView.currentIndex().row() if row != -1 and not self.treeView.isRowHidden(row, QModelIndex()): return self.treeView.model().names()[row] def updateFilter(self): """Called when the text in the entry changes, updates search results.""" text = self.searchEntry.text() ltext = text.lower() filterVars = text.startswith(':') if filterVars: try: fvar, fval = text[1:].split(None, 1) fhide = lambda v: v.get(fvar) in (True, None ) or fval not in v.get(fvar) except ValueError: fvar = text[1:].strip() fhide = lambda v: not v.get(fvar) for row in range(self.treeView.model().rowCount()): name = self.treeView.model().names()[row] nameid = snippets.get(name).variables.get('name', '') if filterVars: hide = fhide(snippets.get(name).variables) elif nameid == text: i = self.treeView.model().createIndex(row, 0) self.treeView.selectionModel().setCurrentIndex( i, QItemSelectionModel.SelectCurrent | QItemSelectionModel.Rows) hide = False elif nameid.lower().startswith(ltext): hide = False elif ltext in snippets.title(name).lower(): hide = False else: hide = True self.treeView.setRowHidden(row, QModelIndex(), hide) self.updateText() def updateText(self): """Called when the current snippet changes.""" name = self.currentSnippet() self.textView.clear() if name: s = snippets.get(name) self.highlighter.setPython('python' in s.variables) self.textView.setPlainText(s.text) def updateColumnSizes(self): self.treeView.resizeColumnToContents(0) self.treeView.resizeColumnToContents(1)
class DY(QTabWidget): def __init__(self, parent = None): super(DY, self).__init__(parent) self.tab1 = QWidget() self.tab2 = QWidget() self.addTab(self.tab1,"Indeed Search") self.addTab(self.tab2,"Bookmarked") self.searchtab() self.bookmarktab() self.setWindowTitle("Job Crawler") self.setGeometry(100, 100, 800, 800) self.show() def searchtab(self): layout = QGridLayout() self.enter = QLineEdit() self.enter.setPlaceholderText('Enter the Search Word') self.enter.returnPressed.connect(self.crawl_indeed) self.cb = QComboBox() self.cb.addItem('See All') self.cb.addItem('Internship') self.cb.addItem('Full-time') self.cb.addItem('Part-time') self.cb.activated[str].connect(self.onActivated) self.button = QPushButton('Serach') self.button.clicked.connect(self.crawl_indeed) self.label = QLabel('') self.label.resize(1,1) self.tb = QTextBrowser() self.tb.setAcceptRichText(True) self.tb.setOpenExternalLinks(True) layout.addWidget(self.enter, 0, 0, 1, 3) layout.addWidget(self.cb, 0, 3, 1 ,1) layout.addWidget(self.button, 0, 4, 1, 1) layout.addWidget(self.label, 1, 0, 1, 5) layout.addWidget(self.tb, 2, 0, 1, 5) self.tab1.setLayout(layout) def onActivated(self, text): self.label.setText(text) self.label.adjustSize() def crawl_indeed(self): search_word = self.enter.text() search_filter = self.cb.currentText() if search_word: self.label.setText('Recently Added on Indeed for "' + search_word + '"') self.tb.clear() url_search = 'https://www.indeed.com/jobs?q=' if search_filter == 'See All': url = url_search + search_word elif search_filter == 'Internship': url = url_search + search_word + '&jt=internship' elif search_filter == 'Full-time': url = url_search + search_word + '&jt=fulltime' elif search_filter == 'Part-time': url = url_search + search_word + '&jt=parttime' response = requests.get(url) html = response.content soup = BeautifulSoup(html, 'html.parser') job = soup.select('#resultsCol > div > .title > a') comp = soup.select('#resultsCol > div > .sjcl > div > .company') loc = soup.select('#resultsCol > div > .sjcl > span') for i in range(len(job)): title = job[i].text company = comp[i].text loca = loc[i].text self.tb.append(str(i+1) + '. ' + title.strip() + '\n ' + company.strip() + ', ' + loca.strip() +'\n') def bookmarktab(self): name = QLabel('Company Name:') nameedit = QLineEdit() location = QLabel('Location:') locedit = QLineEdit() note = QLabel('Note:') noteedit = QTextEdit() vbox = QVBoxLayout() vbox.addWidget(name) vbox.addWidget(nameedit) vbox.addWidget(location) vbox.addWidget(locedit) vbox.addWidget(note) vbox.addWidget(noteedit) vbox.addStretch() self.tab2.setLayout(vbox)
class DocumentationViewerWidget(QWidget): """ Class implementing a rich text documentation viewer. """ def __init__(self, parent=None): """ Constructor @param parent reference to the parent widget @type QWidget """ super(DocumentationViewerWidget, self).__init__(parent) self.setObjectName("DocumentationViewerWidget") self.__verticalLayout = QVBoxLayout(self) self.__verticalLayout.setObjectName("verticalLayout") self.__verticalLayout.setContentsMargins(0, 0, 0, 0) try: from PyQt5.QtWebEngineWidgets import (QWebEngineView, QWebEngineSettings) self.__contents = QWebEngineView(self) self.__contents.page().linkHovered.connect(self.__showLink) try: self.__contents.settings().setAttribute( QWebEngineSettings.FocusOnNavigationEnabled, False) except AttributeError: # pre Qt 5.8 pass self.__viewerType = "QWebEngineView" except ImportError: self.__contents = QTextBrowser(self) self.__contents.setOpenExternalLinks(True) self.__viewerType = "QTextEdit" sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.__contents.sizePolicy().hasHeightForWidth()) self.__contents.setSizePolicy(sizePolicy) self.__contents.setContextMenuPolicy(Qt.NoContextMenu) if self.__viewerType != "QTextEdit": self.__contents.setUrl(QUrl("about:blank")) self.__verticalLayout.addWidget(self.__contents) self.__searchWidget = E5TextEditSearchWidget(self, False) self.__searchWidget.setFocusPolicy(Qt.WheelFocus) self.__searchWidget.setObjectName("searchWidget") self.__verticalLayout.addWidget(self.__searchWidget) self.__searchWidget.attachTextEdit(self.__contents, self.__viewerType) @pyqtSlot(str) def __showLink(self, urlStr): """ Private slot to show the hovered link in a tooltip. @param urlStr hovered URL @type str """ QToolTip.showText(QCursor.pos(), urlStr, self.__contents) def setHtml(self, html): """ Public method to set the HTML text of the widget. @param html HTML text to be shown @type str """ self.__contents.setEnabled(False) self.__contents.setHtml(html) self.__contents.setEnabled(True) def clear(self): """ Public method to clear the shown contents. """ if self.__viewerType == "QTextEdit": self.__contents.clear() else: self.__contents.setHtml("")
class ConsoleWindow(QMainWindow): global textEdit def __init__(self, parent=None): super(ConsoleWindow, self).__init__(parent) self.isConUrl = False # 上 self.searchButton = QLineEdit() self.searchButton.setPlaceholderText("搜索") self.searchButton.setMaximumWidth(300) self.searchButton.setMaximumHeight(32) self.searchButton.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Minimum) self.combo = QComboBox(self) self.combo.insertItem(0, 'Error') self.combo.insertItem(1, 'Debug') self.combo.insertItem(2, 'Verbose') self.combo.insertItem(3, 'Warning') self.combo.setCurrentIndex(0) layout_top = QHBoxLayout() layout_top.setAlignment(Qt.AlignRight) layout_top.setSpacing(20) # layout_top.addWidget(self.combo) # layout_top.addWidget(self.searchButton) self.functionTabWiget = QWidget() self.functionTabWiget.setAutoFillBackground(True) self.functionTabWiget.setFixedHeight(20) self.functionTabWiget.setLayout(layout_top) # 左 self.clearButton = QPushButton(self) icon = QIcon(IconTool.buildQIcon('clear.png')) self.clearButton.setIcon(icon) self.clearButton.setFixedWidth(18) self.clearButton.setFixedHeight(20) self.clearButton.clicked.connect(self.clear) self.clearButton.setToolTip("Clear the logcat") self.setStyleSheet(''' QPushButton{ border: none; background-color: #0000 ; } QPushButton:hover { border: 1px solid #C0C0C0; background-color: yellow; border-style: inset; border-radius:2px; background-color:#C0C0C0; border-style: solid; } ''') self.layoutLeft = QVBoxLayout() self.layoutLeft.setAlignment(Qt.AlignTop) self.layoutLeft.setSpacing(1) self.layoutLeft.addWidget(self.clearButton) self.layoutLeft.setContentsMargins(4, 0, 0, 0) self.leftWiget = QWidget() self.leftWiget.setAutoFillBackground(True) self.leftWiget.setLayout(self.layoutLeft) self.leftWiget.setFixedWidth(22) # 右 self.textEdit = QTextBrowser() self.textEdit.setOpenLinks(True) self.textEdit.setOpenExternalLinks(True) self.textEdit.setReadOnly(True) self.rightWiget = QWidget() self.rightWiget.setAutoFillBackground(True) self.rightWiget.setFixedWidth(15) self.messageSplitter = QSplitter(Qt.Horizontal) self.messageSplitter.addWidget(self.leftWiget) self.messageSplitter.addWidget(self.textEdit) self.messageSplitter.addWidget(self.rightWiget) self.mainSplitter = QSplitter(Qt.Vertical) self.mainSplitter.addWidget(self.functionTabWiget) self.mainSplitter.addWidget(self.messageSplitter) self.setCentralWidget(self.mainSplitter) # 重定向输出 sys.stdout = ConsoleEmittor(textWritten=self.normalOutputWritten) sys.stderr = ConsoleEmittor(textWritten=self.normalOutputWritten) def normalOutputWritten(self, text): cursor = self.textEdit.textCursor() cursor.movePosition(QTextCursor.End) cursor.insertHtml(text) self.textEdit.setTextCursor(cursor) self.textEdit.ensureCursorVisible() def initMenuBar(self): menuBar = self.menuBar() fileMenu = menuBar.addMenu('Logcat') showLogAction = QAction('Show Log', self) fileMenu.addAction(showLogAction) helpMenu = menuBar.addMenu('Setting') aboutAction = QAction(IconTool.buildQIcon('setting.png'), 'About', self) helpMenu.addAction(aboutAction) def clear(self): self.textEdit.clear() return
class MainWindow(QWidget): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) # self.setWindowFlags(Qt.Window | Qt.FramelessWindowHint) # self.setAttribute(Qt.WA_TranslucentBackground) self.resize(900, 700) self.__search_mode = {'fuzzy': 'fuzzy_search', 'precise': 'precise_search', 'reg': 'reg_search'} # self.__pbn_switch_view = None # 创建窗口部件 self.__widget_frame = QLabel() # window title self.__lab_title_fram = QLabel() self.__lab_title = QLabel('搜索辅助工具') self.__lab_title.setAlignment(Qt.AlignCenter) self.__lab_open_tool = QLabel('打开文件方式') self.__ln_open_tool = QLineEdit() self.__pbn_open_tool = QToolButton() self.__pbn_open_tool.setText('选择...') self.__ln_open_tool.setFixedHeight(20) self.__ln_open_tool.setFixedWidth(150) self.__pbn_open_tool.setFixedSize(48, 20) self.__lab_title_fram.setFixedHeight(50) # search mode self.__lab_mode_fram = QLabel() self.__rbn_fuzzy = QRadioButton('模糊搜索') self.__rbn_precise = QRadioButton('精确搜索') self.__rbn_reg = QRadioButton('正则表达式搜索') self.__rbn_fuzzy.setChecked(True) self.__lab_mode_fram.setFixedHeight(22) # search pattern self.__lab_pattern_fram = QLabel() self.__ln_file_name = QLineEdit() self.__ln_file_name.setPlaceholderText('请输入搜索条件或正则表达式......') self.__rbn_reg_Iyes = QRadioButton('区分大小写') self.__rbn_reg_Ino = QRadioButton('不区分大小写') self.__lab_pattern_fram.setFixedHeight(20) # search path self.__lab_path_fram = QLabel() self.__ln_file_path = QLineEdit() self.__ln_file_path.setPlaceholderText('请选择或输入路径......') self.__pbn_file_path = QToolButton() self.__pbn_file_path.setText('浏览...') self.__rbn_search_file = QRadioButton('检索文件名') self.__rbn_search_content = QRadioButton('检索文件内容') self.__pbn_file_path.setFixedSize(48, 20) self.__lab_path_fram.setFixedHeight(20) # search state self.__lab_state_fram = QLabel() self.__lab_state = QLabel('状态:暂无搜索结果!') self.__pbn_search = QPushButton('开始') self.__pbn_stop = QPushButton('停止') self.__pbn_search.setFixedWidth(89) self.__pbn_stop.setFixedWidth(89) self.__lab_state_fram.setFixedHeight(35) # search result self.__tabView = QTabWidget() self.__browser_result = QListWidget() self.__browser_error = QTextBrowser() self.__tabView.addTab(self.__browser_result, '匹配结果') self.__tabView.addTab(self.__browser_error, '错误结果') self.__btn_group_type = QButtonGroup() self.__btn_group_type.addButton(self.__rbn_search_file) self.__btn_group_type.addButton(self.__rbn_search_content) self.__rbn_search_file.setChecked(True) # radiobutton group self.__btn_group_re_I = QButtonGroup() self.__btn_group_re_I.addButton(self.__rbn_reg_Iyes) self.__btn_group_re_I.addButton(self.__rbn_reg_Ino) self.__rbn_reg_Iyes.setChecked(True) # lines ''' self.__line_1 = QFrame() self.__line_1.setFrameStyle(QFrame.HLine | QFrame.Sunken) ''' # 布局 # open tool self.__layout_tool_choose = QHBoxLayout() self.__layout_tool_choose.addWidget(self.__ln_open_tool) self.__layout_tool_choose.addWidget(self.__pbn_open_tool) self.__layout_tool_choose.setSpacing(0) self.__layout_tool_choose.setContentsMargins(0, 0, 0, 0) self.__layout_open_tool = QHBoxLayout() self.__layout_open_tool.addWidget(self.__lab_open_tool) self.__layout_open_tool.addLayout(self.__layout_tool_choose) self.__layout_open_tool.setSpacing(2) # window title self.__layout_title = QHBoxLayout() self.__layout_title.addStretch(5) self.__layout_title.addWidget(self.__lab_title) self.__layout_title.addStretch(1) self.__layout_title.addLayout(self.__layout_open_tool) self.__layout_title.setContentsMargins(0, 0, 0, 20) self.__lab_title_fram.setLayout(self.__layout_title) # search mode self.__layout_search_mode = QHBoxLayout() self.__layout_search_mode.addWidget(self.__rbn_fuzzy) self.__layout_search_mode.addStretch() self.__layout_search_mode.addWidget(self.__rbn_precise) self.__layout_search_mode.addStretch() self.__layout_search_mode.addWidget(self.__rbn_reg) self.__layout_search_mode.setContentsMargins(60, 0, 60, 0) self.__lab_mode_fram.setLayout(self.__layout_search_mode) # search pattern self.__layout_search_reg_I = QHBoxLayout() self.__layout_search_reg_I.addWidget(self.__rbn_reg_Iyes) self.__layout_search_reg_I.addWidget(self.__rbn_reg_Ino) self.__layout_pattern = QHBoxLayout() self.__layout_pattern.addWidget(self.__ln_file_name) self.__layout_pattern.addLayout(self.__layout_search_reg_I) self.__layout_pattern.setContentsMargins(0, 0, 0, 0) self.__lab_pattern_fram.setLayout(self.__layout_pattern) # search path self.__layout_choose_path = QHBoxLayout() self.__layout_choose_path.addWidget(self.__ln_file_path) self.__layout_choose_path.addWidget(self.__pbn_file_path) self.__layout_choose_path.setSpacing(0) self.__layout_path = QHBoxLayout() self.__layout_path.addLayout(self.__layout_choose_path) self.__layout_path.addWidget(self.__rbn_search_file) self.__layout_path.addWidget(self.__rbn_search_content) self.__layout_path.setContentsMargins(0, 0, 0, 0) self.__lab_path_fram.setLayout(self.__layout_path) # search state self.__layout_state = QHBoxLayout() self.__layout_state.addWidget(self.__lab_state) self.__layout_state.addWidget(self.__pbn_search) self.__layout_state.addWidget(self.__pbn_stop) self.__layout_state.setContentsMargins(0, 0, 0, 10) self.__lab_state_fram.setLayout(self.__layout_state) # top layout self.__layout_top = QVBoxLayout() self.__layout_top.addWidget(self.__lab_title_fram) self.__layout_top.addWidget(self.__lab_mode_fram) self.__layout_top.addWidget(self.__lab_pattern_fram) self.__layout_top.addWidget(self.__lab_path_fram) self.__layout_top.addWidget(self.__lab_state_fram) self.__layout_top.addWidget(self.__tabView) self.__layout_top.setSpacing(10) self.__widget_frame.setLayout(self.__layout_top) self.__layout_fram = QGridLayout() self.__layout_fram.addWidget(self.__widget_frame, 0, 0, 1, 1) self.__layout_fram.setContentsMargins(0, 0, 0, 0) self.setLayout(self.__layout_fram) # set object name self.__widget_frame.setObjectName('fram') self.__lab_title.setObjectName('lab_title') self.__ln_open_tool.setObjectName('ln_open_tool') self.__lab_mode_fram.setObjectName('mode_fram') self.__ln_file_name.setObjectName('ln_pattern') self.__ln_file_path.setObjectName('ln_path') self.__lab_state.setObjectName('state') self.__tabView.setObjectName('tabView') self.__browser_result.setObjectName('browser_result') self.__browser_error.setObjectName('browser_error') self.setStyleSheet( '#fram{' 'border-image: url(Images/bg);' '}' '#lab_title{' 'color: white;' 'font-size: 18pt;' '}' '#open_tool{' 'color: black;' '}' '#mode_fram{' # 'border-top: 1px solid rgba(20, 20, 20, 100);' # 'border-bottom: 1px solid rgba(20, 20, 20, 100);' 'background: rgba(0, 0, 0, 40);' '}' '#ln_open_tool, #ln_path{' 'border-top-left-radius: 2px;' 'border-bottom-left-radius: 2px;' '}' '#ln_pattern{' 'border-radius: 2px;' '}' '#state{' 'background: rgba(0, 0, 0, 40);' 'border-radius: 2px;' 'padding: 1px;' 'color: rgb(240, 240, 240);' '}' 'QTabBar::tab {' 'border: 0;' 'width: 90px;' 'height: 20px;' 'margin: 0 2px 0 0;' # top right bottom left # 'border-top-left-radius: 5px;' # 'border-top-right-radius: 5px;' 'color: rgb(200, 255, 255;);' '}' 'QTabBar::tab:selected{' 'background: rgba(25, 0, 0, 40);' 'border-left: 1px solid rgba(255, 255, 255, 200);' 'border-top: 1px solid rgba(255, 255, 255, 200);' 'border-right: 1px solid rgba(255, 255, 255, 200);' '}' 'QTabWidget:pane {' 'border: 1px solid rgba(255, 255, 255, 200);' 'background: rgba(0, 0, 0, 80);' '}' '#browser_result, #browser_error{' 'background: rgba(0, 0, 0, 0);' 'border: 0;' '}' 'QLineEdit{' 'background: rgba(0, 0, 0, 40);' 'border: 1px solid rgba(220, 220, 220, 200);' 'color: white;' 'height: 20px;' '}' 'QPushButton{' 'background: rgba(0, 0, 0, 100);' 'border-radius: 5px;' 'height: 20px;' 'color: white;' '}' 'QPushButton::hover{' 'background: rgba(0, 0, 0, 150);' '}' 'QToolButton{' 'background: rgba(0, 0, 0, 100);' 'color: white;' 'border-top-right-radius: 2px;' 'border-bottom-right-radius: 2px;' '}' 'QToolButton::hover{' 'background: rgba(0, 0, 0, 150);' '}' ) self.__ln_file_name.setFocus() self.__pbn_search.setShortcut(Qt.Key_Return) # 关联 信号/槽 self.__pbn_file_path.clicked.connect(self.choose_path) self.__pbn_search.clicked.connect(self.pbn_search_clicked) self.__pbn_stop.clicked.connect(self.pbn_stop) self.__pbn_open_tool.clicked.connect(self.choose_open_tool) self.__browser_result.doubleClicked.connect(self.listitem_clicked) # 线程间共享数据队列 queue_size = 10000 self.__queue_result = Queue(queue_size) self.__queue_error = Queue(queue_size) # 标记搜索状态 self.__searching = False # 强制结束子线程 self.__thread_killer = False # 重写鼠标按下事件 def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.offset = event.globalPos() - self.pos() # 重写鼠标移动事件 def mouseMoveEvent(self, event): if event.buttons() == Qt.LeftButton: self.move(event.globalPos() - self.offset) # 检测记事本程序 def set_open_tool(self): if platform.architecture() == ('32bit', 'WindowsPE'): possible_dir = ['C:\\Program Files\\Sublime Text 2', 'C:\\Sublime Text 2', 'D:\\Program Files\\Sublime Text 2', 'D:\\Sublime Text 2', 'E:\\Program Files\\Sublime Text 2', 'E:\\Sublime Text 2', 'F:\\Program Files\\Sublime Text 2', 'F:\\Sublime Text 2', 'C:\\Program Files\\Notepad++', 'C:\\notepad++', 'D:\\Program Files\\Notepad++', 'D:\\notepad++', 'E:\\Program Files\\Notepad++', 'E:\\notepad++', 'F:\\Program Files\\Notepad++', 'F:\\notepad++', 'C:\\Windows\\System32'] elif platform.architecture() == ('32bit', 'ELF'): possible_dir = ['/usr/bin'] for rootdir in possible_dir: for root, dirs, files in walk(rootdir): for file in files: if file == 'sublime_text.exe' or file == 'notepad++.exe' or file == 'notepad.exe': self.__ln_open_tool.setText(join(root, file)) return # 搜索文件名 def search_from_filename(self, filepath, filename, mode='fuzzy_search', I=True): # check arguments of searching if filepath == '' or not exists(filepath): return False if mode not in self.__search_mode.values(): return False if filename == '': return False # count count = 0 # fuzzy mode if mode == self.__search_mode['fuzzy']: for root, dirs, files in walk(filepath): for each_file in files: # kill subThread if self.__thread_killer == True: return if filename in each_file: count += 1 self.__lab_state.setText('正在搜索......已搜到 %d 个文件' % count) self.__queue_result.put(join(root, each_file)) self.__tabView.setTabText(0, '匹配结果(%d)' % count) # precise mode elif mode == self.__search_mode['precise']: for root, dirs, files in walk(filepath): for each_file in files: # kill subThread if self.__thread_killer == True: return if filename == splitext(each_file)[0] or filename == each_file: count += 1 self.__lab_state.setText('正在搜索......已搜到 %d 个文件' % count) self.__queue_result.put(join(root, each_file)) self.__tabView.setTabText(0, '匹配结果(%d)' % count) # regular expression mode elif mode == self.__search_mode['reg']: if I: pattern = re.compile(r'%s' % filename) else: pattern = re.compile(r'%s' % filename, re.I) for root, dirs, files in walk(filepath): for each_file in files: # kill subThread if self.__thread_killer == True: return if re.search(pattern, each_file): count += 1 self.__lab_state.setText('正在搜索......已搜到 %d 个文件' % count) self.__queue_result.put(join(root, each_file)) self.__tabView.setTabText(0, '匹配结果(%d)' % count) self.__lab_state.setText('搜索完毕! 共搜到 %d 个文件' % count) # finished self.__searching = False # set serching flag # 搜索文件内容 def search_from_content(self, path, content, mode='fuzzy_search', I=True): if path == '' or not exists(path): return False if mode not in self.__search_mode.values(): return False if content == '': return False pass_file_count = 0 error_number = 0 current_file = '' processing_file = '' match_files_count = 0 if mode == self.__search_mode['reg']: if I: pattern = re.compile(r'%s' % content) else: pattern = re.compile(r'%s' % content, re.I) for root, dirs, files in walk(path): for each_file in [file for file in files if file.endswith('.h') or file.endswith('.cpp') or file.endswith('.cs')]: current_file = join(root, each_file) pass_file_count += 1 self.__lab_state.setText('正在搜索......%s' % current_file) try: for line_number, line in enumerate(open(current_file)): # kill subThread if self.__thread_killer == True: return if re.search(pattern, line): if processing_file != current_file: self.__queue_result.put('\n%s' % current_file) processing_file = current_file match_files_count += 1 self.__queue_result.put('line %s: %s' % (line_number, line.strip())) except Exception as error: self.__queue_error.put("%s\n(%s)\n" % (error, current_file)) pass_file_count -= 1 error_number += 1 continue self.__tabView.setTabText(0, '匹配结果(%d)' % match_files_count) else: for root, dirs, files in walk(path): for each_file in [file for file in files if file.endswith('.h') or file.endswith('.cpp') or file.endswith('.cs') or file.endswith('.txt') or file.endswith('.py')]: current_file = join(root, each_file) pass_file_count += 1 self.__lab_state.setText('正在搜索......%s' % current_file) try: for line_number, line in enumerate(open(current_file)): # kill subThread if self.__thread_killer == True: return if content in line: # 匹配成功 if processing_file != current_file: # 如果是新文件 self.__queue_result.put('\n%s' % current_file) # 文件名入队 processing_file = current_file # 更新文件标记 match_files_count += 1 self.__queue_result.put('line %s: %s' % (line_number, line.strip())) # 匹配行入队 except Exception as error: self.__queue_error.put("%s\n(%s)\n" % (error, current_file)) pass_file_count -= 1 error_number += 1 continue self.__tabView.setTabText(0, '匹配结果(%d)' % match_files_count) # self.__queue_result.put() self.__lab_state.setText('搜索完毕!成功匹配 %d 个文件,处理 %s 个文件,失败 %s 文件。' % (match_files_count, pass_file_count, error_number)) self.__searching = False # 单击选择路径按钮 def choose_path(self): path = QFileDialog.getExistingDirectory() if path != '': path = sep.join(path.split('/')) self.__ln_file_path.setText(path) # 选择打开文件工具 def choose_open_tool(self): path = QFileDialog.getOpenFileName() if path[0] != '': self.__ln_open_tool.setText(path[0]) # 显示搜索结果 def show_search_result(self): """将搜索结果加载到界面,供用户查看和操作""" line_block = [] # 定义临时列表,成批加载,避免刷新频率过高造成界面闪烁 block_size = 10 # 一次性加载的个数 while self.__searching or self.__queue_result.qsize(): # kill subThread if self.__thread_killer == True: return # if self.__searching or self.__queue_result.qsize() >= block_size: // 永远记住这个 bug (生产者-消费者 问题) if self.__queue_result.qsize() >= block_size: # 如果队列中不小于 block_size 个项 for i in range(block_size): # 取出 block_size 个项 line_block.append(self.__queue_result.get()) # 出队操作 self.__browser_result.addItems(line_block) # 一次性添加 block_size 个条目 line_block.clear() # 清空临时列表 elif self.__queue_result.qsize() >= 0: # 如果队列中小于 block_size 各项 item = self.__queue_result.get() # 出队一项 self.__browser_result.addItem(QListWidgetItem(item)) # 加载到界面 #self.__browser.setCurrentRow(self.__browser.count()-1) # 设置列表中最后一项为当前项,使列表不停滚动 sleep(0.05) # 给界面事件循环腾出时间,避免界面冻结 #self.__pbn_search.setEnabled(True) # 显示出错结果 def show_error_result(self): """打印略过的文件和出错原因,多为 I/O Error""" count = 0 while self.__queue_error.qsize() or self.__searching: # kill subThread if self.__thread_killer == True: return if self.__queue_error.qsize() <= 0: continue self.__browser_error.append(self.__queue_error.get()) count += 1 self.__tabView.setTabText(1, '错误结果(%d)' % count) # 单击检索按钮 def pbn_search_clicked(self): """To search allow the arguments from UI""" # 获取 UI 数据 file_path = self.__ln_file_path.text() file_name = self.__ln_file_name.text() # 检查参数 if file_path == '': QMessageBox(QMessageBox.Warning, '缺少参数!', '请输入搜索路径!', QMessageBox.Ok, self).exec_() return if file_name == '': QMessageBox(QMessageBox.Warning, '缺少参数!', '请输入匹配条件!', QMessageBox.Ok, self).exec_() return # 判断搜索模式 mode = self.__search_mode['fuzzy'] if self.__rbn_reg.isChecked(): mode = self.__search_mode['reg'] elif self.__rbn_fuzzy.isChecked(): mode = self.__search_mode['fuzzy'] elif self.__rbn_precise.isChecked(): mode = self.__search_mode['precise'] # 大小写敏感标记 I = True if self.__rbn_reg_Ino.isChecked(): I = False self.__browser_result.clear() self.__browser_error.clear() self.__tabView.setTabText(0, '匹配结果(0)') self.__tabView.setTabText(1, '错误结果(0)') self.__searching = True # 开启子线程,后台深度遍历 self.__thread_killer = False if self.__rbn_search_file.isChecked(): self.__lab_state.setText('正在搜索......已搜索到 0 个文件') self.__sub_thread_search = Thread(target=self.search_from_filename, args=(file_path, file_name, mode, I)) self.__sub_thread_search.start() else: self.__lab_state.setText('正在搜索......') self.__sub_thread_search = Thread(target=self.search_from_content, args=(file_path, file_name, mode, I)) self.__sub_thread_search.start() # 开启子线程,显示搜索结果 self.__sub_thread_show_result = Thread(target=self.show_search_result) self.__sub_thread_show_result.start() # 开启子线程,显示错误结果 self.__sub_thread_show_error = Thread(target=self.show_error_result) self.__sub_thread_show_error.start() # self.__pbn_search_file.setEnable(False) # self.__pbn_search_content.setEnable(False) # 单击停止按钮 def pbn_stop(self): if not self.__searching: return self.__thread_killer = True while self.__queue_result.qsize(): self.__queue_result.get() while self.__queue_error.qsize(): self.__queue_error.get() self.__lab_state.setText('搜索已停止!') self.__searching = False # 双击搜索结果 def listitem_clicked(self): """Double click to open the file from search result""" file_path = self.__browser_result.currentItem().text().strip() read_tool = self.__ln_open_tool.text() if not exists(file_path): QMessageBox.warning(self, '错误!', '请双击文件名\n%s 不是文件或打不开!' % file_path, QMessageBox.Ok) return if splitext(file_path)[1] in ['.jpg', '.png', '.jpeg', '.gif']: file_path = r'%s'.replace(' ', r'\ ') % file_path system('%s' % file_path) else: system('"%s" %s' % (read_tool, file_path))
class Sansimera(QMainWindow): def __init__(self, parent=None): super(Sansimera, self).__init__(parent) self.settings = QSettings() self.timer = QTimer(self) self.timer_reminder = QTimer(self) self.timer_reminder.timeout.connect(self.reminder_tray) interval = self.settings.value('Interval') or '1' if interval != '0': self.timer_reminder.start(int(interval) * 60 * 60 * 1000) self.tentatives = 0 self.gui() self.lista = [] self.lista_pos = 0 self.eortazontes_shown = False self.eortazontes_names = '' def gui(self): self.systray = QSystemTrayIcon() self.icon = QIcon(':/sansimera.png') self.systray.setIcon(self.icon) self.systray.setToolTip('Σαν σήμερα...') self.menu = QMenu() self.exitAction = QAction('&Έξοδος', self) self.refreshAction = QAction('&Ανανέωση', self) self.aboutAction = QAction('&Σχετικά', self) self.notification_interval = QAction('Ει&δοποίηση εορταζόντων', self) self.menu.addAction(self.notification_interval) self.menu.addAction(self.refreshAction) self.menu.addAction(self.aboutAction) self.menu.addAction(self.exitAction) self.systray.setContextMenu(self.menu) self.notification_interval.triggered.connect(self.interval_namedays) self.exitAction.triggered.connect(exit) self.refreshAction.triggered.connect(self.refresh) self.aboutAction.triggered.connect(self.about) self.browser = QTextBrowser() self.browser.setOpenExternalLinks(True) self.setGeometry(600, 500, 400, 300) self.setWindowIcon(self.icon) self.setWindowTitle('Σαν σήμερα...') self.setCentralWidget(self.browser) self.systray.show() self.systray.activated.connect(self.activate) self.browser.append('Λήψη...') nicon = QIcon(':/next') picon = QIcon(':/previous') ricon = QIcon(':/refresh') iicon = QIcon(':/info') qicon = QIcon(':/exit') inicon = QIcon(':/notifications') self.nextAction = QAction('Επόμενο', self) self.nextAction.setIcon(nicon) self.previousAction = QAction('Προηγούμενο', self) self.refreshAction.triggered.connect(self.refresh) self.nextAction.triggered.connect(self.nextItem) self.previousAction.triggered.connect(self.previousItem) self.previousAction.setIcon(picon) self.refreshAction.setIcon(ricon) self.exitAction.setIcon(qicon) self.aboutAction.setIcon(iicon) self.notification_interval.setIcon(inicon) controls = QToolBar() self.addToolBar(Qt.BottomToolBarArea, controls) controls.setObjectName('Controls') controls.addAction(self.previousAction) controls.addAction(self.nextAction) controls.addAction(self.refreshAction) self.restoreState(self.settings.value("MainWindow/State", QByteArray())) self.refresh() def interval_namedays(self): dialog = sansimera_reminder.Reminder(self) dialog.applied_signal['QString'].connect(self.reminder) if dialog.exec_() == 1: print('Apply namedays reminder interval...') def reminder(self, time): self.settings.setValue('Interval', time) if time != '0': self.timer_reminder.start(int(time) * 60 * 60 * 1000) print('Reminder = ' + time + ' hour(s)') else: print('Reminder = None') def nextItem(self): if len(self.lista) >= 1: self.browser.clear() if self.lista_pos != len(self.lista)-1: self.lista_pos += 1 else: self.lista_pos = 0 self.browser.append(self.lista[self.lista_pos]) self.browser.moveCursor(QTextCursor.Start) else: return def previousItem(self): if len(self.lista) >= 1: self.browser.clear() if self.lista_pos == 0: self.lista_pos = len(self.lista)-1 else: self.lista_pos -= 1 self.browser.append(self.lista[self.lista_pos]) self.browser.moveCursor(QTextCursor.Start) else: return def refresh(self): try: if self.workThread.isRunning(): return except AttributeError: pass self.menu.hide() self.browser.clear() self.lista = [] self.systray.setToolTip('Σαν σήμερα...') self.browser.append('Λήψη...') self.tentatives = 0 self.eortazontes_shown = False self.download() def activate(self, reason): self.menu.hide() state = self.isVisible() if reason == 3: if state: self.hide() return else: self.show() return if reason == 1: self.menu.hide() self.menu.popup(QCursor.pos()) def download(self): self.workThread = WorkThread() self.workThread.online_signal[bool].connect(self.status) self.workThread.finished.connect(self.window) self.workThread.event['QString'].connect(self.addlist) self.workThread.names['QString'].connect(self.nameintooltip) self.workThread.start() def addlist(self, text): self.lista.append(text) def status(self, status): self.status_online = status def reminder_tray(self): text = self.eortazontes_names.replace('<br/>', '\n') urltexts = re.findall('(<a [\S]+php">)', text) urltexts.extend(['</a>', '<p>', '<div>']) show_notifier_text = text for i in urltexts: show_notifier_text = show_notifier_text.replace(i, '') show_notifier_text = show_notifier_text.replace('\n\n', '\n') show_notifier_text = show_notifier_text.replace('www.eortologio.gr)', 'www.eortologio.gr)\n') self.systray.showMessage('Εορτάζουν:\n', show_notifier_text) self.systray.setToolTip('Εορτάζουν:\n' + show_notifier_text) def nameintooltip(self, text): self.eortazontes_names = text for i in ['<br/>', '<div>']: text = text.replace(i, '') self.eortazontes_in_window = text if self.eortazontes_shown: return self.reminder_tray() self.eortazontes_shown = True def window(self): self.lista.append('<div class=""></div>' + self.eortazontes_in_window) if self.status_online: self.browser.clear() self.browser.append(self.lista[0]) self.lista_pos = 0 return else: if self.tentatives == 10: return self.timer.singleShot(5000, self.refresh) self.tentatives += 1 def closeEvent(self, event): self.settings.setValue("MainWindow/State", self.saveState()) def about(self): self.menu.hide() QMessageBox.about(self, "Εφαρμογή «Σαν σήμερα...»", """<b>sansimera-qt</b> v{0} <p>Δημήτριος Γλενταδάκης <a href="mailto:[email protected]">[email protected]</a> <br/>Ιστοσελίδα: <a href="https://github.com/dglent/sansimera-qt"> github sansimera-qt</a> <p>Εφαρμογή πλαισίου συστήματος για την προβολή <br/>των γεγονότων από την ιστοσελίδα <a href="http://www.sansimera.gr"> www.sansimera.gr</a><br/> Πηγή εορτολογίου: <a href="http://www.eortologio.gr"> www.eortologio.gr</a>, <a href="http://www.synaxari.gr"> www.synaxari.gr</a> <p>Άδεια χρήσης: GPLv3 <br/>Python {1} - Qt {2} - PyQt {3} σε {4}""".format( __version__, platform.python_version(), QT_VERSION_STR, PYQT_VERSION_STR, platform.system()))
class Widget(QWidget): def __init__(self, panel): super(Widget, self).__init__(panel) layout = QVBoxLayout() self.setLayout(layout) layout.setSpacing(0) self.searchEntry = SearchLineEdit() self.treeView = QTreeView(contextMenuPolicy=Qt.CustomContextMenu) self.textView = QTextBrowser() applyButton = QToolButton(autoRaise=True) editButton = QToolButton(autoRaise=True) addButton = QToolButton(autoRaise=True) self.menuButton = QPushButton(flat=True) menu = QMenu(self.menuButton) self.menuButton.setMenu(menu) splitter = QSplitter(Qt.Vertical) top = QHBoxLayout() layout.addLayout(top) splitter.addWidget(self.treeView) splitter.addWidget(self.textView) layout.addWidget(splitter) splitter.setSizes([200, 100]) splitter.setCollapsible(0, False) top.addWidget(self.searchEntry) top.addWidget(applyButton) top.addSpacing(10) top.addWidget(addButton) top.addWidget(editButton) top.addWidget(self.menuButton) # action generator for actions added to search entry def act(slot, icon=None): a = QAction(self, triggered=slot) self.addAction(a) a.setShortcutContext(Qt.WidgetWithChildrenShortcut) icon and a.setIcon(icons.get(icon)) return a # hide if ESC pressed in lineedit a = act(self.slotEscapePressed) a.setShortcut(QKeySequence(Qt.Key_Escape)) # import action a = self.importAction = act(self.slotImport, 'document-open') menu.addAction(a) # export action a = self.exportAction = act(self.slotExport, 'document-save-as') menu.addAction(a) # apply button a = self.applyAction = act(self.slotApply, 'edit-paste') applyButton.setDefaultAction(a) menu.addSeparator() menu.addAction(a) # add button a = self.addAction_ = act(self.slotAdd, 'list-add') a.setShortcut(QKeySequence(Qt.Key_Insert)) addButton.setDefaultAction(a) menu.addSeparator() menu.addAction(a) # edit button a = self.editAction = act(self.slotEdit, 'document-edit') a.setShortcut(QKeySequence(Qt.Key_F2)) editButton.setDefaultAction(a) menu.addAction(a) # set shortcut action a = self.shortcutAction = act(self.slotShortcut, 'preferences-desktop-keyboard-shortcuts') menu.addAction(a) # delete action a = self.deleteAction = act(self.slotDelete, 'list-remove') a.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_Delete)) menu.addAction(a) # restore action a = self.restoreAction = act(self.slotRestore) menu.addSeparator() menu.addAction(a) # help button a = self.helpAction = act(self.slotHelp, 'help-contents') menu.addSeparator() menu.addAction(a) self.treeView.setSelectionBehavior(QTreeView.SelectRows) self.treeView.setSelectionMode(QTreeView.ExtendedSelection) self.treeView.setRootIsDecorated(False) self.treeView.setAllColumnsShowFocus(True) self.treeView.setModel(model.model()) self.treeView.setCurrentIndex(QModelIndex()) # signals self.searchEntry.returnPressed.connect(self.slotReturnPressed) self.searchEntry.textChanged.connect(self.updateFilter) self.treeView.doubleClicked.connect(self.slotDoubleClicked) self.treeView.customContextMenuRequested.connect(self.showContextMenu) self.treeView.selectionModel().currentChanged.connect(self.updateText) self.treeView.model().dataChanged.connect(self.updateFilter) # highlight text self.highlighter = highlight.Highlighter(self.textView.document()) # complete on snippet variables self.searchEntry.setCompleter(QCompleter([ ':icon', ':indent', ':menu', ':name', ':python', ':selection', ':set', ':symbol', ':template', ':template-run'], self.searchEntry)) self.readSettings() app.settingsChanged.connect(self.readSettings) app.translateUI(self) self.updateColumnSizes() self.setAcceptDrops(True) def dropEvent(self, ev): if not ev.source() and ev.mimeData().hasUrls(): filename = ev.mimeData().urls()[0].toLocalFile() if filename: ev.accept() from . import import_export import_export.load(filename, self) def dragEnterEvent(self, ev): if not ev.source() and ev.mimeData().hasUrls(): ev.accept() def translateUI(self): try: self.searchEntry.setPlaceholderText(_("Search...")) except AttributeError: pass # not in Qt 4.6 shortcut = lambda a: a.shortcut().toString(QKeySequence.NativeText) self.menuButton.setText(_("&Menu")) self.addAction_.setText(_("&Add...")) self.addAction_.setToolTip( _("Add a new snippet. ({key})").format(key=shortcut(self.addAction_))) self.editAction.setText(_("&Edit...")) self.editAction.setToolTip( _("Edit the current snippet. ({key})").format(key=shortcut(self.editAction))) self.shortcutAction.setText(_("Configure Keyboard &Shortcut...")) self.deleteAction.setText(_("&Remove")) self.deleteAction.setToolTip(_("Remove the selected snippets.")) self.applyAction.setText(_("A&pply")) self.applyAction.setToolTip(_("Apply the current snippet.")) self.importAction.setText(_("&Import...")) self.importAction.setToolTip(_("Import snippets from a file.")) self.exportAction.setText(_("E&xport...")) self.exportAction.setToolTip(_("Export snippets to a file.")) self.restoreAction.setText(_("Restore &Built-in Snippets...")) self.restoreAction.setToolTip( _("Restore deleted or changed built-in snippets.")) self.helpAction.setText(_("&Help")) self.searchEntry.setToolTip(_( "Enter text to search in the snippets list.\n" "See \"What's This\" for more information.")) self.searchEntry.setWhatsThis(''.join(map("<p>{0}</p>\n".format, ( _("Enter text to search in the snippets list, and " "press Enter to apply the currently selected snippet."), _("If the search text fully matches the value of the '{name}' variable " "of a snippet, that snippet is selected.").format(name="name"), _("If the search text starts with a colon ':', the rest of the " "search text filters snippets that define the given variable. " "After a space a value can also be entered, snippets will then " "match if the value of the given variable contains the text after " "the space."), _("E.g. entering {menu} will show all snippets that are displayed " "in the insert menu.").format(menu="<code>:menu</code>"), )))) def sizeHint(self): return self.parent().mainwindow().size() / 4 def readSettings(self): data = textformats.formatData('editor') self.textView.setFont(data.font) self.textView.setPalette(data.palette()) def showContextMenu(self, pos): """Called when the user right-clicks the tree view.""" self.menuButton.menu().popup(self.treeView.viewport().mapToGlobal(pos)) def slotReturnPressed(self): """Called when the user presses Return in the search entry. Applies current snippet.""" name = self.currentSnippet() if name: view = self.parent().mainwindow().currentView() insert.insert(name, view) self.parent().hide() # make configurable? view.setFocus() def slotEscapePressed(self): """Called when the user presses ESC in the search entry. Hides the panel.""" self.parent().hide() self.parent().mainwindow().currentView().setFocus() def slotDoubleClicked(self, index): name = self.treeView.model().name(index) view = self.parent().mainwindow().currentView() insert.insert(name, view) def slotAdd(self): """Called when the user wants to add a new snippet.""" edit.Edit(self, None) def slotEdit(self): """Called when the user wants to edit a snippet.""" name = self.currentSnippet() if name: edit.Edit(self, name) def slotShortcut(self): """Called when the user selects the Configure Shortcut action.""" from widgets import shortcuteditdialog name = self.currentSnippet() if name: collection = self.parent().snippetActions action = actions.action(name, None, collection) default = collection.defaults().get(name) mgr = actioncollectionmanager.manager(self.parent().mainwindow()) cb = mgr.findShortcutConflict dlg = shortcuteditdialog.ShortcutEditDialog(self, cb, (collection, name)) if dlg.editAction(action, default): mgr.removeShortcuts(action.shortcuts()) collection.setShortcuts(name, action.shortcuts()) self.treeView.update() def slotDelete(self): """Called when the user wants to delete the selected rows.""" rows = sorted(set(i.row() for i in self.treeView.selectedIndexes()), reverse=True) if rows: for row in rows: name = self.treeView.model().names()[row] self.parent().snippetActions.setShortcuts(name, []) self.treeView.model().removeRow(row) self.updateFilter() def slotApply(self): """Called when the user clicks the apply button. Applies current snippet.""" name = self.currentSnippet() if name: view = self.parent().mainwindow().currentView() insert.insert(name, view) def slotImport(self): """Called when the user activates the import action.""" filetypes = "{0} (*.xml);;{1} (*)".format(_("XML Files"), _("All Files")) caption = app.caption(_("dialog title", "Import Snippets")) filename = None filename = QFileDialog.getOpenFileName(self, caption, filename, filetypes)[0] if filename: from . import import_export import_export.load(filename, self) def slotExport(self): """Called when the user activates the export action.""" allrows = [row for row in range(model.model().rowCount()) if not self.treeView.isRowHidden(row, QModelIndex())] selectedrows = [i.row() for i in self.treeView.selectedIndexes() if i.column() == 0 and i.row() in allrows] names = self.treeView.model().names() names = [names[row] for row in selectedrows or allrows] filetypes = "{0} (*.xml);;{1} (*)".format(_("XML Files"), _("All Files")) n = len(names) caption = app.caption(_("dialog title", "Export {num} Snippet", "Export {num} Snippets", n).format(num=n)) filename = QFileDialog.getSaveFileName(self, caption, None, filetypes)[0] if filename: from . import import_export try: import_export.save(names, filename) except (IOError, OSError) as e: QMessageBox.critical(self, _("Error"), _( "Can't write to destination:\n\n{url}\n\n{error}").format( url=filename, error=e.strerror)) def slotRestore(self): """Called when the user activates the Restore action.""" from . import restore dlg = restore.RestoreDialog(self) dlg.setWindowModality(Qt.WindowModal) dlg.populate() dlg.show() dlg.finished.connect(dlg.deleteLater) def slotHelp(self): """Called when the user clicks the small help button.""" userguide.show("snippets") def currentSnippet(self): """Returns the name of the current snippet if it is visible.""" row = self.treeView.currentIndex().row() if row != -1 and not self.treeView.isRowHidden(row, QModelIndex()): return self.treeView.model().names()[row] def updateFilter(self): """Called when the text in the entry changes, updates search results.""" text = self.searchEntry.text() ltext = text.lower() filterVars = text.startswith(':') if filterVars: try: fvar, fval = text[1:].split(None, 1) fhide = lambda v: v.get(fvar) in (True, None) or fval not in v.get(fvar) except ValueError: fvar = text[1:].strip() fhide = lambda v: not v.get(fvar) for row in range(self.treeView.model().rowCount()): name = self.treeView.model().names()[row] nameid = snippets.get(name).variables.get('name', '') if filterVars: hide = fhide(snippets.get(name).variables) elif nameid == text: i = self.treeView.model().createIndex(row, 0) self.treeView.selectionModel().setCurrentIndex(i, QItemSelectionModel.SelectCurrent | QItemSelectionModel.Rows) hide = False elif nameid.lower().startswith(ltext): hide = False elif ltext in snippets.title(name).lower(): hide = False else: hide = True self.treeView.setRowHidden(row, QModelIndex(), hide) self.updateText() def updateText(self): """Called when the current snippet changes.""" name = self.currentSnippet() self.textView.clear() if name: s = snippets.get(name) self.highlighter.setPython('python' in s.variables) self.textView.setPlainText(s.text) def updateColumnSizes(self): self.treeView.resizeColumnToContents(0) self.treeView.resizeColumnToContents(1)
class LogWidget(QWidget, MooseWidget): """ A widget that shows the log. This ties into mooseutils.message.mooseMessage which will emit a signal on mooseutils.message.messageEmitter This widget listens to messageEmitter and puts the text in the widget. Color text is supported. """ def __init__(self, **kwds): """ Constructor. """ super(LogWidget, self).__init__(**kwds) self.top_layout = WidgetUtils.addLayout(vertical=True) self.setLayout(self.top_layout) self.log = QTextBrowser(self) self.log.setStyleSheet("QTextBrowser { background: black; color: white; }") self.log.setReadOnly(True) message.messageEmitter.message.connect(self._write) self.button_layout = WidgetUtils.addLayout() self.hide_button = WidgetUtils.addButton(self.button_layout, self, "Hide", lambda: self.hide()) self.clear_button = WidgetUtils.addButton(self.button_layout, self, "Clear", lambda: self.log.clear()) self.top_layout.addWidget(self.log) self.top_layout.addLayout(self.button_layout) self.resize(800, 500) @pyqtSlot(str, str) def _write(self, msg, color): """ This is the slot that will write the message to the widget. Inputs: msg: The message to write color: The color to write the text in. """ if not msg: return msg = msg.encode('utf-8') # make sure if there are bad characters in the message that we can show them. if not color or color == "None": color = "white" else: color = str(color) if msg.find("\n") >= 0: self.log.insertHtml('<div style="color:%s"><pre><code>%s</code></pre></div><br>' % (color.lower(), escape(msg))) else: self.log.insertHtml('<div style="color:%s">%s</div><br>' % (color.lower(), escape(msg)))
class Dialog(QDialog): def __init__(self, parent=None): super(Dialog, self).__init__(parent) self._info = None self._text = '' self._convertedtext = '' self._encoding = None self.mainwindow = parent self.fromVersionLabel = QLabel() self.fromVersion = QLineEdit() self.reason = QLabel() self.toVersionLabel = QLabel() self.toVersion = QLineEdit() self.lilyChooser = lilychooser.LilyChooser() self.messages = QTextBrowser() self.diff = QTextBrowser(lineWrapMode=QTextBrowser.NoWrap) self.uni_diff = QTextBrowser(lineWrapMode=QTextBrowser.NoWrap) self.copyCheck = QCheckBox(checked= QSettings().value('convert_ly/copy_messages', True, bool)) self.tabw = QTabWidget() self.tabw.addTab(self.messages, '') self.tabw.addTab(self.diff, '') self.tabw.addTab(self.uni_diff, '') self.buttons = QDialogButtonBox( QDialogButtonBox.Reset | QDialogButtonBox.Save | QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.buttons.button(QDialogButtonBox.Ok).clicked .connect(self.accept) self.buttons.rejected.connect(self.reject) self.buttons.button(QDialogButtonBox.Reset).clicked.connect(self.run) self.buttons.button(QDialogButtonBox.Save).clicked.connect(self.saveFile) layout = QVBoxLayout() self.setLayout(layout) grid = QGridLayout() grid.addWidget(self.fromVersionLabel, 0, 0) grid.addWidget(self.fromVersion, 0, 1) grid.addWidget(self.reason, 0, 2, 1, 3) grid.addWidget(self.toVersionLabel, 1, 0) grid.addWidget(self.toVersion, 1, 1) grid.addWidget(self.lilyChooser, 1, 3, 1, 2) layout.addLayout(grid) layout.addWidget(self.tabw) layout.addWidget(self.copyCheck) layout.addWidget(widgets.Separator()) layout.addWidget(self.buttons) app.translateUI(self) qutil.saveDialogSize(self, 'convert_ly/dialog/size', QSize(600, 300)) app.settingsChanged.connect(self.readSettings) self.readSettings() self.finished.connect(self.saveCopyCheckSetting) self.lilyChooser.currentIndexChanged.connect(self.slotLilyPondVersionChanged) self.slotLilyPondVersionChanged() def translateUI(self): self.fromVersionLabel.setText(_("From version:")) self.toVersionLabel.setText(_("To version:")) self.copyCheck.setText(_("Save convert-ly messages in document")) self.copyCheck.setToolTip(_( "If checked, the messages of convert-ly are appended as a " "comment to the end of the document.")) self.tabw.setTabText(0, _("&Messages")) self.tabw.setTabText(1, _("&Changes")) self.tabw.setTabText(2, _("&Diff")) self.buttons.button(QDialogButtonBox.Reset).setText(_("Run Again")) self.buttons.button(QDialogButtonBox.Save).setText(_("Save as file")) self.setCaption() def saveCopyCheckSetting(self): QSettings().setValue('convert_ly/copy_messages', self.copyCheck.isChecked()) def readSettings(self): font = textformats.formatData('editor').font self.diff.setFont(font) diffFont = QFont("Monospace") diffFont.setStyleHint(QFont.TypeWriter) self.uni_diff.setFont(diffFont) def slotLilyPondVersionChanged(self): self.setLilyPondInfo(self.lilyChooser.lilyPondInfo()) def setCaption(self): version = self._info and self._info.versionString() or _("<unknown>") title = _("Convert-ly from LilyPond {version}").format(version=version) self.setWindowTitle(app.caption(title)) def setLilyPondInfo(self, info): self._info = info self.setCaption() self.toVersion.setText(info.versionString()) self.setConvertedText() self.setDiffText() self.messages.clear() def setConvertedText(self, text=''): self._convertedtext = text self.buttons.button(QDialogButtonBox.Ok).setEnabled(bool(text)) if text: self.diff.setHtml(htmldiff.htmldiff( self._text, text, _("Current Document"), _("Converted Document"), wrapcolumn=100)) else: self.diff.clear() def setDiffText(self, text=''): if text: from_filename = "current" # TODO: maybe use real filename here to_filename = "converted" # but difflib can choke on non-ascii characters, # see https://github.com/wbsoft/frescobaldi/issues/674 difflist = list(difflib.unified_diff( self._text.split('\n'), text.split('\n'), from_filename, to_filename)) diffHLstr = self.diffHighl(difflist) self.uni_diff.setHtml(diffHLstr) else: self.uni_diff.clear() def convertedText(self): return self._convertedtext or '' def setDocument(self, doc): v = documentinfo.docinfo(doc).version_string() if v: self.fromVersion.setText(v) self.reason.setText(_("(set in document)")) else: self.reason.clear() self._text = doc.toPlainText() self._encoding = doc.encoding() or 'UTF-8' self.setConvertedText() self.setDiffText() def run(self): """Runs convert-ly (again).""" fromVersion = self.fromVersion.text() toVersion = self.toVersion.text() if not fromVersion or not toVersion: self.messages.setPlainText(_( "Both 'from' and 'to' versions need to be set.")) return info = self._info command = info.toolcommand(info.ly_tool('convert-ly')) command += ['-f', fromVersion, '-t', toVersion, '-'] # if the user wants english messages, do it also here: LANGUAGE=C env = None if os.name == "nt": # Python 2.7 subprocess on Windows chokes on unicode in env env = util.bytes_environ() else: env = dict(os.environ) if sys.platform.startswith('darwin'): try: del env['PYTHONHOME'] except KeyError: pass try: del env['PYTHONPATH'] except KeyError: pass if QSettings().value("lilypond_settings/no_translation", False, bool): if os.name == "nt": # Python 2.7 subprocess on Windows chokes on unicode in env env[b'LANGUAGE'] = b'C' else: env['LANGUAGE'] = 'C' with qutil.busyCursor(): try: proc = subprocess.Popen(command, env = env, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE) out, err = proc.communicate(util.platform_newlines(self._text).encode(self._encoding)) except OSError as e: self.messages.setPlainText(_( "Could not start {convert_ly}:\n\n" "{message}\n").format(convert_ly = command[0], message = e)) return out = util.universal_newlines(out.decode('UTF-8')) err = util.universal_newlines(err.decode('UTF-8')) self.messages.setPlainText(err) self.setConvertedText(out) self.setDiffText(out) if not out or self._convertedtext == self._text: self.messages.append('\n' + _("The document has not been changed.")) def saveFile(self): """Save content in tab as file""" tabdata = self.getTabData(self.tabw.currentIndex()) doc = self.mainwindow.currentDocument() orgname = doc.url().toLocalFile() filename = os.path.splitext(orgname)[0] + '['+tabdata.filename+']'+'.'+tabdata.ext caption = app.caption(_("dialog title", "Save File")) filetypes = '{0} (*.txt);;{1} (*.htm);;{2} (*)'.format(_("Text Files"), _("HTML Files"), _("All Files")) filename = QFileDialog.getSaveFileName(self.mainwindow, caption, filename, filetypes)[0] if not filename: return False # cancelled with open(filename, 'wb') as f: f.write(tabdata.text.encode('utf-8')) def getTabData(self, index): """Get content of current tab from current index""" if index == 0: return FileInfo('message', 'txt', self.messages.toPlainText()) elif index == 1: return FileInfo('html-diff', 'html', self.diff.toHtml()) elif index == 2: return FileInfo('uni-diff', 'diff', self.uni_diff.toPlainText()) def diffHighl(self, difflist): """Return highlighted version of input.""" result = [] for l in difflist: if l.startswith('-'): s = '<span style="color: red; white-space: pre-wrap;">' elif l.startswith('+'): s = '<span style="color: green; white-space: pre-wrap;">' else: s = '<span style="white-space: pre-wrap;">' h = l.replace('&', '&').replace('<', '<').replace('>', '>') result.append(s + h + '</span>') return '<br>'.join(result)
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.selectedDate = QDate.currentDate() self.fontSize = 10 centralWidget = QWidget() dateLabel = QLabel("Date:") monthCombo = QComboBox() for month in range(1, 13): monthCombo.addItem(QDate.longMonthName(month)) yearEdit = QDateTimeEdit() yearEdit.setDisplayFormat('yyyy') yearEdit.setDateRange(QDate(1753, 1, 1), QDate(8000, 1, 1)) monthCombo.setCurrentIndex(self.selectedDate.month() - 1) yearEdit.setDate(self.selectedDate) self.fontSizeLabel = QLabel("Font size:") self.fontSizeSpinBox = QSpinBox() self.fontSizeSpinBox.setRange(1, 64) self.fontSizeSpinBox.setValue(10) self.editor = QTextBrowser() self.insertCalendar() monthCombo.activated.connect(self.setMonth) yearEdit.dateChanged.connect(self.setYear) self.fontSizeSpinBox.valueChanged.connect(self.setfontSize) controlsLayout = QHBoxLayout() controlsLayout.addWidget(dateLabel) controlsLayout.addWidget(monthCombo) controlsLayout.addWidget(yearEdit) controlsLayout.addSpacing(24) controlsLayout.addWidget(self.fontSizeLabel) controlsLayout.addWidget(self.fontSizeSpinBox) controlsLayout.addStretch(1) centralLayout = QVBoxLayout() centralLayout.addLayout(controlsLayout) centralLayout.addWidget(self.editor, 1) centralWidget.setLayout(centralLayout) self.setCentralWidget(centralWidget) def insertCalendar(self): self.editor.clear() cursor = self.editor.textCursor() cursor.beginEditBlock() date = QDate(self.selectedDate.year(), self.selectedDate.month(), 1) tableFormat = QTextTableFormat() tableFormat.setAlignment(Qt.AlignHCenter) tableFormat.setBackground(QColor('#e0e0e0')) tableFormat.setCellPadding(2) tableFormat.setCellSpacing(4) constraints = [QTextLength(QTextLength.PercentageLength, 14), QTextLength(QTextLength.PercentageLength, 14), QTextLength(QTextLength.PercentageLength, 14), QTextLength(QTextLength.PercentageLength, 14), QTextLength(QTextLength.PercentageLength, 14), QTextLength(QTextLength.PercentageLength, 14), QTextLength(QTextLength.PercentageLength, 14)] tableFormat.setColumnWidthConstraints(constraints) table = cursor.insertTable(1, 7, tableFormat) frame = cursor.currentFrame() frameFormat = frame.frameFormat() frameFormat.setBorder(1) frame.setFrameFormat(frameFormat) format = cursor.charFormat() format.setFontPointSize(self.fontSize) boldFormat = QTextCharFormat(format) boldFormat.setFontWeight(QFont.Bold) highlightedFormat = QTextCharFormat(boldFormat) highlightedFormat.setBackground(Qt.yellow) for weekDay in range(1, 8): cell = table.cellAt(0, weekDay-1) cellCursor = cell.firstCursorPosition() cellCursor.insertText(QDate.longDayName(weekDay), boldFormat) table.insertRows(table.rows(), 1) while date.month() == self.selectedDate.month(): weekDay = date.dayOfWeek() cell = table.cellAt(table.rows()-1, weekDay-1) cellCursor = cell.firstCursorPosition() if date == QDate.currentDate(): cellCursor.insertText(str(date.day()), highlightedFormat) else: cellCursor.insertText(str(date.day()), format) date = date.addDays(1) if weekDay == 7 and date.month() == self.selectedDate.month(): table.insertRows(table.rows(), 1) cursor.endEditBlock() self.setWindowTitle("Calendar for %s %d" % (QDate.longMonthName(self.selectedDate.month()), self.selectedDate.year())) def setfontSize(self, size): self.fontSize = size self.insertCalendar() def setMonth(self, month): self.selectedDate = QDate(self.selectedDate.year(), month + 1, self.selectedDate.day()) self.insertCalendar() def setYear(self, date): self.selectedDate = QDate(date.year(), self.selectedDate.month(), self.selectedDate.day()) self.insertCalendar()