#########################################################
## @file : kmanapp.py
## @desc : kindle note managerment tool GUI
## @create : 2020/06/03
## @author : Chengan
## @email : douboer@gmail.com
#########################################################
import sys
import os
import operator
from time import sleep
#import pandas as pd
from mtable import mTable
import threading
#if hasattr(sys, 'frozen'):
# os.environ['PATH'] = sys._MEIPASS + ";" + os.environ['PATH']
from PySide2.QtWidgets import (QMainWindow, QApplication, QMessageBox,
QFileDialog, QLabel, QAbstractItemView, QHeaderView)
from PySide2.QtCore import (QAbstractTableModel, Signal, QSize, QTimer, Qt)
from PySide2.QtGui import (QPalette, QStandardItemModel, QStandardItem, QIcon)
from mainwindow import Ui_MainWindow
from kman import *
from parseweb import *
# import binary resource file(kmanapp_rc.py)
import kmanapp_rc
notes_temp = """
《{bookname}》
{author}
({time})
【{note}】
{content}
【P{position}】
"""
infos_temp = """
| |
{bookname}
作者 : {author}
评论数 : {ratenum}
评分 : {score}
出版社 : {publisher}
出版时间 : {publishing}
内容简介 : {description}
|
|
|
|
"""
words_temp = """
{usage}
{bookname}
{author}
{category}
{timestamp}
{position}
"""
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)
# create ui and initial it
ui = Ui_MainWindow()
ui.setupUi(self)
self.ui = ui
self.add_ui_component()
# initial tree selected
self.tree_selected = 'note_root'
self.km = kMan()
self.spide = bookInfoSpide()
### in order to smaller the package,
### substitute pandas table with mTable
self.mt = mTable()
# initial check order:
# 1. backup file bk.data ->
# 2. kindle(My Clippings.txt) ->
# 3. local file(config) ->
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 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:
if self.km.get_kindle_path():
self.import_kindle()
else:
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)
# initial books information which grab from douban or amazon
# 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
self.books_info = defaultdict(dict)
try:
if os.path.exists(BACKUPINFOFN):
self.books_info = self.km.json2dict(BACKUPINFOFN)
increase_book_list = self.check_increase_books(self.books_data, self.books_info)
if len(increase_book_list) > 0:
trd = threading.Thread(target=self.grab_books_info, args=(increase_book_list,))
trd.setDaemon(True)
trd.start()
else:
booklist = list(self.books_data.keys())
trd = threading.Thread(target=self.grab_books_info, args=(book_list,))
trd.setDaemon(True)
trd.start()
except Exception as e:
print(e)
finally:
pass
self.fill_treeview()
self.refresh_ui_component(comp=1)
# 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())
ui.actionimportlocal.triggered.connect(lambda: self.import_local())
ui.actionconfig.triggered.connect(lambda: self.config())
ui.actionwords.triggered.connect(lambda: self.words())
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.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.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
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)
# initial tableView
data = self.convert_to_panda(self.filter_list)
ui.tablemodel = nTableModel(data)
ui.tableView.verticalHeader().hide()
ui.tableView.setModel(self.ui.tablemodel)
ui.tableView.setSortingEnabled(True)
self.ui.textEdit.installEventFilter(self)
# XXXX
def eventFilter(self, source, event):
if source==self.ui.textEdit:
"""
if (event.type() == QEvent.Type.InputMethodQuery):
self.anchor = self.anchorAt(e.pos())
if self.anchor:
QApplication.setOverrideCursor(Qt.PointingHandCursor)
elif (event.type() == QEvent.Type.InputMethodQuery):
if self.anchor:
QDesktopServices.openUrl(QUrl(self.anchor))
QApplication.setOverrideCursor(Qt.ArrowCursor)
self.anchor = None
"""
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]
last_list = list(bksinfo.keys()) # grab book information last time
increase_list = []
for nn in new_list:
flag = 0
for gg in last_list:
if nn in gg: flag = 1
if flag == 0:
increase_list.append(nn)
return increase_list
def add_ui_component(self):
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()
def refresh_ui_component(self, comp=0):
""" refresh treeView, tableview, textedit information
after import or open clips file
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
5 - textedit , info tree view clicked
"""
# 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 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 comp in [1,2]:
if len(self.filter_list)>0:
[stype,sbookname,sauthor,sposition,stime,scontent] = self.filter_list[0]
tt = notes_temp.format( bookname=sbookname, author=sauthor, time=stime,
note=stype, content=scontent, position=sposition)
print(re.split(r'[\((\-\::_\s]',sbookname.strip())[0])
self.ui.textEdit.setHtml(tt)
elif comp in [3,4]:
self.render_textedit_words(self.words_data)
elif comp == 5:
self.render_textedit_infos(self.books_info)
self.show_status_info()
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][0]
else:
word = index.sibling(index.row(), 0).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)
'''
{
"金融的本质": {
"link": "https://book.douban.com/subject/25843334",
"bookname": "金融的本质",
"img": "https://img9.doubanio.com/view/subject/s/public/s27246465.jpg",
"score": "8.2",
"ratenum": "893",
"publisher": "中信出版社",
"publishing": "2014",
"description": "xxx",
"author": "【美】伯南克/巴曙松"
}
'''
def render_textedit_infos(self, idata, selectitem):
""" render textedit for book information
Args:
idata - books_info
selectitem - text of treeitem selected
"""
if selectitem in list(idata.keys()):
vv = idata[selectitem]
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'],
img=vv['img'].split('/')[-1]))
else: pass
def convert_to_panda(self, mlist, tp=0):
if tp==0:
#### 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, \
# columns = ['Word','Bookname','Author','Category'])
self.mt.dataframe(mlist, \
columns = ['Word','Bookname','Author','Category'])
return self.mt
def tabledata_update_slot(self, s):
print('call tabledata_update_slot() {}'.format(s))
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
self.tree_selected = item.accessibleDescription()
print(self.tree_selected, item.text())
# filter clips
self.filter_list = None
info = re.split(r'\s+',item.text())[0]
comp = 0
if self.tree_selected.split('_')[0] == 'info':
self.ui.tableView.setVisible(False)
self.render_textedit_infos(self.books_info, item.text())
comp = 5
else:
self.ui.tableView.setVisible(True)
# refresh filter clips(tableview) after tree item clicked
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 == '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 in ['word_root', 'word_bookname']:
self.filter_list = self.km.filter_words(self.words_data)
comp = 3
elif self.tree_selected == 'word_leaf': # word bookname leaf
comp = 3
self.filter_list = self.km.filter_words(self.words_data, info)
else: return
if comp == 3:
self.ui.tableView.setColumnWidth(1, 50) # author
self.ui.tableView.setColumnWidth(3, 50) # category
# QHeaderView::Interactive 0
# QHeaderView::Stretch 1
# QHeaderView::Fixed 2
# QHeaderView::ResizeToContents 3
self.ui.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
if comp == 1:
self.ui.tableView.setColumnWidth(0, 40) # type
self.ui.tableView.setColumnWidth(2, 50) # author
self.ui.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
self.refresh_ui_component(comp)
def table_item_clicked(self, index):
"""
print('tableView.currentIndex().row() {} tableView.currentIndex().column() {}'
.format(self.ui.tableView.currentIndex().row(),
self.ui.tableView.currentIndex().column()))
"""
if not index.isValid(): return
ss = self.tree_selected.split('_')[0]
if ss=='note':
row = index.row()
stype = index.sibling(row, 0).data()
sbookname = index.sibling(row, 1).data()
sauthor = index.sibling(row, 2).data()
sposition = index.sibling(row, 3).data()
stime = index.sibling(row, 4).data()
scontent = index.sibling(row, 5).data()
self.ui.textEdit.setHtml(notes_temp.format(
bookname=sbookname, author=sauthor, time=stime,
note=stype, content=scontent, position=sposition))
elif ss=='note':
self.render_textedit_words(self.words_data)
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_data, search_word, 'ALL', content_type)
[self.filter_books, self.filter_list] = self.km.filter_clips(sbks)
self.refresh_ui_component(1)
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()
#print(self.books_data)
#print(search_clip(self.books_data,s,'ALL',p[t]))
print('call search_scope_change()')
## XXX
'''
def check_kindle_status(self):
while self.flag:
self.show_status_info()
sleep(2)
'''
def show_status_info(self):
""" show status information on statusbar
Args:
conn: 1 if kindle is connected else 0
Return:
conn
"""
status = self.km.status_info()
self.ui.statusbar.showMessage(status[0],0)
self.ui.status_label.setText(status[1])
if not self.km.status:
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):
fp = self.km.get_kindle_path()
if not fp:
self.messagebox(ico=2, info='\n\n kindle is not connected')
return 0
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)
self.fill_treeview()
self.refresh_ui_component(1)
def import_local(self):
fn, ft = QFileDialog.getOpenFileName(self,
"choose file to import",
'./', # start path
"All Files (*);;Text Files (*.txt)") # filter file type
self.fn = fn
self.books_data = self.km.import_clips(fn)
[self.filter_books, self.filter_list] = self.km.filter_clips(self.books_data)
self.fill_treeview()
self.refresh_ui_component(1)
#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 ({})'.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('note_root')
rootItem.appendRow(item)
parent_item = item
# add bookname tree
[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('note_bookname')
parent_item.appendRow(bookname_item)
if numbooks > 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('note_bleaf')
bookname_item.appendRow(item)
# add author tree
[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('note_author')
parent_item.appendRow(author_item)
parent_item = author_item
if numauthor > 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('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)
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)
# add infos root
self.ui.tableView.setVisible(True)
info_rootItem = self.ui.model.invisibleRootItem()
item = QStandardItem('All Books({})'.format(len(self.books_info.keys())))
icon = QIcon()
icon.addFile(u":/icons/amazon.png", QSize(), QIcon.Normal, QIcon.Off)
item.setIcon(icon)
item.setAccessibleDescription('info_root')
info_rootItem.appendRow(item)
info_parent_item = item
# add book info tree
info_bookname_item = QStandardItem('Douban ({})'.format(numbooks))
icon = QIcon()
icon.addFile(u":/icons/book_open.png", QSize(), QIcon.Normal, QIcon.Off)
info_bookname_item.setIcon(icon)
info_bookname_item.setAccessibleDescription('info_bookname')
info_parent_item.appendRow(info_bookname_item)
for k in self.books_info.keys():
item = QStandardItem('{}'.format(k))
icon = QIcon()
icon.addFile(u":/icons/list.png", QSize(), QIcon.Normal, QIcon.Off)
item.setIcon(icon)
item.setAccessibleDescription('info_leaf')
info_bookname_item.appendRow(item)
self.ui.treeView.setModel(self.ui.model)
self.ui.treeView.expandAll()
def config(self):
print("call slot config()")
pass
def words(self):
print("call slot words()")
pass
def statistic(self):
print("call slot statistic()")
pass
def homepage(self):
import webbrowser
webbrowser.open('https://gitee.com/douboer/kman')
print("call slot homepage()")
pass
def about(self):
self.messagebox(ico=1, info='\n'+ \
' kindle management tool \n\n' + \
' v1.0.4\n\n' + \
' Author: chengan\n\n' + \
' douboer@gmail.com')
print("call slot about()")
pass
def refresh(self):
self.import_kindle()
print("call slot refresh()")
pass
def export(self):
if self.tree_selected.split('_')[0]=='note':
self.export_filter_notes()
else:
self.export_filter_words()
print("call export()")
def export_filter_notes(self):
self.km.export_notes(self.filter_books, 'export', ft='MD')
pass
def export_filter_words(self):
self.km.export_words(self.words_data, self.filter_list, 'export', ft='MD')
pass
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(info)
msgBox.setInformativeText("")
msgBox.setIcon(icons[ico])
msgBox.setStandardButtons(QMessageBox.Cancel | QMessageBox.Ok)
msgBox.setBaseSize(QSize(600, 300))
r = msgBox.exec()
# 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:
fw.write(self.km.dict2json(self.words_data))
with open(BACKUPINFOFN, 'w', encoding='utf8', errors='ignore') as fw:
fw.write(self.km.dict2json(self.books_info))
# stop check thread
self.flag = False
def grab_books_info(self, booklist):
bks_info = {}
for bkname in booklist:
bkname = re.split(r'[\((\-\::_\s]',bkname.strip())[0]
print(bkname)
bkinfo = self.spide.grab_book_info(bkname)
filter_bkinfo = self.spide.filter_spide_book(bkinfo)
if filter_bkinfo:
bks_info.update(filter_bkinfo)
self.spide.down_book_img(filter_bkinfo)
if bks_info: return self.books_info.update(bks_info)
# thanks Martin Fitzpatrick ^_^
# https://www.learnpyqt.com/courses/model-views/qtableview-modelviews-numpy-pandas/
class nTableModel(QAbstractTableModel):
tabledata_update = Signal(str)
def __init__(self, data):
super(nTableModel, self).__init__()
self._data = data
def data(self, index, role):
if role == Qt.DisplayRole:
#### 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):
#### XXX remove pandas
#return self._data.shape[1]
return self._data.get_num_rows()
def columnCount(self, index):
#### 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:
#### XXX remove pandas
#return str(self._data.columns[section])
return str(self._data.get_columns()[section])
if orientation == Qt.Vertical:
#### 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__":
print('sys.path[0]', sys.path[0])
print('sys.argv[0]', sys.argv[0])
print('os.path.realpath(sys.executable)', os.path.realpath(sys.executable))
print('os.path.realpath(sys.argv[0]))', os.path.realpath(sys.argv[0]))
print('os.path.dirname(os.path.realpath(sys.executable))',
os.path.dirname(os.path.realpath(sys.executable)))
print('os.path.dirname(os.path.realpath(sys.argv[0]))',
os.path.dirname(os.path.realpath(sys.argv[0])))
util = Util()
print('get_app_path',util.get_app_path())
app = QApplication(sys.argv)
kmw = kmanWindow()
icon = QIcon()
icon.addFile(u":/icons/Cbb20.png", QSize(), QIcon.Normal, QIcon.Off)
kmw.setWindowIcon(icon)
kmw.setWindowTitle("kindle management")
kmw.resize(1200, 800)
#kmw.showFullScreen()
kmw.show()
"""
# move to __init__()
try:
booklist = self.books_data.keys()
trd = threading.Thread(target=kmw.grab_books_info, args=(booklist,))
trd.setDaemon(True)
trd.start()
except Exception as e:
print(e)
pass
finally:
pass
"""
# 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_()