From 76cc0d8c6db4eab1387959fa860891e8617af7fc Mon Sep 17 00:00:00 2001 From: gavin Date: Sun, 7 Jun 2020 10:21:02 +0800 Subject: [PATCH] kindle manager --- changelog.md | 5 +- icons/person.png | Bin 0 -> 1211 bytes icons/user.png | Bin 0 -> 1274 bytes kman.py | 122 ++++++++++-- kmanapp.py | 248 ++++++++++++++++++----- kmanapp.pyproject.user | 175 ++++++++++++++++ kmanapp.qrc | 2 + kmanapp_rc.py | 442 ++++++++++++++++++++++++++++------------- mainwindow.py | 1 + mainwindow.ui | 3 + searchtitle.md | 7 +- tclip.txt | 11 +- test_kman.py | 116 ++++++++--- tthread.py | 106 ++++++++++ xx | 2 +- 15 files changed, 1007 insertions(+), 233 deletions(-) create mode 100644 icons/person.png create mode 100644 icons/user.png create mode 100644 kmanapp.pyproject.user create mode 100644 tthread.py diff --git a/changelog.md b/changelog.md index 2f401ea..69b8ff9 100644 --- a/changelog.md +++ b/changelog.md @@ -72,10 +72,13 @@ b['1']['2'] = {'3':1} # OK so I need to use resouce file(.qrc) to manage resouce(icons), and generator rcc binnay file, must kmanapp\_rc.py command: pyside2-rcc -binary kmanapp.qrc -o kmanapp\_rc.py +- use QTime to check kindle kindle is connected or not # feature plan ## 20200528 - first abstract from kindle hard / local directory for different OS **done** - add GUI use QT **done** -- new thread to check kindle connection status +- use thread to check kindle connection status **XXXX** +- export function + diff --git a/icons/person.png b/icons/person.png new file mode 100644 index 0000000000000000000000000000000000000000..8e0ea243c360d2ffe172a81968534c9d29624504 GIT binary patch literal 1211 zcmV;s1VsCZP)V)*y+{ZI6XzXVv=L>LqomEIlF6*qA8k>qrEJE?*6J2Tsr^&gmc!ZB z2Sx_eR5ly}Go?T`Op=8waWFuUur&z~0`9%<$MbX^K5uZLURtX^INRBK-t(O2oZow% zbI$V;_>YM!0ayaC1mLd>SR*8W2pdt9z<^qEAM`F{|Jju!A`r4(7L-(->engI6VI+} z*B1qVo`cuXU=L^@14D%ZqpA^>ZCUTH-*vKEKusj_Kv7mA<@Uv0?r2$5Dh;Y-_zgcG z2xR%ZM)eIlR(1MJ0Wi+MHp1XI%)&k@JKKxYniKsj{yAXGMF{EBDfJ%6TKRc#S8}b- z7Hf=8u5fs7lQm(smzbOFPH&BJav;TA)jKIfG1}(mH(CADMn<7$IMD-K#F-1po zs?PB#3Ciibq^p}u0SMH>Pnh=GgLOaB2jQT45Hy|6v5$6L>`Y83a5FY{4YP20SIV_D zrU3Yk!}qwF9;`cNc%jCh6Vl#c`0BO&b- zd1Ua;)lb<`ltV0^@}^$fYzn~ek@54d3f3Lf@}OFOCZxR}_}lOByx5^A16${=veydI zy5BPe;O3V=u$b#m+%TnUHXeWj+Pk3v5VdMm;)jKi5zS5b8XmONhX7Iv*Iw;61%Olk z7vRJ~Y(+6{+!KpA=~c_qa4f`xaI~W~H?w%}g`^xT#L{U!A=$grJF4f4u^@oHQb@&F z&_FeC@pr#$JyxpbSDaC^zTzJ}6U4X_#dMv^}8vr!htU z2mq(}aQeZ<7~dYdWN27Tc!zQ}Xzr6Qj5{Y~Wo1r$W+1zfqc{(1EcWXgumvrrdRNZEid1LU|CG_vdeu+=+aS1K>d)M&`8;4HJJkR^(e?qD#0OwnzZHYR6!rk%lK_ z-Xb@U+mUO=j{rgNFBB)4-)0iIXOA>|NmFK1mNGM ZKLB!St$UIN6X^f|002ovPDHLkV1h6FIVu1E literal 0 HcmV?d00001 diff --git a/icons/user.png b/icons/user.png new file mode 100644 index 0000000000000000000000000000000000000000..559636cdb88a3c038f29dcf0e430cac4c19fc4f0 GIT binary patch literal 1274 zcmVGA4B4Arn|o;tLGK z_<|*xz_REY65sj4#2384m`F7GLJ~Fn5h})K5(gnhhy-Loq?2Vq7%&WD!g$zZ>(<-b zdyg+%N4NI2&Gh@KJ?GqWKKI^p&$(BqQqBF^U@W>3b^%WVZ79vL>y8IZqTECn5cH&H zS$$VtmZ@s;N~M6CvHp3heAeGyzVPKp-a91@szGp zIO|uu{md*Iznez%v2DohdwilIWOj6s?dpXyZ9H7jjw(M4}>f(6? z#vhb(M^Wb;0Mp#B4Rb@rKUub#YrjyEEf1~AzK)|>Z;VAZB_>>e z*xB7?Znl@z{bZRTfd4Rhcs)umati)|eWTn60t3Ld#Xf6BN&c87@vDtB<2%l_uMLr1 z-%e)RCMfm3ApCAniZaxVyX^SrA?-iUmMvaMlCcS;E>nNx7-r&8F(CSrkq|!s=|V@> zr;mtCF1_$#nW;396K58i(?PY4n|m8&8sUpV&-LfaPUa=a-nwD2>GPppnKl5T90KOs zd9*9U*yhmxR@_Op;UwD%O>28nJ4Lztj#xXap~*CFqwEKwesL9cK^FAmT-18+ z+HSE+o=mx;VXiM~I0)=31>yscM)=GV?@+$m{Z#etj1OrY4&Cap6Jay3X2It 0: km.format_out(searchnote[1], 'searchauthor', ft='MD') + print(km.get_bookname_num(books)) + print(km.get_author_num(books)) + # add note content to hightlight, then delete note km.add_note_to_highlight(books) diff --git a/kmanapp.py b/kmanapp.py index dab4e57..aee0b7f 100644 --- a/kmanapp.py +++ b/kmanapp.py @@ -1,19 +1,20 @@ import sys from time import sleep -from threading import Thread -import _thread -import threading from PySide2.QtWidgets import QApplication from PySide2.QtWidgets import QMainWindow +from PySide2.QtWidgets import QLabel +from PySide2.QtWidgets import QMessageBox +from PySide2.QtWidgets import QFileDialog from PySide2.QtCore import (QCoreApplication, QDate, QDateTime, QMetaObject, - QObject, QPoint, QRect, QSize, QTime, QUrl, Qt) + QAbstractTableModel, QObject, QPoint, QRect, QSize, QTime, + QUrl, Qt, QThread, Signal, QTimer) from PySide2.QtGui import (QBrush, QColor, QConicalGradient, QCursor, QFont, QFontDatabase, QIcon, QKeySequence, QLinearGradient, QPalette, QPainter, QPixmap, QRadialGradient, QStandardItem, QStandardItemModel) -from PySide2.QtWidgets import * +#from PySide2.QtWidgets import * from mainwindow import Ui_MainWindow from kman import * @@ -21,38 +22,34 @@ from kman import * # import binary resource file(kmanapp_rc.py) import kmanapp_rc -ONLY_TEST = 0 +ONLY_TEST = 1 class kmanWindow(QMainWindow): """ def __init__(self, *args, **kwargs): super(kmanWindow, self).__init__(*args, **kwargs) """ + flag = True def __init__(self, parent=None): super(kmanWindow, self).__init__(parent) - self.stat_str = 'status information' - self.search_str = '' - self.local_fn = CLIPPATH - # create ui and initial it ui = Ui_MainWindow() ui.setupUi(self) self.ui = ui self.km = kMan() - self.books = self.km.import_clips('local') + self.books = self.km.import_clips() - # loop check kindle is connected or not - # to be implement - """ - try: - #_thread.start_new_thread(self.check_kindle_status) - t1 = threading.Thread(target=check_kindle_status) - t1.start() - except: - print ("Error: can not start thread") - """ + self.add_ui_component() + + self.show_status_info() + self.fill_treeview() + + # timer to check status of kindle + self.timer = QTimer(self) + self.timer.timeout.connect(self.show_status_info) + self.timer.start(1000) # connect action/toolbutton to slot functions ui.actionimportkindle.triggered.connect(lambda: self.import_kindle(self.books)) @@ -62,18 +59,34 @@ class kmanWindow(QMainWindow): ui.actionstatistic.triggered.connect(lambda: self.statistic()) ui.actionhomepage.triggered.connect(lambda: self.homepage()) ui.actionabout.triggered.connect(lambda: self.about()) - ui.actionflush.triggered.connect(lambda: self.flush()) + ui.actionflush.triggered.connect(lambda: self.refresh()) ui.searchComboBox.currentIndexChanged.connect(self.search_scope_change) ui.searchToolButton.clicked.connect(self.search_button_clicked) - ui.treeView.clicked.connect(self.clicked_items) - - self.add_ui_component() - #add_ui_component() ###! can not found this function + ui.treeView.clicked.connect(self.tree_item_clicked) + ui.tableView.clicked.connect(self.table_item_clicked) def add_ui_component(self): self.ui.searchComboBox.addItems(['ALL','bookname','content','author']) + # status bar + self.ui.status_label = QLabel() + self.ui.pe = QPalette() + + # table + #self.ui.tablemodel=QStandardItemModel(100,5) + self.ui.tablemodel= nTableModel(100,5) + self.ui.tablemodel.setHorizontalHeaderLabels( + [u'Content',u'Type',u'Bookname',u'Author',u'Position',u'Date']) + self.ui.tablemodel.update(self.km.filter_clips(self.books)) + self.ui.tableView.verticalHeader().hide() + for row in range(5): + for column in range(5): + i=QStandardItem("row %s,column %s"%(row,column)) + self.ui.tablemodel.setItem(row,column,i) + self.ui.tableView.setModel(self.ui.tablemodel) + + """ if not ONLY_TEST: # XXXXXXXXXXXXX model = QStandardItemModel() rootItem = model.invisibleRootItem() @@ -113,11 +126,25 @@ class kmanWindow(QMainWindow): icon.addFile(u":/icons/book_open.png", QSize(), QIcon.Normal, QIcon.Off) item.setIcon(icon) parentItem.appendRow(item) + self.ui.treeView.setModel(model) + """ - self.ui.treeView.setModel(model) + def tree_item_clicked(self, modelidx): + model_index_list = self.ui.treeView.selectedIndexes() # QModelIndexList + model_index = model_index_list[0] # QModelIndex + itemmodel = model_index.model() #QAbstractItemModel/QStandardItemModel + item = itemmodel.itemFromIndex(modelidx) #QStandardItem - def clicked_items(self): - print( 'call clicked_items()' ) + print(item.text()) + + # filter clips + + #item = self.ui.treeView.selectedIndexes()[0] + #print(item.model().itemFromIndex(modelidx).text()) + + def table_item_clicked(self, item): + content = item.data() + #print('call table_item_clicked() {}'.format(content)) def search_button_clicked(self): print( 'call search_button_clicked()' ) @@ -129,10 +156,11 @@ class kmanWindow(QMainWindow): #print(search_clip(self.books,s,'ALL',p[t])) print('call search_scope_change()') + ## XXXX def check_kindle_status(self): - while True: + while self.flag: self.show_status_info() - sleep(1) + sleep(2) def show_status_info(self): """ show status information on statusbar @@ -143,33 +171,92 @@ class kmanWindow(QMainWindow): """ status = self.km.status_info() self.ui.statusbar.showMessage(status[0],0) - clabel = QLabel(status[1]) + self.ui.status_label.setText(status[1]) if not self.km.status: - pe = QPalette() - pe.setColor(QPalette.WindowText,Qt.red) - #clabel.setAutoFillBackground(True) - clabel.setPalette(pe) - self.ui.statusbar.addPermanentWidget(clabel, stretch=0) + self.ui.pe.setColor(QPalette.WindowText,Qt.red) + #self.ui.status_label.setAutoFillBackground(True) + self.ui.status_label.setPalette(pe) + self.ui.statusbar.addPermanentWidget(self.ui.status_label, stretch=0) # define slot functions def import_kindle(self,bks): + fp = self.km.get_kindle_path() + if not fp: + self.messagebox(ico=2, info='\n\n kindle is not connected') + return 0 + + self.books = self.km.import_clips(self.km.get_kindle_path()) + status = self.km.status_info() self.show_status_info() print(bks) - pass - def import_local(self): fn, ft = QFileDialog.getOpenFileName(self, "choose file to import", - './', # 起始路径 - "All Files (*);;Text Files (*.txt)") # 设置文件扩展名过滤,用双分号间隔 + './', # start path + "All Files (*);;Text Files (*.txt)") # filter file type self.fn = fn + self.books = self.km.import_clips(fn) + + self.show_status_info() + #print('filename ', fn, 'filetype ', ft) if fn == "": return False + def fill_treeview(self): + self.ui.model = QStandardItemModel() + rootItem = self.ui.model.invisibleRootItem() + item = QStandardItem('All Notes') + icon = QIcon() + icon.addFile(u":/icons/emblem_library.png", QSize(), QIcon.Normal, QIcon.Off) + item.setIcon(icon) + item.setAccessibleDescription('top') + rootItem.appendRow(item) + parent_item = item + + # add bookname tree + [totalnum, booknum] = self.km.get_bookname_num(self.books) + bookname_item = QStandardItem('Bookname ({})'.format(totalnum)) + icon = QIcon() + icon.addFile(u":/icons/book_open.png", QSize(), QIcon.Normal, QIcon.Off) + bookname_item.setIcon(icon) + bookname_item.setAccessibleDescription('root') + parent_item.appendRow(bookname_item) + + if totalnum > 0: + for k, v in booknum.items(): + item = QStandardItem('{} ({})'.format(k, v)) + icon = QIcon() + icon.addFile(u":/icons/book_open_bookmark.png", QSize(), QIcon.Normal, QIcon.Off) + item.setIcon(icon) + item.setAccessibleDescription('leaf') + bookname_item.appendRow(item) + + # add author tree + [totalnum, authnum] = self.km.get_author_num(self.books) + author_item = QStandardItem('Author ({})'.format(totalnum)) + icon = QIcon() + icon.addFile(u":/icons/person.png", QSize(), QIcon.Normal, QIcon.Off) + author_item.setIcon(icon) + author_item.setAccessibleDescription('root') + parent_item.appendRow(author_item) + parent_item = author_item + + if totalnum > 0: + for k, v in authnum.items(): + item = QStandardItem('{} ({})'.format(k, v)) + icon = QIcon() + icon.addFile(u":/icons/user.png", QSize(), QIcon.Normal, QIcon.Off) + item.setIcon(icon) + item.setAccessibleDescription('leaf') + author_item.appendRow(item) + + self.ui.treeView.setModel(self.ui.model) + self.ui.treeView.expandAll() + def config(self): print("call slot config()") pass @@ -187,7 +274,7 @@ class kmanWindow(QMainWindow): pass def about(self): - self.messagebox('\n'+ \ + self.messagebox(ico=1, info='\n'+ \ ' kindle management tool \n\n' + \ ' v1.0.4\n\n' + \ ' Author: chengan\n\n' + \ @@ -196,28 +283,87 @@ class kmanWindow(QMainWindow): print("call slot about()") pass - def flush(self): - print("call slot flush()") + def refresh(self): + print("call slot refresh()") pass - # unify messagebox - def messagebox(self, showinfo): + def messagebox(self, ico=1, info=''): + """ unify messagebox + Args: ico - QMessageBox.NoIcon 0 + QMessageBox.Information 1 + QMessageBox.Warning 2 + QMessageBox.Critical 3 + QMessageBox.Question 4 + """ + icons = {0:QMessageBox.NoIcon, \ + 1:QMessageBox.Information, \ + 2:QMessageBox.Warning, \ + 3:QMessageBox.Critical, \ + 4:QMessageBox.Question } msgBox = QMessageBox() - msgBox.setText(showinfo) + msgBox.setText(info) msgBox.setInformativeText("") - msgBox.setIcon(QMessageBox.Information) + msgBox.setIcon(icons[ico]) msgBox.setStandardButtons(QMessageBox.Cancel | QMessageBox.Ok) msgBox.setBaseSize(QSize(600, 300)) r = msgBox.exec() + ## XXXX + def closeEvent(self, e): + # stop check thread + self.flag = False + +## thanks 勤奋的小青蛙 ^_^ - http://www.jyguagua.com/?p=2615 +#class nTableModel(QAbstractTableModel): +class nTableModel(QStandardItemModel): + def __init__(self, parent=None, seclist=None, *args): + super(nTableModel, self).__init__() + self.seclist = None + + def update(self, seclist): + self.seclist = seclist + + def rowCount(self, parent): + if not self.seclist: return 0 + return len(self.seclist) + + def columnCount(self, parent): + if not self.seclist: return 0 + return len(self.seclist[0]) + + def data(self, index, role): + if not index.isValid(): + return None + elif role != Qt.DisplayRole: + return None + return self.seclist[index.row()][index.column()] + + def sort(self, col, order): + """sort table by given column number col""" + self.emit(SIGNAL("layoutAboutToBeChanged()")) + + self.seclist = sorted(self.seclist, key=operator.itemgetter(col)) + if order == Qt.DescendingOrder: + self.seclist.reverse() + + self.emit(SIGNAL("layoutChanged()")) + if __name__ == "__main__": - import sys - from PySide2.QtWidgets import QApplication, QLabel app = QApplication(sys.argv) kmw = kmanWindow() kmw.resize(900, 600) kmw.show() + + # loop check kindle is connected or not + # BUG to be implement XXXX + """ + try: + t = threading.Thread(target=kmw.check_kindle_status) + t.start() + except: + print ("Error: can not start thread") + """ + app.exec_() - diff --git a/kmanapp.pyproject.user b/kmanapp.pyproject.user new file mode 100644 index 0000000..3bdb45e --- /dev/null +++ b/kmanapp.pyproject.user @@ -0,0 +1,175 @@ + + + + + + EnvironmentId + {fae58cf6-d2fe-464b-83cf-b657b7f31038} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + true + + + + ProjectExplorer.Project.Target.0 + + Desktop (x86-darwin-generic-mach_o-32bit) + Desktop (x86-darwin-generic-mach_o-32bit) + {47431a9c-e34f-4b94-83d9-f5f98149f5e9} + -1 + 0 + 0 + 0 + + + 0 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + kmanapp + PythonEditor.RunConfiguration./Users/mark/kman/kmanapp.py + /Users/mark/kman/kmanapp.py + {8add66da-db0d-4573-865d-9852c93e0d0e} + /Users/mark/kman/kmanapp.py + + false + + false + true + false + false + true + + /Users/mark/kman + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + + diff --git a/kmanapp.qrc b/kmanapp.qrc index 11a956f..fd08ffb 100644 --- a/kmanapp.qrc +++ b/kmanapp.qrc @@ -46,5 +46,7 @@ icons/emblem_library.png icons/book3.png icons/register.png + icons/person.png + icons/user.png diff --git a/kmanapp_rc.py b/kmanapp_rc.py index a9c6aa4..bedeb79 100644 --- a/kmanapp_rc.py +++ b/kmanapp_rc.py @@ -6,94 +6,96 @@ from PySide2 import QtCore qt_resource_data = b"\ -\x00\x00\x05^\ +\x00\x00\x05w\ \x00\ -\x00\x1c\xaax\x9c\xb5Y\xbd\x8e\xdc6\x10\xee\xef)\x84\ -\xed\xb3\xda=\x5cr\x81\xc1\x93\x91\x0b\x9c\x18\x88\x0f8\ -\xe36v\x19p%\xee\x8a9I\xd4Q\x94o\xd7\x95\ -]8@\x80\x04q\x91\xd2U\x8aT\x81\x93\x22\x8d\x8b\ -\x8dc\xa0\xad\x15\x85\x17\xfb\x8a\xb3\xd0\x92\x1bT\x05\ -=\xdbA\xfdH\x9c\xfb\xf1\xd7\x853\xea\x01\xf4\xe1\x7f\ -{\xf0\xabH\xc6\xc4\x7f\xe7\x0e\xbb \xd7\xc5<\x1a\xd8\ -\xca~\x17\xdc\xa6t\x18\xe0\xca\xd2p\xa8\x95\x9d\x94\xcb\ -\x11z\x00\xae\xaa\xeb\x8c\x06+L~\xb0\xc4\xef\xc2\xb5\ -\x22\x1e\x06\xac65\x1cYm\xc8\xd2\xc9\x9c\xe5\xb0}\ -\x95R\xf7\xb2\xe0\xdcJB\xab\x8bp4\xe0a\x16\xb8\ -L\xba`7\x84\xc3@\x97A\x0c\x87|\x97\x99]X\ -\x96\x13\xc3hx\x16[t\x82Z\xd7\x18\x86lam\ -8\xba\xa5c\x105\xce\x1e\xa9\x96\x8f\x97K*\x06 \ -^\x8cE\xa3\x01\x9e\xed\xd0\x05u)\x1b\x06r\x1e\xc5\ -m4\x0d\x8ff\xaf\x13K0+\x84\x07\xf1n\xc3\xbb\ -\x10V#\xe5h\xf0^\xa5$\xc9\xb6\xe9\x82\xb8*\x1f\ -\x06\xb3\x0ce8\xc6\xa0\x12Y\xd2\x96\xe5Q\xf0\xb6\xef\ -\x16\xdd\xd91\xe4/\xb0\xe3\xc1{N7\xd8#\x9b.\ -t+\xe2\x81\x8d\xa2\xf9/\xca\xc7u\x09i\xc7\x8a\x98\ -\xd83k\x8dG\x0a\xca\xe1I\xa4\x0e\x8d\xdc \xf5\x88\ -\x1c\xba\x85\xfc\x0b\xd1\x04\xcd\x96k\xcd\x15\x08\x00\x88\x88\ -:\x17\x90\x22;\xa5\xce\xc1\x7f\xdc\x00'-\ +\x00\x1d\x01x\x9c\xb5Y\xcd\x8e\xdb6\x10\xbe\xefS\x10\ +\xbe\xd7\xb2\x17\xdbn\xb1\x90\x1dt\x8b\xb4\x01\x9a\x056\ +Xws,h\x89\xb6\xd8\x95D-Ee\xed\x9c\x92\ +C\x0a\x14h\xd1\x1cz\xcc\xa9\x87\x9e\x8a\xb4\x87^r\ +\xe8\xd34\x9b\xe41:\x22)\x89\xfa\xb5\x1b\xadn\x9a\ +\x1f\x0eg>\xce\x0c\x87\xb6}o\x13\xf8\xe8\x09\xe11\ +e\xe1l4\x1dOF\x88\x84\x0esi\xb8\x9e\x8d\xbe\ +]|\xf5\xc9\xe7\xa3{\xf3\x03;\xa1\x85\xd2\x11(\xcd\ +\x0f\x90\xed\xf88\x8e\xe7g\x98\x86\x8fi\xe8\xb2\x1b\xdb\ +R\x1c\x10\xddPwM\x04\x92\xf4l\xf4\xa8\xd0\x19\xa1\ +\x10\x07d628\xa0\x8f\xec\x88\xb3\x88p\xb1\xd5\xe2\ +5a\x01\x11|+\x85\xc8\xe6\xc4\x11\xf2\x0b\xd9\x9b\xf9\ +\xc4\xb66\x9a\xd8\xa6\xc4V\x13\xb0\xa7\xf0\xe6\xc7\xc7G\ +\xb6\xa5>\x15\xdb#t\xed\x89\xf9\xd1\x14T\xf5\xb7\xb4\ +ieFm+\xdb\xbc\xc9\x93\x1b\xe9\xe4\x82\x0a\x9fh\ +gb\xc1\x01\x9c\xf97 \xf0\x09:\xc3!^\x93\x80\ +\x84\xc2\xb6\xb4\xa4n\xb3\x02\xc7cIfP8\xb0\x96\ +c_\xe9\xe8=|\xbceI\xb1\xe0kN\xdd\x87\x92\ +\x95-Z\x17\x1c\x1d'\x15$@\x9c\xdd\xccFp\x84\ +\x0e\xf3\x93 L?\x95\xb4f\xf1\xc1)\xdb\x94-z\ +\x8c\xd3\xa7,\x14\xd8/\xd9\xd5\x963\xa2\x16\xcbC\xbc\ +$~f#&\x98;\x9eb\xe5+j\x90\x0a\xb2\x11\ +\x868G\xf4B\xae6a\xd4\xf2\x12\x98\x9a\xa5\xdc\xc8\ +}\xb4L'wxLCr\xdf\xa5\xa2\xe2t\xc6m\ +\xf7;\xf2\xb1C<\xe6\xbb\x84/ZB\xb8\xfd\xe5\xcf\ +w?\xfd\xf8\xf6\xcd\xef\xb7/\x7f\xfe\xf7\xd9\xf3\xb7\xff\ +\xbc\xfa\xf0\xec\x05|\xdc\xfe\xf0\xe2\xf6\xf5\x9bw/_\ +\xbd\xff\xfb\xb7\xf7\x7f\xfc\xfa\xe1\xf5_\x83\x87\xf9%\x0b\ +\x96\x0cN\xb9\x1cf\xcem\x0f\xd3I8\x87\x94l\x09\ +\xd1\x1a\xcc\xe1\x05c\xfei\x22\x04\x0b\xcb.\x1b\xfc\xff\ +\x9fS\xe3\xf1x/\xa4k\x06\xa9S\xda\x0f|\x07F\ +\x0c\xeer\x12\xb3\x84;\xa0r\x15@\xedG\xd1\xf8\x9a\ +;\xa6&\xb2C\xc6\x03\xec\xb3\xd5j~b\xc9e\x96\ +\x8ad\xfc}D\xd6\xb6\xb5C\xac7\xfax\x9cmK\ +\x15\xbbn\x0c\x86\xc8h\x12\xd3\xa6&Q9\x91\x8b\xc8\ +\xa7B\x10\x9e\x9f\x87\xa6\xbf;,\x9aC\x056h\x22\ +\x90;XP\x13=\x9b\x84I0\x7f$NN\x1e\xe4\ +M\xc6\xb6$\xf3\xa0-\xc4ZvpB.)\xc9/\ +\x10\x91\xd1\xc5.\x15Wb\xfa\x94\x9c3\x9f:[3\ +oRn$\xb9\xc8K\xbf\xc56\x02\xddsNV\x04\ +\xd2\xde\x1d\xa1'\x05\xf7\xfe&\xc2az\x13\x96\x12\x01\ +\x1a%$\x14\x11\x8e\x97\xde>\x06e\xe8\xa4we\xa1\ +cP\xc6\xa1\x16\x9e\x18\xc7Z?\xe9JT\x01\xde\xd0\ + \x09.`q5,\xd3\x01u\x03\x1eM&\xa5\xcb\ +P\x07\xa0n\xc1\xe9g\xc7\xc7\xc7\x87\xd3OK\xd7\xa2\ +\xe1[\xa7WX@M-\x13A\xb2\xdb\x83`h\x8b\ +\x974\xa6K\xbf\xe4\xd8\x12\xaaw\xbe\xc2~LlK\ +~\x17Vs\x1bE\x16T\xb2z\xcf|l\xcf\x81\xc6\ +t4\xf2\xf1\x12t\xa9S\xcd\xc6\xc6\x88\xab\xf9\x88!\ +\xd0RB\xe6\x8c\xf6\xa6\xd2\x98\x92m9y\xa6Nz\ +wF\xee\x95\x92\xfb\xe4dsR\xee\xd3\x7f\xea\xf0@\ +?6/Y\x91\xd1\x03\x82S\x14q/p\xa6}\xc1\ +\xd9\xb3fkE\x9bUmQ\x98\xd5\xd2-\xa6\xd9\xc9\ +\xa4^\xb6\xd5\xba\xdd\xef\xe2(\xd1e\xd2\xb8:\xcc;\ +\xc5T\xaa\x95(\x14[\x12\x9f\xe2\xa2F%c\x09\x0c\ +\xabI\xff\x0c\xea\xce\xd0\x0e4\xa9\xf6\xec|\x14\x98\xaf\ +\x82\xf2\xb3\xa0\xfc.h{\x18\xe4X\x1e\x1e\x96\xa1,\ +^\x06\xd51\xbe#n9\xa4\x14q\x08M6\xc6Q\ +{R\xe4\xd3\x8a^V\x9aX*\x87X\xeb\xbcz\xcd\ +\x17\x9c\xe0\xcc\x9a\xece\x0b\x16-\x0a\x91\xd1\xe0\xaa\x8d\ +\xb7\xcd\xe2),\xbb\xcaL6\xb6\xf1\xba%\xd7\xc5N\ +\xdal\xb5%E\xd0 b\x5c\x5c\xc9\xf7\x92\xca\x82n\ +M\x9fAGnS\x8cI\x849\x16\x8cw[\xbaa\ +\xdc\x8d\xbbU\xd2\xcc\xa41\xb4\xff\x9e[\xc1\xb8\xb6\xa2\ +\xeb\x9eF\xcc\xfa\ +\xed\xb4\xf2\x93\xd8\xd3\xc5h&\xf4\x8e\xe3h\xccdc\ +H\xdeo>n\x18\x8d\xa1\x14B>\x8e\xc2\xc6\xc1\xd8\ +\x10\x9acq\xb5&\xda\x1f\x03Ye\x19\xa1tVW\ +\xd5\x12\xa4\xfa\x82F\x8d\xc6\xa0\xf6i\x14\x01\x8dV\xd4\ +'h\xc5Y\x80\xe4\x06eA\xc7vP?\x12\xe7n\ +\xfcu\xe1\x0cz\x00]\xf8\xdf\x1d\xfc*\x92!\xf1\xdf\ +\xb9\xc3.\xc8u1\x0f\x06\xb6\xb2\xdf\x06\xb7)\xed\x07\ +\xb8\xb2\xd4\x1fje'\xe1r\x84\xee\x81\xab\xea:\x83\ +\xc1\x0a\x93\x1f,\xf1\xdap-\x89\xfb\x01\xabM\xf5G\ +V\x1bB:\x99\xd3\x1c\xb6\xae\x13\xea\x5c\xe5\x9c;I\ +hu\x11\x0e\x06<\xcc\x02Wq\x1b\xec\x86\xb0\x1f\xe8\ +2\x88\xfe\x90\xef2\xb3\x0b\xcbbb\x18\x0c\xcf|\x8b\ +VP\xab\x1a\xfd\x90\xcd\xad\xf5G\xb7p\x0c\xa2\xc6\xe9\ +#\x15yx\xb9\xa4\xa2\x07\xe2\xf9X4\x18\xe0\xe9\x0e\ +mP\x17\xb2~ gQ\xdcE\xd3pi\xfa:A\ +\x82\xa1\x00\x1e\xc4\xbb\x0d\xefBX\x8d\x94\x83\xc1{\x9d\ +\x908\xdd\xa6\x0d\xe2\xb2\xbc\x1f\xcc2\x94\xfe\x18\x83J\ +\x88\xa4-\xe4R\xf0\xb6\xeb\x16\xdd\xd91\xe4\x0f\xbb\xc3\ +\xc1{N7\xd8%\x9b6tK\xe2\x9e\x8d\xa2\xfe\xe7\ +\xcc\xc7u\x09i\x07\x85L\xec\x99\xb5\xc6#\xc5\xce\xe0\ +\x89\xa5\x0e\x0d\x1d?q\x89\x1c\xba\x85\xfcg\xd2\x04\xcd\ +\x92k\xcd\x156\x00\x10\x12u. \xb5\xad\x84\xce\x0f\ +\xfe\x03Ie@\xd5\ \x00\x00\x0f\xf6\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -29968,6 +29970,84 @@ w\x0b\xbe\x86\xd8\xb8\xeb\x81L\x83\xc8\x9cP\x80\xe9<\ \x02\xbf&;^~3\xb09K\xae\xa5$\xcaR\xec\ \xec1\xfc\x7f\x89E]\xa3\xc9\xb4-\xf9\x00\x00\x00\x00\ IEND\xaeB`\x82\ +\x00\x00\x04\xbb\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ +\x00\x00\x04\x82IDATx\xda\xedV}L\x95e\ +\x14?\xcf\xfbu\xe1~\xc4\xbdH\x08\x04\x13\xe7\x1d\x5c\ +\xb4\x11e\x94\xa3\xa4\xcd\xa6\x92\xc9\xac\xd5\x1fmQ\xab\ +\xa5l\xc6\xc8\xd6\xea\x16E\xa9\xfdS\xd9\x96\xc3\xd9\xd6\ +\x07F\x06\xd4T6\x1c\x023\xa5@7L\x92\x85+\ +q0@\x91\xb05\x09\x10\x02\xee\xbd\xef\xc7\xf3t\x1e\ +>op\xa1^Z\xab?8\xdb\xd9{\xde\xf3\x9c\xe7\ +\x9c\xdf{\x9es\xce\xf3\x12\xf8\x8f\x89,\x01X\x02\xb0\ +\x04\xe0\xaf\x0cX#$\x80\x08\x1bQ\x94\xc0\x80Zr\ +\x1f\xf4.d\xff\xd9\x95$\x22\x10\xb2^\x16\x94T\x9d\ +\xea\xd7)\xd0\x13\xcf\xael\xd7\x17\x05\x80\x9e\x83\xd7\xd1\ +`\x0fh \x03C\x85\x02\xa3\xaa\x11\x96mY\xef\xaf\ +\xdfu\xb2[@M$\xf2@QV\x22\xe5\xf6\xc5]\ +\xeehYT*\x0d\xaae\xf8\x0d? \x08d\xf9\xbc\ +F\xf5\x0d;Vu\xfaL\x010\xce\xc06\xc2\xe08\ +\xcc\xc2>*;\xdb\x8b\xd4\x9a\x13\xfd,\xfe9`\xcc\ +E\x08\xe9\xd3)\xf5\x1e\xc8Z\xf9yqWr\xad\xcf\ +\x18y\x8816m/\x10\x11\x14\xc1\xf2R\xae\xbbs\ +\xbf)\x00\xda7P\x85\xc1\xb3\xfft\x1c\x8c\xc0\xc7P\ +\x06-\xbet\xd0\xe8L\x10\x9b\x22RWD\xf5\x13\xf1\ +1EGt\xaa\xce\xf1)\x09\xca\xe9\xbc\xa4\xab\x9bL\ +\x01\x08\xd4\xc2O\x98\xf6\xdb\x83u?\xd2\x07\xe1\xa0z\ +\x104\x9d\xce\xb1\x8fv]\xecLL(p36w\ +\x0d\xb3pyW\xca\xb55\xa6\x00\xf8\x8e\xc3\xf7\xb8\x9a\ +\x1e\xac;fx\xa1\xc6\x9f\x13\xd2\xdea\xfb\x99y\xdc\ +;\xe7\xf3w\xf9\xe55=\xe6\x00\x8cT\xc0a\x5c}\ +:XW\xa2\xbd\x05\x0d\xda#!\xed\x15yd\xf0\xce\ +\xd5O\xd9Q\x94C,\x9f\xf2\xa6^\xdbl\x0a\xc0\xf0\ +\x91\xf1\xf3\xaf\x0a\xd6\x1d\xd5\xf2\xa0Z\x7f&\xa4\xbd \ +\xf8\xdb\xef\xf0\xbc\xd8\xa1(\x03[\xe7\xae\xb2\xd7\x0a\xd2\ +\xba\xdf3\x05\xe0\xe6\x97@\xb0\x98\xebP\xdc0\xa5k\ +6\x1e\x80\x03\xda\xbb\xa1\x01\x10\xb5jU\xe2\x87\x85\x91\ +\x11\xcdM\xf8\x1a\x1e\xb4\xd4\x87\x00R\x0a\xd7^\xed7\ +\x05\x80S\xff\x17\xe0\xc4BlE1n\xdc\x13\x8b9\ +\xe9U\xcb\xd3p,\xc4\x84p\xb4\xa367\xb3x\xef\ +\x85\xa4\x1c,\xc4\xd2i=!\xd9\xbb\xd3;\xaa\xe7\x8b\ +\xb1 \x80\xbeRH\xc5Y\xd0@5p\xf1w\xbfl\ +=V\xaa\xe6W\x9cQ\xb3\xbe\xe2\x1f=\x13\xc4\xb8\x14\ +\xe5j\xbb;yE%U\xe4\xa1\x821}d/\xef\ +\x06\x81H|\x18m.\xbc\xe7\xe2\xa9\xbf\x0d\xe0\xd7\xc3\ +\xb8G\x80Gq~<\x8f>2\xe9\xe8\x8c\x0d\xc1\xf2\ +\xd2-JG\x89/?\xac\xde\x97\x950\xa5\x8f\xbd\xb5\ +y\x8bg\xc5\xd9u\x924\xb4=\xa0\xfb\xe3\xfc\xfa\xcc\ +\xd0\xb3+\x0e]\x16-\xdf\xe2\xee\xea\x80\xaeU\xbe\xb9\ +\xee\xbb\xde\x90\x00~9\x04\x0eA\x86\xf7\xdes\xcf\xb9W\xa8\ +R\xcd\xfd\xda`,\xba\x11v\x01O\x03m(\xcd\xb1\ +\xeb\x8e\x07L\xa2\xdcD\x18\x10\xf4\xa4gY}W^\ +\x96\xa9j\xf2J\xa5\x80\xd8\x80&\xd5\xe3\x80\x08\xaf\x00\ +\x91\x22\xff5\xa7\xd4a3*\x1c1x\x87.\xf7\xd4\ +\x0e/\x09 \xf1\x8b\x863\x11\xdeGy\x13\x08\xfa\x02\ +\x96\x06\xc8\xcb\x11\xd1\xc3\xb3S\xd6\xc1\x9b\xafI\xa6j\ +\x80xJ\xd7\x01\xdf*l\xf2\xcbl\xcd(\xd1q\x07\ +kl\x02\xaf\xb1\x0e\x0dY\xfe\x18J\xbf\x04j\xf6\x5c\ +\xde+\x7fU\x04\x88\x0f\xe8\x16UN\x00\xf1R\xb9\x9a\ +\xfftH\x1e\x9f!>\x9cE\x14\x86\xdc>T\x047\ +\xd1Bf{'nK\xcc\x87BFU\xbc\xee+=\ +\xa1K\xbe\x00\xf1\x94\xaeS8\xebW\xbc\xfd\xcc,\x1b\ +\xbf\x9bF\xf4\xb1m\xc8\xed{|\xa2\x22dvt\x91\ +\xed\xec\xf0\x83\x18\xf3\xd4y\xe6jo\xe4v\xdeb\xf2\ +?\xdaNi\xad\xc2W~\xc5[\x07m6-*^\ +\x94^\x95\xf0\xe9\x0b\xd4\xdc\x18\xf5\x89\xd0\x15F\x82G\ +\x13_j\xb8\x08`\xba\x89\x0f\xf8\xf7\xf1*\x92qa\ +\xe3\xf7i(S\xfcq\x0d\xa8=}\x01\x5c\xcf/\xa2\ +\xab\xced\xdfZ\x00\x10\x1b\xd0\xe4\x5c\xb7\x97Tl8\ +Kd\xc2\xad\xa2\xfa\x5c\xd2\xa94\xc1\xdbw\xcb@\xca\ +\xfe\xf5\xdfh\xeb<\x80z\x1c\xa0\xcc\xa3\xb6\xecV\xae\ +\xea\xe2y\x05\xc6\x1f\x94sGQ\xe7\x1d\x00\xd3\xdc\xaf\ +\x0dsC\xc6?Y\xb6\x9ak\xbfP\x92-\x0f\xad\xca\ +\xbe\x8e\xa3Zo\x8cE7%&\x5c\xa12\x0d\xa6\x9c\ +\xbbt\x81h\xb8RH\xd4\xd8\xd9\xddfn\xb6\x97\xd5\ +\xfdd\x99!\xe3\xa3\xdc\x93\xad\x15c\xd4\xc8.\x83O\ +\xe7\x17jjy\x80\xbb\x1b\xaa\x87p\xd6\xac\xc4mj\ +\xa8\x1c\xe8\xd1i\x805\xd5$\xbd\xd4S_\xd5\xad\xd0\ +h\x98\xcc\xceg\xabI\x09B\xbb\x01\xaa@\x85\xd9e\ +\x86\xb3o,\xe3\xd1\x0a\xdf\x87\x05/\xd6D\xba\xe7E\ +\xbc\xca\xf7?\xafF\x89\xa5\xd4\x06\xaa\xbe\xbe\xa2\xb02\ +e\xd3:hS?j3\xe2\x9e\xc5mj\xc0yj\ +\x15\xb9u\xabQ\xa9\xb8\xe1\x0beK,\xa5\xf7\x00\xbf\ +\x0dRQ\x15\xd6q%\x8d\x07\x81\x91r\x00\xc6\x85\xe8\ +}\x97\xd0\x94\x87x\x8b\xe6\x81\xab\x04\xee\x94\x98x\xc6\ +\xa0\x910nc\x1d\x982}\xa3\xdc\x08\x02\x03\xc0\xb6\ +\xc5>kFI\xfe\x98&\xf1\xab\x8d5\xe3;\xd7\x19\ +rO\xfa\xe7\xaf\x0d\x91]\xdfNf\xdb&(\xf5\xbe\ + \xfcnP\x8a2\xd4\x8d\xbb\xec\xf8\xe8!\xed?\xcf\ +\x96-^I\x92\xb1\x09\xa5.S\x7f\xe4\x18f\xe2Q\ +1 \xfa\x93\x91\x10?\x00\xe9BG\xd7\xa7\x8f\x88L\ +.\xbd\xf0b\x99\xa94\x91\x13g\x16\x9b\xd3A\xb5\x8e\ +\x9b{\x1be\x1a\xe1\x8bB\xcf\xf5\xe7\xcbN\xe6%\xc9\ +\xde\xbaa\xb1\xe9\xf3\xa1^\x996\x00\xa2\x1c\x02\xe6\xdb\ +y\xb4+\xc4\xd8\xe6\xd0\xffV\xdcI\xb6\xe1$\xdb\x0a\ +MY\xcfx\x1f\xc2\xdc:\xbe\xb7E\x86\x81\xc3\x85\x11\ +\x17_\xad\xe7A{\xcd\x7f.\x9eK,g\xf6\x85\xed\ +\x0b\x8d\xa2\x9f\x5c\xdd[{c\x1e\x00\xa0n\x92\x83\x22\ +\xf4\xe7\xff{5\xc2\xb9\xd7\x1b\xb9\xbde\xe9W\x22\xdb\ +\xd1\xc6\xccK;\xd1@\xa0\xd0|.\x17\xb1\xde\x9dg\ +)\xf4\xc4\xcfk\x8b\x069\x8f\xb0\xaa\xd0\x9e\xb8h\xb3\ +\xbeo\x9a\xf0Dqc\x16\xbe\x94\xe6\xa5\xf5\x11f\x9f\ +\xdb\x8a\x93\x5c\xbd\xc8S\xfcRZ47\x9f\xf8M;\ +=C\x1f\x90(\xb4\x9b\x9c\x92H\xd9\xacH\xd94\x8f\ +8\x04m]\x00\xa0V\x0d\xb9\xd68NG\x1b\xce\xda\ +\xd5\x10X8\x80T\xb8%\x9ev\xff\xd1\x1b\x1a\x5c\x80\ +T\x84\x0f\xb4\x5c\xd4xN\xf8\x1a\xd8Q\xca/\x0a\xe1\ +\x87.\xa1\xbfsXc\x0f\xd1p-^C\x14\xfc\xf7\ +\xc0\xb9\x80\xd6\xec\x19\xea\x95;E\xb9\xfc\x8eX;\xac\ +\xa1\xc94o\xa3\xec\x07\xa2~q\x15vA\x16\xf4\xe3\ +\x5c\xd4z\xef\xdan\xb1K\x9eL\xb9\xa3a\xae/j\ +8\x08\xec+\x05\xe2\x03\x90F\xf8\xcc\x13\xefP\xbe\xdb\ +\xfdT\xf5\xee\x8c\x0fi\x1d\x0e\xdd\xea\xb1\x13a3\xb0\ +f\xc1\xe79\x8c\x08\xa4<\xd1SA\xcf:6\xd4+\ +\xd3\xd5\xe4\xfd\x07O\xc0\xaf\xb9s\x8fj\x8f\x00\x00\x00\ +\x00IEND\xaeB`\x82\ \x00\x00kN\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -46350,6 +46512,10 @@ qt_resource_name = b"\ \x03v\xc2\x07\ \x00q\ \x00u\x00e\x00s\x00t\x00i\x00o\x00n\x00.\x00p\x00n\x00g\ +\x00\x0a\ +\x0ao\x8eg\ +\x00p\ +\x00e\x00r\x00s\x00o\x00n\x00.\x00p\x00n\x00g\ \x00\x06\ \x07\x84WG\ \x00q\ @@ -46374,6 +46540,10 @@ qt_resource_name = b"\ \x0c\xcb\xdb\xc7\ \x00m\ \x00o\x00n\x00e\x00y\x002\x00.\x00p\x00n\x00g\ +\x00\x08\ +\x09\xc5X\xc7\ +\x00u\ +\x00s\x00e\x00r\x00.\x00p\x00n\x00g\ \x00\x0b\ \x0e|&g\ \x00w\ @@ -46415,99 +46585,103 @@ qt_resource_name = b"\ qt_resource_struct = b"\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\ \x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00-\x00\x00\x00\x03\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00/\x00\x00\x00\x03\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x00\x10\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x01r\x82\xd3\xbeg\ -\x00\x00\x03|\x00\x00\x00\x00\x00\x01\x00\x0838\ +\x00\x00\x01r\x8a17\x84\ +\x00\x00\x03\x96\x00\x00\x00\x00\x00\x01\x00\x088\x10\ \x00\x00\x01ro \xc0+\ -\x00\x00\x00\xf0\x00\x00\x00\x00\x00\x01\x00\x01\x92\x83\ +\x00\x00\x00\xf0\x00\x00\x00\x00\x00\x01\x00\x01\x92\x9c\ \x00\x00\x01rybF\xf5\ -\x00\x00\x04.\x00\x00\x00\x00\x00\x01\x00\x09\xdbM\ +\x00\x00\x04^\x00\x00\x00\x00\x00\x01\x00\x09\xe5#\ \x00\x00\x01ro-O\xd6\ -\x00\x00\x00\x94\x00\x00\x00\x00\x00\x01\x00\x006\xd5\ +\x00\x00\x00\x94\x00\x00\x00\x00\x00\x01\x00\x006\xee\ \x00\x00\x01ryefk\ -\x00\x00\x036\x00\x00\x00\x00\x00\x01\x00\x074\x93\ +\x00\x00\x036\x00\x00\x00\x00\x00\x01\x00\x074\xac\ \x00\x00\x01ro!\xbci\ -\x00\x00\x01\xfc\x00\x00\x00\x00\x00\x01\x00\x04(\xe1\ +\x00\x00\x01\xfc\x00\x00\x00\x00\x00\x01\x00\x04(\xfa\ \x00\x00\x01r\x83\x0a\xde,\ -\x00\x00\x04d\x00\x00\x00\x00\x00\x01\x00\x0a\x10\xdd\ +\x00\x00\x04\x94\x00\x00\x00\x00\x00\x01\x00\x0a\x1a\xb3\ \x00\x00\x01ro \x94\xf5\ -\x00\x00\x01j\x00\x00\x00\x00\x00\x01\x00\x03N\xc8\ +\x00\x00\x01j\x00\x00\x00\x00\x00\x01\x00\x03N\xe1\ \x00\x00\x01rn\x81\xa0K\ -\x00\x00\x00j\x00\x00\x00\x00\x00\x01\x00\x001\xd8\ +\x00\x00\x00j\x00\x00\x00\x00\x00\x01\x00\x001\xf1\ \x00\x00\x01r\x83\x17T#\ -\x00\x00\x03\x18\x00\x00\x00\x00\x00\x01\x00\x071\xfb\ +\x00\x00\x03\x18\x00\x00\x00\x00\x00\x01\x00\x072\x14\ \x00\x00\x01r\x83\x18\xc72\ -\x00\x00\x000\x00\x00\x00\x00\x00\x01\x00\x00\x05b\ +\x00\x00\x000\x00\x00\x00\x00\x00\x01\x00\x00\x05{\ \x00\x00\x01r\x83\x18J\xbf\ -\x00\x00\x01\x9a\x00\x00\x00\x00\x00\x01\x00\x03\xd6&\ +\x00\x00\x01\x9a\x00\x00\x00\x00\x00\x01\x00\x03\xd6?\ \x00\x00\x01r\x83\x0b\xa39\ -\x00\x00\x01R\x00\x00\x00\x00\x00\x01\x00\x02\xe4\x97\ +\x00\x00\x01R\x00\x00\x00\x00\x00\x01\x00\x02\xe4\xb0\ \x00\x00\x01rn\x7f\x9a\xa2\ -\x00\x00\x02\xb2\x00\x00\x00\x00\x00\x01\x00\x06'b\ +\x00\x00\x02\xb2\x00\x00\x00\x00\x00\x01\x00\x06'{\ \x00\x00\x01rx\xd0\xef\xa4\ -\x00\x00\x01\xe6\x00\x00\x00\x00\x00\x01\x00\x04\x0c\xf0\ +\x00\x00\x01\xe6\x00\x00\x00\x00\x00\x01\x00\x04\x0d\x09\ \x00\x00\x01ro&U\x86\ -\x00\x00\x03\x92\x00\x00\x00\x00\x00\x01\x00\x08\xa35\ +\x00\x00\x03\xac\x00\x00\x00\x00\x00\x01\x00\x08\xa8\x0d\ \x00\x00\x01ro'\x5c\xdd\ -\x00\x00\x04\xb2\x00\x00\x00\x00\x00\x01\x00\x0b\x0a\xde\ +\x00\x00\x04\xe2\x00\x00\x00\x00\x00\x01\x00\x0b\x14\xb4\ \x00\x00\x01rxL\xc3L\ -\x00\x00\x02\x84\x00\x00\x00\x00\x00\x01\x00\x05t\xa8\ +\x00\x00\x02\x84\x00\x00\x00\x00\x00\x01\x00\x05t\xc1\ \x00\x00\x01rn\x80a\x98\ -\x00\x00\x03T\x00\x00\x00\x00\x00\x01\x00\x07L`\ +\x00\x00\x03n\x00\x00\x00\x00\x00\x01\x00\x07Q8\ \x00\x00\x01ro!\x10\x8b\ -\x00\x00\x00\xbc\x00\x00\x00\x00\x00\x01\x00\x015\xfa\ +\x00\x00\x00\xbc\x00\x00\x00\x00\x00\x01\x00\x016\x13\ \x00\x00\x01ro6\xcc\x14\ -\x00\x00\x03f\x00\x00\x00\x00\x00\x01\x00\x07\xbe\xef\ +\x00\x00\x03\x80\x00\x00\x00\x00\x00\x01\x00\x07\xc3\xc7\ \x00\x00\x01ryf\xd9E\ -\x00\x00\x02\xe4\x00\x00\x00\x00\x00\x01\x00\x06~\xdc\ +\x00\x00\x02\xe4\x00\x00\x00\x00\x00\x01\x00\x06~\xf5\ \x00\x00\x01rn\x83W\xb2\ -\x00\x00\x02T\x00\x00\x00\x00\x00\x01\x00\x04\xd7\xa1\ +\x00\x00\x02T\x00\x00\x00\x00\x00\x01\x00\x04\xd7\xba\ \x00\x00\x01rn\x80\x8e_\ -\x00\x00\x01\xcc\x00\x00\x00\x00\x00\x01\x00\x03\xd8\xa1\ +\x00\x00\x01\xcc\x00\x00\x00\x00\x00\x01\x00\x03\xd8\xba\ \x00\x00\x01ro'\xd9\xb1\ -\x00\x00\x02\x9a\x00\x00\x00\x00\x00\x01\x00\x05\xc2\xb6\ +\x00\x00\x02\x9a\x00\x00\x00\x00\x00\x01\x00\x05\xc2\xcf\ \x00\x00\x01ro!\x80\x9f\ -\x00\x00\x04B\x00\x00\x00\x00\x00\x01\x00\x09\xf2'\ +\x00\x00\x04r\x00\x00\x00\x00\x00\x01\x00\x09\xfb\xfd\ \x00\x00\x01ro*{\xa5\ -\x00\x00\x04\x96\x00\x00\x00\x00\x00\x01\x00\x0a\xd1\xcb\ +\x00\x00\x04\xc6\x00\x00\x00\x00\x00\x01\x00\x0a\xdb\xa1\ \x00\x00\x01rxA\xa0\xe6\ -\x00\x00\x02\xc8\x00\x00\x00\x00\x00\x01\x00\x06[\x1e\ +\x00\x00\x03\xfc\x00\x00\x00\x00\x00\x01\x00\x09(\xc5\ +\x00\x00\x01r\x8a:\x08\x8f\ +\x00\x00\x02\xc8\x00\x00\x00\x00\x00\x01\x00\x06[7\ \x00\x00\x01ro'\xf7\xd9\ -\x00\x00\x024\x00\x00\x00\x00\x00\x01\x00\x04xM\ +\x00\x00\x03T\x00\x00\x00\x00\x00\x01\x00\x07Ly\ +\x00\x00\x01r\x8a6j\xde\ +\x00\x00\x024\x00\x00\x00\x00\x00\x01\x00\x04xf\ \x00\x00\x01ro+U:\ -\x00\x00\x00H\x00\x00\x00\x00\x00\x01\x00\x00\x15\x5c\ +\x00\x00\x00H\x00\x00\x00\x00\x00\x01\x00\x00\x15u\ \x00\x00\x01ro\x22L\x9b\ -\x00\x00\x01\x1c\x00\x00\x00\x00\x00\x01\x00\x02QY\ +\x00\x00\x01\x1c\x00\x00\x00\x00\x00\x01\x00\x02Qr\ \x00\x00\x01rn\x80\xbaA\ -\x00\x00\x016\x00\x00\x00\x00\x00\x01\x00\x02\x9d\x07\ +\x00\x00\x016\x00\x00\x00\x00\x00\x01\x00\x02\x9d \ \x00\x00\x01ro\x14<\x9f\ -\x00\x00\x03\xae\x00\x00\x00\x00\x00\x01\x00\x08\xc3\xe4\ +\x00\x00\x03\xc8\x00\x00\x00\x00\x00\x01\x00\x08\xc8\xbc\ \x00\x00\x01ro\x14\xa8\xb6\ -\x00\x00\x00\xa8\x00\x00\x00\x00\x00\x01\x00\x00\xb0!\ +\x00\x00\x00\xa8\x00\x00\x00\x00\x00\x01\x00\x00\xb0:\ \x00\x00\x01ro\x1e\xc7F\ -\x00\x00\x03\xfe\x00\x00\x00\x00\x00\x01\x00\x09\x8f?\ +\x00\x00\x04.\x00\x00\x00\x00\x00\x01\x00\x09\x99\x15\ \x00\x00\x01rxK\x8a\x1d\ -\x00\x00\x02p\x00\x00\x00\x00\x00\x01\x00\x05\x22\x97\ +\x00\x00\x02p\x00\x00\x00\x00\x00\x01\x00\x05\x22\xb0\ \x00\x00\x01ro!G\x15\ -\x00\x00\x01\x82\x00\x00\x00\x00\x00\x01\x00\x03\xb6\x09\ +\x00\x00\x01\x82\x00\x00\x00\x00\x00\x01\x00\x03\xb6\x22\ \x00\x00\x01ro*\xb4%\ -\x00\x00\x00\xd0\x00\x00\x00\x00\x00\x01\x00\x01\x82!\ +\x00\x00\x00\xd0\x00\x00\x00\x00\x00\x01\x00\x01\x82:\ \x00\x00\x01r\x82\xb4i\x96\ -\x00\x00\x03\xc8\x00\x00\x00\x00\x00\x01\x00\x08\xcd~\ +\x00\x00\x03\xe2\x00\x00\x00\x00\x00\x01\x00\x08\xd2V\ \x00\x00\x01ryaf\xee\ -\x00\x00\x02\xfe\x00\x00\x00\x00\x00\x01\x00\x06\xcc\xa4\ +\x00\x00\x02\xfe\x00\x00\x00\x00\x00\x01\x00\x06\xcc\xbd\ \x00\x00\x01ryg+\xf0\ -\x00\x00\x04|\x00\x00\x00\x00\x00\x01\x00\x0an\xf3\ +\x00\x00\x04\xac\x00\x00\x00\x00\x00\x01\x00\x0ax\xc9\ \x00\x00\x01rx\xcbU\xa4\ -\x00\x00\x04\x1a\x00\x00\x00\x00\x00\x01\x00\x09\xb3\xbc\ +\x00\x00\x04J\x00\x00\x00\x00\x00\x01\x00\x09\xbd\x92\ \x00\x00\x01rx\xcc\xdf'\ -\x00\x00\x02\x1c\x00\x00\x00\x00\x00\x01\x00\x04-y\ +\x00\x00\x02\x1c\x00\x00\x00\x00\x00\x01\x00\x04-\x92\ \x00\x00\x01rn\x80\xf2c\ -\x00\x00\x03\xe2\x00\x00\x00\x00\x00\x01\x00\x09#\xed\ +\x00\x00\x04\x12\x00\x00\x00\x00\x00\x01\x00\x09-\xc3\ \x00\x00\x01ro!-\x86\ -\x00\x00\x01\x08\x00\x00\x00\x00\x00\x01\x00\x01\xe3\xa2\ +\x00\x00\x01\x08\x00\x00\x00\x00\x00\x01\x00\x01\xe3\xbb\ \x00\x00\x01rn\x7f\xe8!\ " diff --git a/mainwindow.py b/mainwindow.py index eeb1fb5..874e7fb 100644 --- a/mainwindow.py +++ b/mainwindow.py @@ -111,6 +111,7 @@ class Ui_MainWindow(object): self.treeView.setSizePolicy(sizePolicy) self.treeView.setMaximumSize(QSize(400, 16777215)) self.splitter_2.addWidget(self.treeView) + self.treeView.header().setVisible(False) self.splitter = QSplitter(self.splitter_2) self.splitter.setObjectName(u"splitter") self.splitter.setOrientation(Qt.Vertical) diff --git a/mainwindow.ui b/mainwindow.ui index 36af336..207f5b3 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -69,6 +69,9 @@ 16777215 + + false + diff --git a/searchtitle.md b/searchtitle.md index 3727ac9..c07cfea 100644 --- a/searchtitle.md +++ b/searchtitle.md @@ -1,6 +1,5 @@ TYPE|BOOKNAME|AUTHOR|MARKTIME|CONTENT --|--|--|--|-- -HL|薛兆丰经济学讲义 |薛兆丰|2020/1/13 8:11:05|么到底什么叫边际?边际就是“新增”带来的“新增”。 例如,边际成本就是每新增一个单位产品所需要付出的新增成本;边际收入是每多卖一个产品能够带来的新增收入;边际产量是每新增一份投入所带来的新增产量;边际效用是每消耗一个单位的商品所能带来的新增享受。 -HL|薛兆丰经济学讲义 |薛兆丰|2020/1/30 10:23:58|一个国家很大,贫富有差距,并非每个学校和家长都能负担得起这样标准的校车。标准太高,就会逼着很多学校,尤其是农村的学校放弃提供校车,家长们就只能使用安全性能更低的交通工具,比如自己骑自行车或雇用黑车等,结果是孩子们享受到的安全保障反而降低了。 -NT|薛兆丰经济学讲义 |薛兆丰|2020/1/30 10:26:31|山寨 假货 问题 -HL|薛兆丰经济学讲义 |薛兆丰|2020/1/30 10:29:41|为了克服信息不对称,建立互信,人类社会构想出了各种各样有趣的解决方案,从重复交易到第三方背书,从质保、延保,再到收益共享。此外,还有三种非常接近的建立信任的办法:付出沉没成本、给出人质或者给出抵押。 +HL|薛兆丰经济学讲义|薛兆丰|2020/1/13 8:11:05|么到底什么叫边际?边际就是“新增”带来的“新增”。 例如,边际成本就是每新增一个单位产品所需要付出的新增成本;边际收入是每多卖一个产品能够带来的新增收入;边际产量是每新增一份投入所带来的新增产量;边际效用是每消耗一个单位的商品所能带来的新增享受。 +HL|薛兆丰经济学讲义|薛兆丰|2020/1/30 10:23:58|一个国家很大,贫富有差距,并非每个学校和家长都能负担得起这样标准的校车。标准太高,就会逼着很多学校,尤其是农村的学校放弃提供校车,家长们就只能使用安全性能更低的交通工具,比如自己骑自行车或雇用黑车等,结果是孩子们享受到的安全保障反而降低了。 +NT|薛兆丰经济学讲义|薛兆丰|2020/1/30 10:26:31|山寨 假货 问题 diff --git a/tclip.txt b/tclip.txt index 9a8dad3..1e9d0b1 100755 --- a/tclip.txt +++ b/tclip.txt @@ -18,8 +18,13 @@ 山寨 假货 问题 ========== -薛兆丰经济学讲义 (薛兆丰) -- 您在位置 #4382-4384的标注 | 添加于 2020年1月30日星期四 上午10:29:41 +庆余年(精校版) (猫腻) +- 您在位置 #48484-48484的标注 | 添加于 2020年1月19日星期日 下午8:00:29 -为了克服信息不对称,建立互信,人类社会构想出了各种各样有趣的解决方案,从重复交易到第三方背书,从质保、延保,再到收益共享。此外,还有三种非常接近的建立信任的办法:付出沉没成本、给出人质或者给出抵押。 +园子里的护卫能掺多少人就掺多少人,我会派人盯着 +========== +庆余年(精校版) (猫腻) +- 您在位置 #49901-49901的标注 | 添加于 2020年1月20日星期一 下午7:57:10 + +叶灵儿叹了口 ========== diff --git a/test_kman.py b/test_kman.py index 1592113..d671699 100644 --- a/test_kman.py +++ b/test_kman.py @@ -1,11 +1,11 @@ -import unittest +import unittest2 from collections import defaultdict from kman import * -class TestKman(unittest.TestCase): +class TestKman(unittest2.TestCase): # initial def setUp(self): CLIPPATH = './test.data' @@ -13,9 +13,15 @@ class TestKman(unittest.TestCase): LOG2FILE = 1 DELIMITER= '|' + self.km = kMan() + global t_bm_sec global t_hl_sec global t_nt_sec + global t_hl_sec2 + global t_hl_sec3 + global t_hl_sec4 + self.t_num_nt = 0 global t_books t_bm_sec = ["""另一半中国史 (高洪雷) """, \ """- 您在位置 #2468 的书签 | 添加于 2020年1月12日星期日 下午11:09:06 """] @@ -25,22 +31,55 @@ class TestKman(unittest.TestCase): t_nt_sec = ["""薛兆丰经济学讲义 (薛兆丰) """, \ """- 您在位置 #4286 的笔记 | 添加于 2020年1月30日星期四 下午10:26:31 """, \ """山寨 假货 问题 """] + t_hl_sec2 = ["""枪炮、病菌与钢铁 : 人类社会的命运 (世纪人文系列丛书·开放人文) (贾雷德·戴蒙德) """,\ + """- 您在位置 #4267-4268的标注 | 添加于 2020年1月29日星期三 上午12:42:32 """,\ + """从柏拉图到马克思的所有政治理论家都提出过这个问题xxxx"""] + t_hl_sec3 = ["""枪炮、病菌与钢铁(贾雷德·戴蒙德)""",\ + """- 您在位置 #4267-4268的标注 | 添加于 2020年1月29日星期三 上午12:42:32""",\ + """从柏拉图到马克思的所有政治理论家都提出过这个问题yyyy"""] + t_hl_sec4 = ["""枪炮、病菌与钢铁 : 人类社会的命运 (世纪人文系列丛书·开放人文) (贾雷德·戴蒙德)""",\ + """- 您在位置 #4267-4268的标注 | 添加于 2020年1月29日星期三 上午12:42:32""",\ + """从柏拉图到马克思的所有政治理论家都提出过这个问题zzzz"""] t_books = defaultdict(dict) def cre_tbooks(self): # parsing section & fill data structure - t_secd = parse_section(t_bm_sec,0) + self.t_num_nt = 0 + t_secd = self.km.parse_section(t_bm_sec,0) - t_secd = parse_section(t_hl_sec,1) + self.t_num_nt += 1 + t_secd = self.km.parse_section(t_hl_sec,self.t_num_nt) bn = t_secd['bookname'] t_books[bn]['author'] = t_secd[bn]['author'] - t_books[bn]['1'] = t_secd[bn]['1'] + t_books[bn][str(self.t_num_nt)] = t_secd[bn][str(self.t_num_nt)] t_secd.clear() - t_secd = parse_section(t_nt_sec,2) + self.t_num_nt += 1 + t_secd = self.km.parse_section(t_nt_sec,self.t_num_nt) bn = t_secd['bookname'] t_books[bn]['author'] = t_secd[bn]['author'] - t_books[bn]['2'] = t_secd[bn]['2'] + t_books[bn][str(self.t_num_nt)] = t_secd[bn][str(self.t_num_nt)] + t_secd.clear() + + self.t_num_nt += 1 + t_secd = self.km.parse_section(t_hl_sec2,self.t_num_nt) + bn = t_secd['bookname'] + t_books[bn]['author'] = t_secd[bn]['author'] + t_books[bn][str(self.t_num_nt)] = t_secd[bn][str(self.t_num_nt)] + t_secd.clear() + + self.t_num_nt += 1 + t_secd = self.km.parse_section(t_hl_sec3,self.t_num_nt) + bn = t_secd['bookname'] + t_books[bn]['author'] = t_secd[bn]['author'] + t_books[bn][str(self.t_num_nt)] = t_secd[bn][str(self.t_num_nt)] + t_secd.clear() + + self.t_num_nt += 1 + t_secd = self.km.parse_section(t_hl_sec4,self.t_num_nt) + bn = t_secd['bookname'] + t_books[bn]['author'] = t_secd[bn]['author'] + t_books[bn][str(self.t_num_nt)] = t_secd[bn][str(self.t_num_nt)] t_secd.clear() return t_books @@ -48,13 +87,13 @@ class TestKman(unittest.TestCase): # test function parse_section def test_parse_section(self): # parsing section & fill data structure - t_secd = parse_section(t_bm_sec,0) + t_secd = self.km.parse_section(t_bm_sec,0) self.assertEqual(t_secd,False) - t_secd = parse_section(t_hl_sec,1) + t_secd = self.km.parse_section(t_hl_sec,1) bn = t_secd['bookname'] self.assertIsNotNone(t_secd) - self.assertEqual(bn,'薛兆丰经济学讲义 ') + self.assertEqual(bn,'薛兆丰经济学讲义') self.assertEqual(t_secd[bn]['author'],'薛兆丰') self.assertEqual(t_secd[bn]['1']['type'],'HL') self.assertEqual(t_secd[bn]['1']['position'],'1408-1410') @@ -67,10 +106,10 @@ class TestKman(unittest.TestCase): t_books[bn]['1'] = t_secd[bn]['1'] t_secd.clear() - t_secd = parse_section(t_nt_sec,2) + t_secd = self.km.parse_section(t_nt_sec,2) bn = t_secd['bookname'] self.assertIsNotNone(t_secd) - self.assertEqual(bn,'薛兆丰经济学讲义 ') + self.assertEqual(bn,'薛兆丰经济学讲义') self.assertEqual(t_secd[bn]['author'],'薛兆丰') self.assertEqual(t_secd[bn]['2']['type'],'NT') self.assertEqual(t_secd[bn]['2']['position'],'4286') @@ -86,7 +125,7 @@ class TestKman(unittest.TestCase): # test drop_duplicate def test_drop_duplicate(self): t_books = self.cre_tbooks() - t_secd = parse_section(t_hl_sec,3) + t_secd = self.km.parse_section(t_hl_sec,3) bn = t_secd['bookname'] t_books_du = t_books.copy() t_books_du[bn]['3'] = t_secd[bn]['3'] @@ -94,7 +133,7 @@ class TestKman(unittest.TestCase): self.assertIsInstance(t_books_du[bn]['3'],dict) try: - t_books_du = drop_duplicate(t_books_du) + t_books_du = self.km.drop_duplicate(t_books_du) t = t_books_du[bn]['3'] except KeyError as keyerror: print("与预期匹配,sidx 3 重复被删除,抛出: %s" % 'keyerror') @@ -104,31 +143,58 @@ class TestKman(unittest.TestCase): # test function format_time() def test_format_time(self): t_ds = '2020年1月13日 星期一 下午 8:11:05' - t_ds = format_time(t_ds) + t_ds = self.km.format_time(t_ds) self.assertEqual(t_ds, '2020/1/13 20:11:05') # test function format_data def test_format_data(self): t_books = self.cre_tbooks() - t_out = format_data(t_books, ft='MD') + t_out = self.km.format_data(t_books, ft='MD') self.assertEqual(t_out[0], 'TYPE|BOOKNAME|AUTHOR|MARKTIME|CONTENT') self.assertEqual(t_out[1], '--|--|--|--|--') - self.assertEqual(t_out[2], 'HL|薛兆丰经济学讲义 |薛兆丰|2020/1/13 8:11:05|边际就是“新增”带来的“新增”。\n') + self.assertEqual(t_out[2], 'HL|薛兆丰经济学讲义|薛兆丰|2020/1/13 8:11:05|边际就是“新增”带来的“新增”。\n') t_out.clear() def test_add_note_to_highlight(self): t_books = self.cre_tbooks() - t_books_remove_nt = add_note_to_highlight(t_books) - for k in t_books_remove_nt.keys(): - bn = k - self.assertEqual((t_books_remove_nt[bn]['1']['content']).replace('\n',''),\ + t_books_remove_nt = self.km.add_note_to_highlight(t_books) + self.assertEqual((t_books_remove_nt['薛兆丰经济学讲义']['1']['content']).replace('\n',''),\ '边际就是“新增”带来的“新增”。'+NTPREF+ '山寨 假货 问题') def test_get_kindle_path(self): - kp = get_kindle_path() + kp = self.km.get_kindle_path() s = u"kindle disconnected" if not kp else u"kindle connected {}".format(kp) print(s) + def test_get_bookname_num(self): + t_books = self.cre_tbooks() + [nu, bn] = self.km.get_bookname_num(t_books) + self.assertEqual(nu, self.t_num_nt) + self.assertEqual(bn['薛兆丰经济学讲义'],2) + + def test_get_author_num(self): + t_books = self.cre_tbooks() + [nu, bn] = self.km.get_author_num(t_books) + self.assertEqual(nu, self.t_num_nt) + self.assertEqual(bn['薛兆丰'],2) + + def test_filter_clips(self): + t_books = self.cre_tbooks() + # no filter + bn = self.km.filter_clips(t_books, '薛兆丰', 0) + print('filter 0 \n',bn) + bn = {} + + # by bookname + bn = self.km.filter_clips(t_books, '枪炮、病菌与钢铁 : 人类社会的命运 (世纪人文系列丛书·开放人文)', 1) + print('filter 1 \n',bn) + bn = {} + + # by author + bn = self.km.filter_clips(t_books, '贾雷德·戴蒙德', 2) + print('filter 2 \n',bn,'\n===========\n') + bn = {} + """ def test_search_clip(self): pass @@ -149,17 +215,17 @@ class TestKman(unittest.TestCase): if __name__ == '__main__': """ - suite = unittest.TestSuite () + suite = unittest2.TestSuite () suite.addTest(TestKman('test_parse_section')) suite.addTest(TestKman('test_format_time')) suite.addTest(TestKman('test_format_data')) suite.addTest(TestKman('test_drop_duplicate')) suite.addTest(TestKman('test_add_note_to_highlight')) - run = unittest.TextTestRunner (verbosity=2) + run = unittest2.TextTestRunner (verbosity=2) run.run (suite) """ # not callable sequency - unittest.main() + unittest2.main() diff --git a/tthread.py b/tthread.py new file mode 100644 index 0000000..039c0ca --- /dev/null +++ b/tthread.py @@ -0,0 +1,106 @@ + +import sys +import pyqtgraph as pg +from PyQt5.QtGui import * +from PyQt5.QtWidgets import * +from PyQt5.QtCore import QThread, pyqtSignal, QTimer +import numpy as np + +class PlotSin(QThread): + + # 定义信号,self.y 是 numpy.array,所以信号数据类型为 object + signal = pyqtSignal(object) + + def __init__(self, parent=None): + super().__init__() + self.y = None + self.phase = 0 + + def sin(self): + self.x = np.arange(0, 3.0, 0.01) + self.y = np.sin(2 * np.pi * self.x + self.phase) + self.phase += 0.1 + QThread.msleep(200) # 等待200毫秒 + + def run(self): + for _ in range(300): + self.sin() + self.signal.emit(self.y) # 向连接槽发射信号 self.y + +class PlotSin_MainWindow(QDialog): + + def __init__(self): + super().__init__() + self.initUI() + self.clock_time = 0 + self.timer = QTimer(self) # 生成定时器 + self.timer.timeout.connect(self.clock) # 绑定计时函数 self.clock + + def initUI(self): + + self.creatContorls("时间显示:") + self.creatResult("函数绘制:") + + layout = QHBoxLayout() + layout.addWidget(self.controlsGroup) + layout.addWidget(self.resultGroup) + self.setLayout(layout) + self.beginButton.clicked.connect(self.clock_begin) + self.setGeometry(300, 300, 600, 300) + self.setWindowTitle('Plot Sine') + self.show() + + def creatContorls(self,title): + self.controlsGroup = QGroupBox(title) + self.beginButton = QPushButton("开始") + numberLabel = QLabel("运行时间:") + self.clockLabel = QLabel("") + controlsLayout = QGridLayout() + controlsLayout.addWidget(numberLabel, 0, 0) + controlsLayout.addWidget(self.clockLabel, 0, 1) + controlsLayout.addWidget(self.beginButton, 3, 0) + self.controlsGroup.setLayout(controlsLayout) + + def creatResult(self,title): + self.resultGroup = QGroupBox(title) + self.guiplot = pg.PlotWidget() + gridLayout = QGridLayout() + gridLayout.addWidget(self.guiplot,0,2,2,3) + self.resultGroup.setLayout(gridLayout) + + def clock_begin(self): + if not self.timer.isActive(): + self.recorder_thread = PlotSin() + self.recorder_thread.signal.connect(self.displaySin) # 绑定信号槽函数 + self.recorder_thread.start() # 线程执行 + self.clock() + self.timer.start(1000) + else: + self.beginButton.setText("开始") + self.clockLabel.setText("") + self.recorder_thread.terminate() # 终止线程 + self.timer.stop() # 终止定时器 + self.clock_time = 0 + text = str(self.clock_time) + "s" + self.clockLabel.setText(text) + + def clock(self): + text = str(self.clock_time) + "s" + self.clockLabel.setText(text) + if self.clock_time == 0: + self.beginButton.setText("结束") + + self.clock_time += 1 + + def plotSin(self, y): + self.guiplot.clear() + self.guiplot.plot(y) + + def displaySin(self, y): + self.plotSin(y) + +if __name__ == '__main__': + app = QApplication(sys.argv) + window = PlotSin_MainWindow() + window.show() + sys.exit(app.exec_()) diff --git a/xx b/xx index 925c5fd..b3a5c9b 100644 --- a/xx +++ b/xx @@ -1 +1 @@ -{"\u859b\u5146\u4e30\u7ecf\u6d4e\u5b66\u8bb2\u4e49 ": {"author": "\u859b\u5146\u4e30", "1": {"type": "HL", "position": "1408-1410", "day": "2020\u5e741\u670813\u65e5", "week": "\u661f\u671f\u4e00", "meridiem": "\u4e0a\u5348", "time": "8:11:05", "content": "\u4e48\u5230\u5e95\u4ec0\u4e48\u53eb\u8fb9\u9645\uff1f\u8fb9\u9645\u5c31\u662f\u201c\u65b0\u589e\u201d\u5e26\u6765\u7684\u201c\u65b0\u589e\u201d\u3002 \u4f8b\u5982\uff0c\u8fb9\u9645\u6210\u672c\u5c31\u662f\u6bcf\u65b0\u589e\u4e00\u4e2a\u5355\u4f4d\u4ea7\u54c1\u6240\u9700\u8981\u4ed8\u51fa\u7684\u65b0\u589e\u6210\u672c\uff1b\u8fb9\u9645\u6536\u5165\u662f\u6bcf\u591a\u5356\u4e00\u4e2a\u4ea7\u54c1\u80fd\u591f\u5e26\u6765\u7684\u65b0\u589e\u6536\u5165\uff1b\u8fb9\u9645\u4ea7\u91cf\u662f\u6bcf\u65b0\u589e\u4e00\u4efd\u6295\u5165\u6240\u5e26\u6765\u7684\u65b0\u589e\u4ea7\u91cf\uff1b\u8fb9\u9645\u6548\u7528\u662f\u6bcf\u6d88\u8017\u4e00\u4e2a\u5355\u4f4d\u7684\u5546\u54c1\u6240\u80fd\u5e26\u6765\u7684\u65b0\u589e\u4eab\u53d7\u3002"}, "2": {"type": "HL", "position": "4284-4286", "day": "2020\u5e741\u670830\u65e5", "week": "\u661f\u671f\u56db", "meridiem": "\u4e0a\u5348", "time": "10:23:58", "content": "\u4e00\u4e2a\u56fd\u5bb6\u5f88\u5927\uff0c\u8d2b\u5bcc\u6709\u5dee\u8ddd\uff0c\u5e76\u975e\u6bcf\u4e2a\u5b66\u6821\u548c\u5bb6\u957f\u90fd\u80fd\u8d1f\u62c5\u5f97\u8d77\u8fd9\u6837\u6807\u51c6\u7684\u6821\u8f66\u3002\u6807\u51c6\u592a\u9ad8\uff0c\u5c31\u4f1a\u903c\u7740\u5f88\u591a\u5b66\u6821\uff0c\u5c24\u5176\u662f\u519c\u6751\u7684\u5b66\u6821\u653e\u5f03\u63d0\u4f9b\u6821\u8f66\uff0c\u5bb6\u957f\u4eec\u5c31\u53ea\u80fd\u4f7f\u7528\u5b89\u5168\u6027\u80fd\u66f4\u4f4e\u7684\u4ea4\u901a\u5de5\u5177\uff0c\u6bd4\u5982\u81ea\u5df1\u9a91\u81ea\u884c\u8f66\u6216\u96c7\u7528\u9ed1\u8f66\u7b49\uff0c\u7ed3\u679c\u662f\u5b69\u5b50\u4eec\u4eab\u53d7\u5230\u7684\u5b89\u5168\u4fdd\u969c\u53cd\u800c\u964d\u4f4e\u4e86\u3002--CG\u6ce8:\u5c71\u5be8 \u5047\u8d27 \u95ee\u9898"}, "4": {"type": "HL", "position": "4382-4384", "day": "2020\u5e741\u670830\u65e5", "week": "\u661f\u671f\u56db", "meridiem": "\u4e0a\u5348", "time": "10:29:41", "content": "\u4e3a\u4e86\u514b\u670d\u4fe1\u606f\u4e0d\u5bf9\u79f0\uff0c\u5efa\u7acb\u4e92\u4fe1\uff0c\u4eba\u7c7b\u793e\u4f1a\u6784\u60f3\u51fa\u4e86\u5404\u79cd\u5404\u6837\u6709\u8da3\u7684\u89e3\u51b3\u65b9\u6848\uff0c\u4ece\u91cd\u590d\u4ea4\u6613\u5230\u7b2c\u4e09\u65b9\u80cc\u4e66\uff0c\u4ece\u8d28\u4fdd\u3001\u5ef6\u4fdd\uff0c\u518d\u5230\u6536\u76ca\u5171\u4eab\u3002\u6b64\u5916\uff0c\u8fd8\u6709\u4e09\u79cd\u975e\u5e38\u63a5\u8fd1\u7684\u5efa\u7acb\u4fe1\u4efb\u7684\u529e\u6cd5\uff1a\u4ed8\u51fa\u6c89\u6ca1\u6210\u672c\u3001\u7ed9\u51fa\u4eba\u8d28\u6216\u8005\u7ed9\u51fa\u62b5\u62bc\u3002"}, "lines": 4}} \ No newline at end of file +{"\u859b\u5146\u4e30\u7ecf\u6d4e\u5b66\u8bb2\u4e49": {"author": "\u859b\u5146\u4e30", "1": {"type": "HL", "position": "1408-1410", "day": "2020\u5e741\u670813\u65e5", "week": "\u661f\u671f\u4e00", "meridiem": "\u4e0a\u5348", "time": "8:11:05", "content": "\u4e48\u5230\u5e95\u4ec0\u4e48\u53eb\u8fb9\u9645\uff1f\u8fb9\u9645\u5c31\u662f\u201c\u65b0\u589e\u201d\u5e26\u6765\u7684\u201c\u65b0\u589e\u201d\u3002 \u4f8b\u5982\uff0c\u8fb9\u9645\u6210\u672c\u5c31\u662f\u6bcf\u65b0\u589e\u4e00\u4e2a\u5355\u4f4d\u4ea7\u54c1\u6240\u9700\u8981\u4ed8\u51fa\u7684\u65b0\u589e\u6210\u672c\uff1b\u8fb9\u9645\u6536\u5165\u662f\u6bcf\u591a\u5356\u4e00\u4e2a\u4ea7\u54c1\u80fd\u591f\u5e26\u6765\u7684\u65b0\u589e\u6536\u5165\uff1b\u8fb9\u9645\u4ea7\u91cf\u662f\u6bcf\u65b0\u589e\u4e00\u4efd\u6295\u5165\u6240\u5e26\u6765\u7684\u65b0\u589e\u4ea7\u91cf\uff1b\u8fb9\u9645\u6548\u7528\u662f\u6bcf\u6d88\u8017\u4e00\u4e2a\u5355\u4f4d\u7684\u5546\u54c1\u6240\u80fd\u5e26\u6765\u7684\u65b0\u589e\u4eab\u53d7\u3002"}, "2": {"type": "HL", "position": "4284-4286", "day": "2020\u5e741\u670830\u65e5", "week": "\u661f\u671f\u56db", "meridiem": "\u4e0a\u5348", "time": "10:23:58", "content": "\u4e00\u4e2a\u56fd\u5bb6\u5f88\u5927\uff0c\u8d2b\u5bcc\u6709\u5dee\u8ddd\uff0c\u5e76\u975e\u6bcf\u4e2a\u5b66\u6821\u548c\u5bb6\u957f\u90fd\u80fd\u8d1f\u62c5\u5f97\u8d77\u8fd9\u6837\u6807\u51c6\u7684\u6821\u8f66\u3002\u6807\u51c6\u592a\u9ad8\uff0c\u5c31\u4f1a\u903c\u7740\u5f88\u591a\u5b66\u6821\uff0c\u5c24\u5176\u662f\u519c\u6751\u7684\u5b66\u6821\u653e\u5f03\u63d0\u4f9b\u6821\u8f66\uff0c\u5bb6\u957f\u4eec\u5c31\u53ea\u80fd\u4f7f\u7528\u5b89\u5168\u6027\u80fd\u66f4\u4f4e\u7684\u4ea4\u901a\u5de5\u5177\uff0c\u6bd4\u5982\u81ea\u5df1\u9a91\u81ea\u884c\u8f66\u6216\u96c7\u7528\u9ed1\u8f66\u7b49\uff0c\u7ed3\u679c\u662f\u5b69\u5b50\u4eec\u4eab\u53d7\u5230\u7684\u5b89\u5168\u4fdd\u969c\u53cd\u800c\u964d\u4f4e\u4e86\u3002--CG\u6ce8:\u5c71\u5be8 \u5047\u8d27 \u95ee\u9898"}, "lines": 3}, "\u5e86\u4f59\u5e74(\u7cbe\u6821\u7248\uff09": {"author": "\u732b\u817b", "4": {"type": "HL", "position": "48484-48484", "day": "2020\u5e741\u670819\u65e5", "week": "\u661f\u671f\u65e5", "meridiem": "\u4e0b\u5348", "time": "8:00:29", "content": "\uff1a\u201c\u56ed\u5b50\u91cc\u7684\u62a4\u536b\u80fd\u63ba\u591a\u5c11\u4eba\u5c31\u63ba\u591a\u5c11\u4eba\uff0c\u6211\u4f1a\u6d3e\u4eba\u76ef\u7740\uff0c"}, "5": {"type": "HL", "position": "49901-49901", "day": "2020\u5e741\u670820\u65e5", "week": "\u661f\u671f\u4e00", "meridiem": "\u4e0b\u5348", "time": "7:57:10", "content": "\u53f6\u7075\u513f\u53f9\u4e86\u53e3"}, "lines": 2}} \ No newline at end of file