kindle manager

This commit is contained in:
gavin
2020-06-11 17:21:16 +08:00
parent c903004b8f
commit 43c602d8d6
38 changed files with 565 additions and 248 deletions

View File

@@ -8,6 +8,7 @@
#########################################################
import sys
import os
from time import sleep
import pandas as pd
@@ -42,11 +43,20 @@ class kmanWindow(QMainWindow):
ui.setupUi(self)
self.ui = ui
self.km = kMan()
self.books = self.km.import_clips()
self.filter_data = self.km.filter_clips(self.books)
self.add_ui_component()
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():
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()
# timer to check status of kindle
@@ -55,7 +65,7 @@ class kmanWindow(QMainWindow):
self.timer.start(1000)
# connect action/toolbutton to slot functions
ui.actionimportkindle.triggered.connect(lambda: self.import_kindle(self.books))
ui.actionimportkindle.triggered.connect(lambda: self.import_kindle())
ui.actionimportlocal.triggered.connect(lambda: self.import_local())
ui.actionconfig.triggered.connect(lambda: self.config())
ui.actionwords.triggered.connect(lambda: self.words())
@@ -63,56 +73,65 @@ class kmanWindow(QMainWindow):
ui.actionhomepage.triggered.connect(lambda: self.homepage())
ui.actionabout.triggered.connect(lambda: self.about())
ui.actionflush.triggered.connect(lambda: self.refresh())
ui.actionexport.triggered.connect(lambda: self.export())
#ui.searchLineEdit.returnPressed.connect(self.search_return_press())
ui.searchComboBox.currentIndexChanged.connect(self.search_scope_change)
ui.searchToolButton.clicked.connect(self.search_button_clicked)
ui.treeView.clicked.connect(self.tree_item_clicked)
ui.tableView.clicked.connect(self.table_item_clicked)
ui.tableView.horizontalHeader().setStretchLastSection(True)
ui.tableView.verticalHeader().hide()
ui.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
ui.tableView.setColumnWidth(0, 40) # type
ui.tableView.setColumnWidth(2, 50) # author
ui.tableView.selectRow(0)
# creat tablemodel
data = self.convert_to_panda(self.filter_data)
ui.tablemodel = nTableModel(data)
def add_ui_component(self):
self.ui.searchComboBox.addItems(['ALL','bookname','content','author'])
self.ui.searchComboBox.addItems([u'ALL',u'BOOKNAME',u'CONTENT',u'AUTHOR'])
self.ui.treeView.resize(200,200)
# status bar
self.ui.status_label = QLabel()
self.ui.pe = QPalette()
# table view
self.ui.tablemodel = nTableModel(self.convert_to_panda(self.filter_data))
self.ui.tableView.verticalHeader().hide()
self.ui.tableView.setModel(self.ui.tablemodel)
self.ui.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
# fit window
#headerView = self.ui.tableView.horizontalHeader()
#headerView.setSectionResizeMode(QHeaderView.Stretch)
self.ui.tableView.horizontalHeader().setStretchLastSection(True)
self.ui.tablemodel.tabledata_update.connect(self.tabledata_update_slot)
def refresh_ui_component(self):
self.fill_treeview()
self.show_status_info()
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
"""
if not comp in [1,2]:
self.fill_treeview()
# refresh tableview
data = self.convert_to_panda(self.filter_data)
del self.ui.tablemodel
self.ui.tablemodel = nTableModel(data)
self.ui.tableView.verticalHeader().hide()
self.ui.tableView.setModel(self.ui.tablemodel)
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 textedit content
[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 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))
self.show_status_info()
def convert_to_panda(self, seclist):
pdframe = pd.DataFrame(seclist, \
@@ -134,23 +153,15 @@ class kmanWindow(QMainWindow):
# filter clips
self.filter_data = None
if description in ['root', 'bookname', 'author']:
self.filter_data = self.km.filter_clips(self.books)
[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_data = self.km.filter_clips(self.books, info, 1)
[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_data = self.km.filter_clips(self.books, info, 2)
[self.filter_books, self.filter_data] = self.km.filter_clips(self.books, info, 2)
'''
data = self.convert_to_panda(self.filter_data)
del self.ui.tablemodel
self.ui.tablemodel = nTableModel(data)
self.ui.tableView.verticalHeader().hide()
self.ui.tableView.setModel(self.ui.tablemodel)
'''
self.refresh_ui_component()
self.refresh_ui_component(comp=1)
def table_item_clicked(self, index):
if index.isValid():
@@ -175,8 +186,32 @@ class kmanWindow(QMainWindow):
note=stype, content=scontent, position=sposition))
def search_button_clicked(self):
search_word = self.ui.searchLineEdit.text()
if search_word.strip() == '':
self.messagebox(ico=2, info=u'\n\n search content is empty!')
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)
self.refresh_ui_component()
print( 'call search_button_clicked()' )
def keyPressEvent(self, event):
#print('hasfocus {} key {} {} {}'.format(self.ui.searchLineEdit.hasFocus(),\
# event.key(), Qt.Key_Return, event.key()==Qt.Key_Return))
if (self.ui.searchLineEdit.hasFocus() and event.key() == Qt.Key_Return):
print('call keyPressEvent() {} '.format(event.key()))
self.search_button_clicked()
def search_return_press(self):
self.search_button_clicked()
print('call search_return_press()')
# XXX
def search_scope_change(self,t):
p = {0:'ALL',1:'TITLE',2:'AUTHOR',3:'CONTENT'}
s = self.ui.searchLineEdit.text()
@@ -209,20 +244,16 @@ class kmanWindow(QMainWindow):
self.ui.statusbar.addPermanentWidget(self.ui.status_label, stretch=0)
# define slot functions
def import_kindle(self,bks):
def import_kindle(self):
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(fp+'documents/'+CLIPFN)
self.filter_data = self.km.filter_clips(self.books)
status = self.km.status_info()
self.books = self.km.import_clips(fp+'documents/'+KINDLEFN)
[self.filter_books, self.filter_data] = self.km.filter_clips(self.books)
self.refresh_ui_component()
#print(bks)
def import_local(self):
fn, ft = QFileDialog.getOpenFileName(self,
"choose file to import",
@@ -231,8 +262,7 @@ class kmanWindow(QMainWindow):
self.fn = fn
self.books = self.km.import_clips(fn)
self.filter_data = self.km.filter_clips(self.books)
[self.filter_books, self.filter_data] = self.km.filter_clips(self.books)
self.refresh_ui_component()
#print('filename ', fn, 'filetype ', ft)
@@ -241,7 +271,7 @@ class kmanWindow(QMainWindow):
def fill_treeview(self):
self.ui.model = QStandardItemModel()
rootItem = self.ui.model.invisibleRootItem()
item = QStandardItem('All Notes')
item = QStandardItem('All Notes ({})'.format(self.km.get_totalnum_nt(self.books)))
icon = QIcon()
icon.addFile(u":/icons/emblem_library.png", QSize(), QIcon.Normal, QIcon.Off)
item.setIcon(icon)
@@ -250,15 +280,15 @@ class kmanWindow(QMainWindow):
parent_item = item
# add bookname tree
[totalnum, booknum] = self.km.get_bookname_num(self.books)
bookname_item = QStandardItem('Bookname ({})'.format(totalnum))
[numbooks, booknum] = self.km.get_bookname_num(self.books)
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')
parent_item.appendRow(bookname_item)
if totalnum > 0:
if numbooks > 0:
for k, v in booknum.items():
item = QStandardItem('{} ({})'.format(k, v))
icon = QIcon()
@@ -268,8 +298,8 @@ class kmanWindow(QMainWindow):
bookname_item.appendRow(item)
# add author tree
[totalnum, authnum] = self.km.get_author_num(self.books)
author_item = QStandardItem('Author ({})'.format(totalnum))
[numauthor, authnum] = self.km.get_author_num(self.books)
author_item = QStandardItem('Author ({})'.format(numauthor))
icon = QIcon()
icon.addFile(u":/icons/person.png", QSize(), QIcon.Normal, QIcon.Off)
author_item.setIcon(icon)
@@ -277,7 +307,7 @@ class kmanWindow(QMainWindow):
parent_item.appendRow(author_item)
parent_item = author_item
if totalnum > 0:
if numauthor > 0:
for k, v in authnum.items():
item = QStandardItem('{} ({})'.format(k, v))
icon = QIcon()
@@ -302,6 +332,9 @@ class kmanWindow(QMainWindow):
pass
def homepage(self):
import webbrowser
webbrowser.open('https://gitee.com/douboer/kman')
print("call slot homepage()")
pass
@@ -316,10 +349,15 @@ class kmanWindow(QMainWindow):
pass
def refresh(self):
self.import_kindle(self.books)
self.import_kindle()
print("call slot refresh()")
pass
def export(self):
self.km.export_notes(self.filter_books, 'export', ft='MD')
print("call export()")
pass
def messagebox(self, ico=1, info=''):
""" unify messagebox
Args: ico - QMessageBox.NoIcon 0
@@ -341,8 +379,12 @@ class kmanWindow(QMainWindow):
msgBox.setBaseSize(QSize(600, 300))
r = msgBox.exec()
## XXXX
# 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))
# stop check thread
self.flag = False
@@ -376,6 +418,7 @@ class nTableModel(QAbstractTableModel):
if orientation == Qt.Vertical:
return str(self._data.index[section])
if __name__ == "__main__":
app = QApplication(sys.argv)
@@ -384,8 +427,8 @@ if __name__ == "__main__":
icon.addFile(u":/icons/Cbb20.png", QSize(), QIcon.Normal, QIcon.Off)
kmw.setWindowIcon(icon)
kmw.setWindowTitle("kindle management")
#kmw.resize(900, 600)
kmw.showFullScreen()
kmw.resize(900, 600)
#kmw.showFullScreen()
kmw.show()
# loop check kindle is connected or not