kindle manager

This commit is contained in:
gavin
2020-06-12 23:33:35 +08:00
parent 43c602d8d6
commit 8dbd2357b2
17 changed files with 3570 additions and 103 deletions

View File

@@ -27,6 +27,20 @@ from kman import *
# import binary resource file(kmanapp_rc.py)
import kmanapp_rc
notes_temp = """<br><span style='font-size:22pt;color:maroon'>《{bookname}》</span>
<span style='font-size:22pt;color:maroon'> {author} </span>
<span style='font-size:22pt;color:maroon'> ({time}) </span>
<span style='font-size:11pt;color:maroon'> 【{note}】 </span><hr><br><br>
<span style='font-size:22pt;color:#31849B'>{content}</span>
<span style='font-size:11pt;color:maroon'>【P{position}】</span><br>"""
words_temp = """<br><span style='font-size:22pt;color:maroon'>{usage}</span><br><br>
<span style='font-size:12pt;color:maroon'> {bookname} </span>
<span style='font-size:12pt;color:maroon'> {author} </span>
<span style='font-size:12pt;color:maroon'> {category} </span>
<span style='font-size:12pt;color:maroon'> {timestamp} </span>
<span style='font-size:12pt;color:#31849B'>{position}</span><hr><br><br>"""
ONLY_TEST = 1
class kmanWindow(QMainWindow):
@@ -45,19 +59,34 @@ class kmanWindow(QMainWindow):
self.add_ui_component()
# initial tree selected
self.tree_selected = 'note_root'
self.km = kMan()
# initial check order:
# 1. backup file bk.data ->
# 2. kindle(My Clippings.txt) ->
# 3. local file(config) ->
if os.path.exists(BACKUPFN) and os.path.getsize(BACKUPFN) != 0:
self.books = self.km.json2dict(BACKUPFN)
elif self.km.get_kindle_path():
flg = 0
if os.path.exists(BACKUPNOTEFN) and os.path.exists(BACKUPWORDFN):
self.books_data = self.km.json2dict(BACKUPNOTEFN)
self.words_data = self.km.json2dict(BACKUPWORDFN)
if (len(self.books_data)*len(self.words_data[0]))>=1:
self.books_data = self.km.json2dict(BACKUPNOTEFN)
self.words_data = self.km.json2dict(BACKUPWORDFN)
flg = 1
if self.km.get_kindle_path() and (not flg):
self.import_kindle()
else:
self.books = self.km.import_clips()
[self.filter_books, self.filter_data] = self.km.filter_clips(self.books)
self.refresh_ui_component()
self.books_data = self.km.import_clips()
self.words_data = self.km.import_words()
[self.filter_books, self.filter_list] = self.km.filter_clips(self.books_data)
#self.filter_list = self.km.filter_words(self.words_data)
self.fill_treeview()
self.refresh_ui_component(comp=1)
# timer to check status of kindle
self.timer = QTimer(self)
@@ -86,9 +115,11 @@ class kmanWindow(QMainWindow):
ui.tableView.setColumnWidth(2, 50) # author
ui.tableView.selectRow(0)
# creat tablemodel
data = self.convert_to_panda(self.filter_data)
# initial tableView
data = self.convert_to_panda(self.filter_list)
ui.tablemodel = nTableModel(data)
ui.tableView.verticalHeader().hide()
ui.tableView.setModel(self.ui.tablemodel)
def add_ui_component(self):
self.ui.searchComboBox.addItems([u'ALL',u'BOOKNAME',u'CONTENT',u'AUTHOR'])
@@ -101,41 +132,70 @@ class kmanWindow(QMainWindow):
def refresh_ui_component(self, comp=0):
""" refresh treeView, tableview, textedit information
after import or open clips file
Args: comp 0 - treeview + tablevew + textedit
1 - tablevew + textedit
2 - textedit
Args: comp 0 - treeview + tablevew + textedit , initial, fill_treeview()
move to __init__()
1 - tablevew + textedit , note tree view clicked
2 - textedit , note table view clicked
3 - tablevew + textedit , word tree view clicked
4 - textedit , word table view clicked
"""
if not comp in [1,2]:
self.fill_treeview()
# refresh tableview click note tree
if comp in [1,2]:
data = self.convert_to_panda(self.filter_list,0)
# refresh tableview click word tree
elif comp in [3,4]:
data = self.convert_to_panda(self.filter_list,1)
# refresh tableview
if comp != 2:
data = self.convert_to_panda(self.filter_data)
if hasattr(self.ui, 'tablemodel'):
del self.ui.tablemodel
self.ui.tablemodel = nTableModel(data)
self.ui.tableView.verticalHeader().hide()
self.ui.tableView.setModel(self.ui.tablemodel)
#self.ui.tablemodel.tabledata_update.connect(self.tabledata_update_slot)
# refresh tableview content
if hasattr(self.ui, 'tablemodel'):
del self.ui.tablemodel
self.ui.tablemodel = nTableModel(data)
self.ui.tableView.verticalHeader().hide()
self.ui.tableView.setModel(self.ui.tablemodel)
#self.ui.tablemodel.tabledata_update.connect(self.tabledata_update_slot)
# refresh textedit content
if len(self.filter_data)>0:
[stype,sbookname,sauthor,sposition,stime,scontent] = self.filter_data[0]
self.ui.textEdit.setHtml("""<span style='font-size:22pt;color:maroon'>《{bookname}》</span>
<span style='font-size:22pt;color:maroon'> {author} </span>
<span style='font-size:22pt;color:maroon'> ({time}) </span>
<span style='font-size:11pt;color:maroon'> 【{note}】 </span><br><br>
<span><HR style="FILTER: progid:DXImageTransform.Microsoft.Shadow(color:#987cb9,direction:145,strength:15)" width="95%" color=#987cb9 SIZE=1></span>
<span style='font-size:22pt;color:#31849B'>{content}</span>
<span style='font-size:11pt;color:maroon'>【P{position}】</span><br>""".
format(bookname=sbookname, author=sauthor, time=stime,
note=stype, content=scontent, position=sposition))
if comp in [1,2]:
if len(self.filter_list)>0:
[stype,sbookname,sauthor,sposition,stime,scontent] = self.filter_list[0]
self.ui.textEdit.setHtml(notes_temp.format(
bookname=sbookname, author=sauthor, time=stime,
note=stype, content=scontent, position=sposition))
elif comp in [3,4]:
self.render_textedit_words(self.words_data)
self.show_status_info()
def convert_to_panda(self, seclist):
pdframe = pd.DataFrame(seclist, \
columns = ['Type','Bookname','Author','Position','Date','Content'])
def render_textedit_words(self, wdata, mrow=100):
[bookinfo, words, lookups] = wdata
index = self.ui.tableView.currentIndex()
if index.row() == -1:
word = self.filter_list[0][2]
else:
word = index.sibling(index.row(), 2).data()
txt = ""
for row in lookups:
if words[row[1]]['word'] == word:
[susage, stimestamp, sbookname, sauthor, scategory, sposition] = \
[row[4],row[5],bookinfo[row[2]]['bookname'], \
bookinfo[row[2]]['author'], words[row[1]]['category'],row[3]]
txt += words_temp.format(
usage=susage,bookname=sbookname,
author=sauthor,category=scategory,
timestamp=stimestamp,position=sposition)
self.ui.textEdit.setHtml(txt)
def convert_to_panda(self, mlist, tp=0):
if tp==0:
pdframe = pd.DataFrame(mlist, \
columns = ['Type','Bookname','Author','Position','Date','Content'])
else:
pdframe = pd.DataFrame(mlist, \
columns = ['Bookname','Author','Word','Category'])
return pdframe
def tabledata_update_slot(self, s):
@@ -147,24 +207,50 @@ class kmanWindow(QMainWindow):
itemmodel = model_index.model() #QAbstractItemModel/QStandardItemModel
item = itemmodel.itemFromIndex(modelidx) #QStandardItem
description = item.accessibleDescription()
print(description, item.text())
self.tree_selected = item.accessibleDescription()
print(self.tree_selected, item.text())
# filter clips
self.filter_data = None
if description in ['root', 'bookname', 'author']:
[self.filter_books, self.filter_data] = self.km.filter_clips(self.books)
elif description == 'bleaf': # bookname leaf
info = re.split(r'\s+',item.text())[0]
[self.filter_books, self.filter_data] = self.km.filter_clips(self.books, info, 1)
else: # author leaf
info = re.split(r'\s+',item.text())[0]
[self.filter_books, self.filter_data] = self.km.filter_clips(self.books, info, 2)
self.filter_list = None
info = re.split(r'\s+',item.text())[0]
comp = 0
if self.tree_selected in ['note_root', 'note_bookname', 'note_author']:
[self.filter_books, self.filter_list] = self.km.filter_clips(self.books_data)
comp = 1
elif self.tree_selected in ['word_root', 'word_bookname']:
self.filter_list = self.km.filter_words(self.words_data)
comp = 3
elif self.tree_selected == 'note_bleaf': # bookname leaf
comp = 1
[self.filter_books, self.filter_list] = self.km.filter_clips(self.books_data, info, 1)
elif self.tree_selected == 'note_aleaf': # author leaf
comp = 1
[self.filter_books, self.filter_list] = self.km.filter_clips(self.books_data, info, 2)
elif self.tree_selected == 'word_leaf': # word bookname leaf
comp = 3
self.filter_list = self.km.filter_words(self.words_data, info)
else: return
self.refresh_ui_component(comp=1)
if comp == 3:
self.ui.tableView.horizontalHeader().setStretchLastSection(True)
self.ui.tableView.setColumnWidth(0, 250) # author
self.ui.tableView.setColumnWidth(1, 50) # author
self.ui.tableView.setColumnWidth(3, 50) # category
if comp == 1:
self.ui.tableView.setColumnWidth(0, 40) # type
self.ui.tableView.setColumnWidth(2, 50) # author
self.refresh_ui_component(comp)
def table_item_clicked(self, index):
if index.isValid():
"""
print('tableView.currentIndex().row() {} tableView.currentIndex().column() {}'
.format(self.ui.tableView.currentIndex().row(),
self.ui.tableView.currentIndex().column()))
"""
if not index.isValid(): return
if self.tree_selected.split('_')[0]=='note':
row = index.row()
stype = index.sibling(row, 0).data()
sbookname = index.sibling(row, 1).data()
@@ -172,18 +258,12 @@ class kmanWindow(QMainWindow):
sposition = index.sibling(row, 3).data()
stime = index.sibling(row, 4).data()
scontent = index.sibling(row, 5).data()
else:
return
self.ui.textEdit.setHtml("""<span style='font-size:22pt;color:maroon'>《{bookname}》</span>
<span style='font-size:22pt;color:maroon'> {author} </span>
<span style='font-size:22pt;color:maroon'> ({time}) </span>
<span style='font-size:11pt;color:maroon'> 【{note}】 </span><br><br>
<span>********************************************************</span><br><br>
<span style='font-size:22pt;color:#31849B'>{content}</span>
<span style='font-size:11pt;color:maroon'>【P{position}】</span><br>""".
format(bookname=sbookname, author=sauthor, time=stime,
note=stype, content=scontent, position=sposition))
self.ui.textEdit.setHtml(notes_temp.format(
bookname=sbookname, author=sauthor, time=stime,
note=stype, content=scontent, position=sposition))
else:
self.render_textedit_words(self.words_data)
def search_button_clicked(self):
search_word = self.ui.searchLineEdit.text()
@@ -192,8 +272,8 @@ class kmanWindow(QMainWindow):
return 0
content_type = self.ui.searchComboBox.currentText()
#content_idx = self.ui.searchComboBox.currentIndex()
[nu, sbks] = self.km.search_clip(self.books, search_word, 'ALL', content_type)
[self.filter_books, self.filter_data] = self.km.filter_clips(sbks)
[nu, sbks] = self.km.search_clip(self.books_data, search_word, 'ALL', content_type)
[self.filter_books, self.filter_list] = self.km.filter_clips(sbks)
self.refresh_ui_component()
print( 'call search_button_clicked()' )
@@ -215,8 +295,8 @@ class kmanWindow(QMainWindow):
def search_scope_change(self,t):
p = {0:'ALL',1:'TITLE',2:'AUTHOR',3:'CONTENT'}
s = self.ui.searchLineEdit.text()
#print(self.books)
#print(search_clip(self.books,s,'ALL',p[t]))
#print(self.books_data)
#print(search_clip(self.books_data,s,'ALL',p[t]))
print('call search_scope_change()')
## XXX
@@ -250,8 +330,11 @@ class kmanWindow(QMainWindow):
self.messagebox(ico=2, info='\n\n kindle is not connected')
return 0
self.books = self.km.import_clips(fp+'documents/'+KINDLEFN)
[self.filter_books, self.filter_data] = self.km.filter_clips(self.books)
self.books_data = self.km.import_clips(fp+'documents/'+CLIPFN)
self.words_data = self.km.import_words(fp+'system/vocabulary/'+WORDFN)
[self.filter_books, self.filter_list] = self.km.filter_clips(self.books_data)
self.filter_wordlist = self.km.filter_words(self.words_data)
self.refresh_ui_component()
def import_local(self):
@@ -261,8 +344,8 @@ class kmanWindow(QMainWindow):
"All Files (*);;Text Files (*.txt)") # filter file type
self.fn = fn
self.books = self.km.import_clips(fn)
[self.filter_books, self.filter_data] = self.km.filter_clips(self.books)
self.books_data = self.km.import_clips(fn)
[self.filter_books, self.filter_list] = self.km.filter_clips(self.books_data)
self.refresh_ui_component()
#print('filename ', fn, 'filetype ', ft)
@@ -270,22 +353,23 @@ class kmanWindow(QMainWindow):
def fill_treeview(self):
self.ui.model = QStandardItemModel()
rootItem = self.ui.model.invisibleRootItem()
item = QStandardItem('All Notes ({})'.format(self.km.get_totalnum_nt(self.books)))
item = QStandardItem('All Notes ({})'.format(self.km.get_totalnum_nt(self.books_data)))
icon = QIcon()
icon.addFile(u":/icons/emblem_library.png", QSize(), QIcon.Normal, QIcon.Off)
item.setIcon(icon)
item.setAccessibleDescription('root')
item.setAccessibleDescription('note_root')
rootItem.appendRow(item)
parent_item = item
# add bookname tree
[numbooks, booknum] = self.km.get_bookname_num(self.books)
[numbooks, booknum] = self.km.get_bookname_num(self.books_data)
bookname_item = QStandardItem('Bookname ({})'.format(numbooks))
icon = QIcon()
icon.addFile(u":/icons/book_open.png", QSize(), QIcon.Normal, QIcon.Off)
bookname_item.setIcon(icon)
bookname_item.setAccessibleDescription('bookname')
bookname_item.setAccessibleDescription('note_bookname')
parent_item.appendRow(bookname_item)
if numbooks > 0:
@@ -294,16 +378,16 @@ class kmanWindow(QMainWindow):
icon = QIcon()
icon.addFile(u":/icons/book_open_bookmark.png", QSize(), QIcon.Normal, QIcon.Off)
item.setIcon(icon)
item.setAccessibleDescription('bleaf')
item.setAccessibleDescription('note_bleaf')
bookname_item.appendRow(item)
# add author tree
[numauthor, authnum] = self.km.get_author_num(self.books)
[numauthor, authnum] = self.km.get_author_num(self.books_data)
author_item = QStandardItem('Author ({})'.format(numauthor))
icon = QIcon()
icon.addFile(u":/icons/person.png", QSize(), QIcon.Normal, QIcon.Off)
author_item.setIcon(icon)
author_item.setAccessibleDescription('author')
author_item.setAccessibleDescription('note_author')
parent_item.appendRow(author_item)
parent_item = author_item
@@ -313,9 +397,38 @@ class kmanWindow(QMainWindow):
icon = QIcon()
icon.addFile(u":/icons/user.png", QSize(), QIcon.Normal, QIcon.Off)
item.setIcon(icon)
item.setAccessibleDescription('aleaf')
item.setAccessibleDescription('note_aleaf')
author_item.appendRow(item)
# add words root
word_rootItem = self.ui.model.invisibleRootItem()
[numwords, wordnum] = self.km.get_book_word_num(self.words_data)
item = QStandardItem('All Words({})'.format(numwords))
icon = QIcon()
icon.addFile(u":/icons/emblem_library.png", QSize(), QIcon.Normal, QIcon.Off)
item.setIcon(icon)
item.setAccessibleDescription('word_root')
word_rootItem.appendRow(item)
word_parent_item = item
# add word bookname tree
word_bookname_item = QStandardItem('Bookname ({})'.format(numbooks))
icon = QIcon()
icon.addFile(u":/icons/book_open.png", QSize(), QIcon.Normal, QIcon.Off)
word_bookname_item.setIcon(icon)
word_bookname_item.setAccessibleDescription('word_bookname')
word_parent_item.appendRow(word_bookname_item)
print( [numwords, wordnum] )
if numwords > 0:
for k, v in wordnum.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('word_leaf')
word_bookname_item.appendRow(item)
self.ui.treeView.setModel(self.ui.model)
self.ui.treeView.expandAll()
@@ -382,8 +495,10 @@ class kmanWindow(QMainWindow):
# backup file when kman closed
# read backup file when kman start
def closeEvent(self, e):
with open(BACKUPFN, 'w', encoding='utf8', errors='ignore') as fw:
fw.write(self.km.dict2json(self.books))
with open(BACKUPNOTEFN, 'w', encoding='utf8', errors='ignore') as fw:
fw.write(self.km.dict2json(self.books_data))
with open(BACKUPWORDFN, 'w', encoding='utf8', errors='ignore') as fw:
fw.write(self.km.dict2json(self.words_data))
# stop check thread
self.flag = False