kindle manager
This commit is contained in:
232
kmanapp.py
232
kmanapp.py
@@ -9,11 +9,17 @@
|
||||
|
||||
import sys
|
||||
import os
|
||||
import operator
|
||||
from time import sleep
|
||||
import pandas as pd
|
||||
#import pandas as pd
|
||||
from mtable import mTable
|
||||
import threading
|
||||
|
||||
from PySide2.QtWidgets import (QMainWindow, QApplication, QLabel, QAbstractItemView, QHeaderView)
|
||||
#if hasattr(sys, 'frozen'):
|
||||
# os.environ['PATH'] = sys._MEIPASS + ";" + os.environ['PATH']
|
||||
|
||||
from PySide2.QtWidgets import (QMainWindow, QApplication, QMessageBox,
|
||||
QFileDialog, QLabel, QAbstractItemView, QHeaderView, QMenu)
|
||||
from PySide2.QtCore import (QAbstractTableModel, Signal, QSize, QTimer, Qt)
|
||||
from PySide2.QtGui import (QPalette, QStandardItemModel, QStandardItem, QIcon)
|
||||
|
||||
@@ -60,6 +66,7 @@ words_temp = """<br><span style='font-size:18pt;color:#31849B'>{usage}</span><br
|
||||
ONLY_TEST = 1
|
||||
|
||||
class kmanWindow(QMainWindow):
|
||||
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(kmanWindow, self).__init__(*args, **kwargs)
|
||||
@@ -68,6 +75,8 @@ class kmanWindow(QMainWindow):
|
||||
def __init__(self, parent=None):
|
||||
super(kmanWindow, self).__init__(parent)
|
||||
|
||||
self.copyinfo = ''
|
||||
|
||||
# create ui and initial it
|
||||
ui = Ui_MainWindow()
|
||||
ui.setupUi(self)
|
||||
@@ -81,6 +90,13 @@ class kmanWindow(QMainWindow):
|
||||
self.km = kMan()
|
||||
self.spide = bookInfoSpide()
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
### in order to smaller the package,
|
||||
### substitute pandas table with mTable
|
||||
self.mt = mTable()
|
||||
|
||||
>>>>>>> 2d53124ab9aa26c9733646348174311d0967c8c0
|
||||
self.books_info = defaultdict(dict)
|
||||
# initial check order:
|
||||
# 1. backup file bk.data ->
|
||||
@@ -90,9 +106,8 @@ class kmanWindow(QMainWindow):
|
||||
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)
|
||||
if self.books_data and len(self.books_data) >=1 and \
|
||||
self.words_data and len(self.words_data[0])>=1:
|
||||
flg = 1
|
||||
|
||||
if not flg:
|
||||
@@ -114,7 +129,10 @@ class kmanWindow(QMainWindow):
|
||||
# if the information exist in backup file, initial with this file,
|
||||
# and grap new book's information from douban
|
||||
# else grap all book information from douban
|
||||
<<<<<<< HEAD
|
||||
"""
|
||||
=======
|
||||
>>>>>>> 2d53124ab9aa26c9733646348174311d0967c8c0
|
||||
try:
|
||||
if os.path.exists(BACKUPINFOFN):
|
||||
self.books_info = self.km.json2dict(BACKUPINFOFN)
|
||||
@@ -155,7 +173,8 @@ class kmanWindow(QMainWindow):
|
||||
#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.treeView.clicked.connect(self.tree_item_clicked)
|
||||
ui.treeView.selectionModel().selectionChanged.connect(self.tree_item_selectionchanged)
|
||||
ui.tableView.clicked.connect(self.table_item_clicked)
|
||||
ui.tableView.horizontalHeader().setStretchLastSection(True)
|
||||
#ui.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
|
||||
@@ -170,7 +189,11 @@ class kmanWindow(QMainWindow):
|
||||
ui.tablemodel = nTableModel(data)
|
||||
ui.tableView.verticalHeader().hide()
|
||||
ui.tableView.setModel(self.ui.tablemodel)
|
||||
ui.tableView.setSortingEnabled(True)
|
||||
ui.tableView.selectionModel().selectionChanged.connect(self.table_item_selectionchanged)
|
||||
#ui.tableView.contextMenuEvent().selectionChanged.connect(self.table_item_selectionchanged)
|
||||
|
||||
# XXXX
|
||||
self.ui.textEdit.installEventFilter(self)
|
||||
|
||||
# XXXX
|
||||
@@ -190,21 +213,6 @@ class kmanWindow(QMainWindow):
|
||||
else:
|
||||
super(kmanWindow, self).eventFilter(source, event)
|
||||
|
||||
"""
|
||||
app = QApplication(sys.argv)
|
||||
editor = MyWidget()
|
||||
cursor = editor.textCursor()
|
||||
fmt = cursor.charFormat()
|
||||
fmt.setForeground(QColor('blue'))
|
||||
address = 'http://example.com'
|
||||
fmt.setAnchor(True)
|
||||
fmt.setAnchorHref(address)
|
||||
fmt.setToolTip(address)
|
||||
cursor.insertText("Hello world again", fmt)
|
||||
editor.show()
|
||||
app.exec_()
|
||||
"""
|
||||
|
||||
def check_increase_books(self, bks, bksinfo):
|
||||
new_list = list(bks.keys()) # kindle's books with note
|
||||
new_list = [re.split(r'[\((\-\::_\s]',nn.strip())[0] for nn in new_list]
|
||||
@@ -252,6 +260,7 @@ class kmanWindow(QMainWindow):
|
||||
self.ui.tableView.verticalHeader().hide()
|
||||
self.ui.tableView.setModel(self.ui.tablemodel)
|
||||
#self.ui.tablemodel.tabledata_update.connect(self.tabledata_update_slot)
|
||||
self.ui.tableView.selectionModel().selectionChanged.connect(self.table_item_selectionchanged)
|
||||
|
||||
# refresh textedit content
|
||||
if comp in [1,2]:
|
||||
@@ -261,6 +270,11 @@ class kmanWindow(QMainWindow):
|
||||
note=stype, content=scontent, position=sposition)
|
||||
print(re.split(r'[\((\-\::_\s]',sbookname.strip())[0])
|
||||
self.ui.textEdit.setHtml(tt)
|
||||
|
||||
self.copyinfo = \
|
||||
""" {content} \n\n--《{bookname}》{author} ({time}) 【{note} P{position}】""". \
|
||||
format( content=scontent, bookname=sbookname, author=sauthor, time=stime,
|
||||
note=stype, position=sposition )
|
||||
elif comp in [3,4]:
|
||||
self.render_textedit_words(self.words_data)
|
||||
elif comp == 5:
|
||||
@@ -278,6 +292,7 @@ class kmanWindow(QMainWindow):
|
||||
word = index.sibling(index.row(), 0).data()
|
||||
|
||||
txt = ""
|
||||
self.copyinfo = ''
|
||||
for row in lookups:
|
||||
if words[row[1]]['word'] == word:
|
||||
[susage, stimestamp, sbookname, sauthor, scategory, sposition] = \
|
||||
@@ -289,6 +304,12 @@ class kmanWindow(QMainWindow):
|
||||
author=sauthor,category=scategory,
|
||||
timestamp=stimestamp,position=sposition)
|
||||
|
||||
self.copyinfo += \
|
||||
"""{usage} \n\n-- {bookname} {author} {category} {timestamp} {position} \n """ \
|
||||
.format( usage=susage,bookname=sbookname, \
|
||||
author=sauthor,category=scategory, \
|
||||
timestamp=stimestamp,position=sposition)
|
||||
|
||||
self.ui.textEdit.setHtml(txt)
|
||||
|
||||
'''
|
||||
@@ -317,30 +338,58 @@ class kmanWindow(QMainWindow):
|
||||
self.ui.textEdit.setOpenExternalLinks(True)
|
||||
self.ui.textEdit.setHtml(infos_temp.format(link=vv['link'],
|
||||
bookname=vv['bookname'],
|
||||
author=vv['author'], ratenum=vv['ratenum'],
|
||||
score=vv['score'], publisher=vv['publisher'],
|
||||
publishing=vv['publishing'],description=vv['description'],
|
||||
author=vv['author'],
|
||||
ratenum=vv['ratenum'],
|
||||
score=vv['score'],
|
||||
publisher=vv['publisher'],
|
||||
publishing=vv['publishing'],
|
||||
description=vv['description'],
|
||||
img=vv['img'].split('/')[-1]))
|
||||
|
||||
self.copyinfo = """ 1 | :green_book: | [{bookname}]({link}) | """ \
|
||||
"""{author}/{score}/{publisher}/{publishing} {description}""" \
|
||||
.format( bookname=vv['bookname'], \
|
||||
link=vv['link'],
|
||||
author=vv['author'],
|
||||
score=vv['score'],
|
||||
publisher=vv['publisher'],
|
||||
publishing=vv['publishing'],
|
||||
description=vv['description'],)
|
||||
|
||||
else: pass
|
||||
|
||||
|
||||
def convert_to_panda(self, mlist, tp=0):
|
||||
if tp==0:
|
||||
pdframe = pd.DataFrame(mlist, \
|
||||
#### XXX remove pandas
|
||||
#pdframe = pd.DataFrame(mlist, \
|
||||
# columns = ['Type','Bookname','Author','Position','Date','Content'])
|
||||
self.mt.dataframe(mlist, \
|
||||
columns = ['Type','Bookname','Author','Position','Date','Content'])
|
||||
else:
|
||||
pdframe = pd.DataFrame(mlist, \
|
||||
#pdframe = pd.DataFrame(mlist, \
|
||||
# columns = ['Word','Bookname','Author','Category'])
|
||||
self.mt.dataframe(mlist, \
|
||||
columns = ['Word','Bookname','Author','Category'])
|
||||
return pdframe
|
||||
return self.mt
|
||||
|
||||
def tabledata_update_slot(self, s):
|
||||
print('call tabledata_update_slot() {}'.format(s))
|
||||
|
||||
def tree_item_selectionchanged(self, selected, deselected):
|
||||
# selected, deselected are QItemSelection objects
|
||||
model_index_list = selected.indexes() # QModelIndexList
|
||||
if not model_index_list: return 0
|
||||
model_index = model_index_list[0] # QModelIndex
|
||||
self.tree_item_clicked(model_index)
|
||||
|
||||
def tree_item_clicked(self, modelidx):
|
||||
# modelidx is a QModelIndex object
|
||||
|
||||
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
|
||||
item = itemmodel.itemFromIndex(model_index) #QStandardItem
|
||||
|
||||
self.tree_selected = item.accessibleDescription()
|
||||
print(self.tree_selected, item.text())
|
||||
@@ -351,6 +400,7 @@ class kmanWindow(QMainWindow):
|
||||
comp = 0
|
||||
if self.tree_selected.split('_')[0] == 'info':
|
||||
self.ui.tableView.setVisible(False)
|
||||
self.ui.tableView.clearSelection()
|
||||
self.render_textedit_infos(self.books_info, item.text())
|
||||
comp = 5
|
||||
else:
|
||||
@@ -389,6 +439,13 @@ class kmanWindow(QMainWindow):
|
||||
|
||||
self.refresh_ui_component(comp)
|
||||
|
||||
def table_item_selectionchanged(self, selected, deselected):
|
||||
# selected, deselected are QItemSelection objects
|
||||
model_index_list = selected.indexes() # QModelIndexList
|
||||
if not model_index_list: return 0
|
||||
model_index = model_index_list[0] # QModelIndex
|
||||
self.table_item_clicked(model_index)
|
||||
|
||||
def table_item_clicked(self, index):
|
||||
"""
|
||||
print('tableView.currentIndex().row() {} tableView.currentIndex().column() {}'
|
||||
@@ -410,7 +467,11 @@ class kmanWindow(QMainWindow):
|
||||
self.ui.textEdit.setHtml(notes_temp.format(
|
||||
bookname=sbookname, author=sauthor, time=stime,
|
||||
note=stype, content=scontent, position=sposition))
|
||||
elif ss=='note':
|
||||
self.copyinfo = \
|
||||
""" {content} \n\n-- 《{bookname}》{author} ({time}) 【{note} P{position}】""". \
|
||||
format( content=scontent, bookname=sbookname, author=sauthor, time=stime,
|
||||
note=stype, position=sposition )
|
||||
elif ss=='word':
|
||||
self.render_textedit_words(self.words_data)
|
||||
|
||||
def search_button_clicked(self):
|
||||
@@ -434,6 +495,58 @@ class kmanWindow(QMainWindow):
|
||||
print('call keyPressEvent() {} '.format(event.key()))
|
||||
self.search_button_clicked()
|
||||
|
||||
def contextMenuEvent(self, event):
|
||||
|
||||
# do not work!?
|
||||
#if(self.ui.tableView.geometry().contains(event.pos())):
|
||||
# print('contextMenuEvent pos {}'.format(event.globalPos()))
|
||||
tree_index_list = self.ui.treeView.selectedIndexes() # QModelIndexList
|
||||
table_index_list = self.ui.tableView.selectedIndexes()
|
||||
# tableview item selected
|
||||
if table_index_list:
|
||||
model_index = table_index_list[0] # QModelIndex
|
||||
|
||||
menu = QMenu()
|
||||
copy_action = menu.addAction(u"Copy")
|
||||
action = menu.exec_(self.mapToGlobal(event.pos()))
|
||||
if action ==copy_action:
|
||||
self.copy_action(model_index.row(), model_index.column())
|
||||
elif tree_index_list:
|
||||
model_index = tree_index_list[0] # QModelIndex
|
||||
itemmodel = model_index.model() #QAbstractItemModel/QStandardItemModel
|
||||
item = itemmodel.itemFromIndex(model_index) #QStandardItem
|
||||
|
||||
pp = self.tree_selected.split('_')[0]
|
||||
menu = QMenu()
|
||||
[copy_info_action, export_note_action, export_word_action] = \
|
||||
[None, None, None]
|
||||
if pp=='info':
|
||||
copy_info_action = menu.addAction(u"Copy")
|
||||
elif pp=='note':
|
||||
export_note_action = menu.addAction(u"Export Notes")
|
||||
elif pp=='word':
|
||||
export_word_action = menu.addAction(u"Export Notes")
|
||||
else: pass
|
||||
|
||||
action = menu.exec_(self.mapToGlobal(event.pos()))
|
||||
fn = self.tree_selected+item.text().split('(')[0].strip()
|
||||
if action==copy_info_action:
|
||||
action = menu.exec_(self.mapToGlobal(event.pos()))
|
||||
self.copy_action(model_index.row(), model_index.column())
|
||||
elif action==export_note_action: self.export_filter_notes(fn)
|
||||
elif action==export_word_action: self.export_filter_words(fn)
|
||||
else: pass
|
||||
|
||||
else: pass
|
||||
|
||||
print('contextMenuEvent pos {}'.format(event.globalPos()))
|
||||
|
||||
def copy_action(self, row, column):
|
||||
import clipboard
|
||||
clipboard.copy(self.copyinfo)
|
||||
|
||||
print('copy_action row {} column {}'.format(row, column))
|
||||
|
||||
def search_return_press(self):
|
||||
self.search_button_clicked()
|
||||
|
||||
@@ -478,8 +591,8 @@ class kmanWindow(QMainWindow):
|
||||
self.messagebox(ico=2, info='\n\n kindle is not connected')
|
||||
return 0
|
||||
|
||||
self.books_data = self.km.import_clips(fp+'documents/'+CLIPFN)
|
||||
self.words_data = self.km.import_words(fp+'system/vocabulary/'+WORDFN)
|
||||
self.books_data = self.km.import_clips(os.path.join(fp,'documents',CLIPFN))
|
||||
self.words_data = self.km.import_words(os.path.join(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)
|
||||
|
||||
@@ -649,18 +762,22 @@ class kmanWindow(QMainWindow):
|
||||
pass
|
||||
|
||||
def export(self):
|
||||
if self.tree_selected.split('_')[0]=='note':
|
||||
self.export_filter_notes()
|
||||
else:
|
||||
self.export_filter_words()
|
||||
pp = self.tree_selected.split('_')[0]
|
||||
if pp=='note':
|
||||
self.export_filter_notes('export')
|
||||
elif pp=='word':
|
||||
self.export_filter_words('export')
|
||||
else: # info
|
||||
pass
|
||||
|
||||
print("call export()")
|
||||
|
||||
def export_filter_notes(self):
|
||||
self.km.export_notes(self.filter_books, 'export', ft='MD')
|
||||
def export_filter_notes(self, fn):
|
||||
self.km.export_notes(self.filter_books, fn, ft='MD')
|
||||
pass
|
||||
|
||||
def export_filter_words(self):
|
||||
self.km.export_words(self.words_data, self.filter_list, 'export', ft='MD')
|
||||
def export_filter_words(self, fn):
|
||||
self.km.export_words(self.words_data, self.filter_list, fn, ft='MD')
|
||||
pass
|
||||
|
||||
def messagebox(self, ico=1, info=''):
|
||||
@@ -687,6 +804,8 @@ class kmanWindow(QMainWindow):
|
||||
# backup file when kman closed
|
||||
# so we can read backup file when kman start
|
||||
def closeEvent(self, e):
|
||||
if not os.path.exists(BACKUPFOLDER): os.mkdir(BACKUPFOLDER)
|
||||
|
||||
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:
|
||||
@@ -749,24 +868,46 @@ class nTableModel(QAbstractTableModel):
|
||||
|
||||
def data(self, index, role):
|
||||
if role == Qt.DisplayRole:
|
||||
value = self._data.iloc[index.row(), index.column()]
|
||||
#### XXX remove pandas
|
||||
#value = self._data.iloc[index.row(), index.column()]
|
||||
value = self._data.get_iat(index.row(), index.column())
|
||||
self.tabledata_update[str].emit('{} {}'.format(index.row(),index.column()))
|
||||
return str(value)
|
||||
|
||||
def rowCount(self, index):
|
||||
return self._data.shape[0]
|
||||
#### XXX remove pandas
|
||||
#return self._data.shape[1]
|
||||
return self._data.get_num_rows()
|
||||
|
||||
def columnCount(self, index):
|
||||
return self._data.shape[1]
|
||||
#### XXX remove pandas
|
||||
#return self._data.shape[1]
|
||||
return self._data.get_num_columns()
|
||||
|
||||
def headerData(self, section, orientation, role):
|
||||
# section is the index of the column/row.
|
||||
if role == Qt.DisplayRole:
|
||||
if orientation == Qt.Horizontal:
|
||||
return str(self._data.columns[section])
|
||||
#### XXX remove pandas
|
||||
#return str(self._data.columns[section])
|
||||
return str(self._data.get_columns()[section])
|
||||
|
||||
if orientation == Qt.Vertical:
|
||||
return str(self._data.index[section])
|
||||
#### XXX remove pandas
|
||||
#return str(self._data.index[section])
|
||||
return str(self._data.get_index()[section])
|
||||
|
||||
# cheer!!!
|
||||
def sort(self, column, order):
|
||||
"""Sort table by given column number.
|
||||
"""
|
||||
self.layoutAboutToBeChanged.emit()
|
||||
|
||||
self._data.set_data(sorted(self._data.get_data(), key=operator.itemgetter(column)))
|
||||
if order == Qt.DescendingOrder:
|
||||
self._data.reverse()
|
||||
|
||||
self.layoutChanged.emit()
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -795,7 +936,7 @@ if __name__ == "__main__":
|
||||
"""
|
||||
|
||||
# loop check kindle is connected or not
|
||||
# BUG to be implement XXXX
|
||||
# BUG, to be implement XXXX
|
||||
"""
|
||||
try:
|
||||
t = threading.Thread(target=kmw.check_kindle_status)
|
||||
@@ -804,4 +945,5 @@ if __name__ == "__main__":
|
||||
print ("Error: can not start thread")
|
||||
"""
|
||||
app.exec_()
|
||||
#sys.exit(app.exec_())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user