Author link first try

This commit is contained in:
Charles Haley 2011-06-24 17:57:25 +01:00
parent 52edcbe991
commit 034e289ef3
10 changed files with 77 additions and 23 deletions

View File

@ -86,6 +86,8 @@ CALIBRE_METADATA_FIELDS = frozenset([
# a dict of user category names, where the value is a list of item names # a dict of user category names, where the value is a list of item names
# from the book that are in that category # from the book that are in that category
'user_categories', 'user_categories',
# a dict of author to an associated hyperlink
'author_link_map',
] ]
) )

View File

@ -34,6 +34,7 @@ NULL_VALUES = {
'authors' : [_('Unknown')], 'authors' : [_('Unknown')],
'title' : _('Unknown'), 'title' : _('Unknown'),
'user_categories' : {}, 'user_categories' : {},
'author_link_map' : {},
'language' : 'und' 'language' : 'und'
} }

View File

@ -538,7 +538,8 @@ class OPF(object): # {{{
user_categories = MetadataField('user_categories', is_dc=False, user_categories = MetadataField('user_categories', is_dc=False,
formatter=json.loads, formatter=json.loads,
renderer=dump_user_categories) renderer=dump_user_categories)
author_link_map = MetadataField('author_link_map', is_dc=False,
formatter=json.loads)
def __init__(self, stream, basedir=os.getcwdu(), unquote_urls=True, def __init__(self, stream, basedir=os.getcwdu(), unquote_urls=True,
populate_spine=True): populate_spine=True):
@ -1039,7 +1040,7 @@ class OPF(object): # {{{
for attr in ('title', 'authors', 'author_sort', 'title_sort', for attr in ('title', 'authors', 'author_sort', 'title_sort',
'publisher', 'series', 'series_index', 'rating', 'publisher', 'series', 'series_index', 'rating',
'isbn', 'tags', 'category', 'comments', 'isbn', 'tags', 'category', 'comments',
'pubdate', 'user_categories'): 'pubdate', 'user_categories', 'author_link_map'):
val = getattr(mi, attr, None) val = getattr(mi, attr, None)
if val is not None and val != [] and val != (None, None): if val is not None and val != [] and val != (None, None):
setattr(self, attr, val) setattr(self, attr, val)
@ -1336,6 +1337,8 @@ def metadata_to_opf(mi, as_string=True):
for tag in mi.tags: for tag in mi.tags:
factory(DC('subject'), tag) factory(DC('subject'), tag)
meta = lambda n, c: factory('meta', name='calibre:'+n, content=c) meta = lambda n, c: factory('meta', name='calibre:'+n, content=c)
if getattr(mi, 'author_link_map', None) is not None:
meta('author_link_map', json.dumps(mi.author_link_map))
if mi.series: if mi.series:
meta('series', mi.series) meta('series', mi.series)
if mi.series_index is not None: if mi.series_index is not None:

View File

@ -121,6 +121,16 @@ def render_data(mi, use_roman_numbers=True, all_fields=False):
if links: if links:
ans.append((field, u'<td class="title">%s</td><td>%s</td>'%( ans.append((field, u'<td class="title">%s</td><td>%s</td>'%(
_('Ids')+':', links))) _('Ids')+':', links)))
elif field == 'authors' and not isdevice:
authors = []
for aut in mi.authors:
if mi.author_link_map[aut]:
authors.append(u'<a href="%s">%s</a>' %
(mi.author_link_map[aut], aut))
else:
authors.append(aut)
ans.append((field, u'<td class="title">%s</td><td>%s</td>'%(name,
u' & '.join(authors))))
else: else:
val = mi.format_field(field)[-1] val = mi.format_field(field)[-1]
if val is None: if val is None:

View File

@ -33,7 +33,7 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
# Set up the column headings # Set up the column headings
self.table.setSelectionMode(QAbstractItemView.SingleSelection) self.table.setSelectionMode(QAbstractItemView.SingleSelection)
self.table.setColumnCount(2) self.table.setColumnCount(3)
self.down_arrow_icon = QIcon(I('arrow-down.png')) self.down_arrow_icon = QIcon(I('arrow-down.png'))
self.up_arrow_icon = QIcon(I('arrow-up.png')) self.up_arrow_icon = QIcon(I('arrow-up.png'))
self.blank_icon = QIcon(I('blank.png')) self.blank_icon = QIcon(I('blank.png'))
@ -43,26 +43,33 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
self.aus_col = QTableWidgetItem(_('Author sort')) self.aus_col = QTableWidgetItem(_('Author sort'))
self.table.setHorizontalHeaderItem(1, self.aus_col) self.table.setHorizontalHeaderItem(1, self.aus_col)
self.aus_col.setIcon(self.up_arrow_icon) self.aus_col.setIcon(self.up_arrow_icon)
self.aul_col = QTableWidgetItem(_('Link'))
self.table.setHorizontalHeaderItem(2, self.aul_col)
self.aus_col.setIcon(self.blank_icon)
# Add the data # Add the data
self.authors = {} self.authors = {}
auts = db.get_authors_with_ids() auts = db.get_authors_with_ids()
self.table.setRowCount(len(auts)) self.table.setRowCount(len(auts))
select_item = None select_item = None
for row, (id, author, sort) in enumerate(auts): for row, (id, author, sort, link) in enumerate(auts):
author = author.replace('|', ',') author = author.replace('|', ',')
self.authors[id] = (author, sort) self.authors[id] = (author, sort, link)
aut = tableItem(author) aut = tableItem(author)
aut.setData(Qt.UserRole, id) aut.setData(Qt.UserRole, id)
sort = tableItem(sort) sort = tableItem(sort)
link = tableItem(link)
self.table.setItem(row, 0, aut) self.table.setItem(row, 0, aut)
self.table.setItem(row, 1, sort) self.table.setItem(row, 1, sort)
self.table.setItem(row, 2, link)
if id == id_to_select: if id == id_to_select:
if select_sort: if select_sort:
select_item = sort select_item = sort
else: else:
select_item = aut select_item = aut
self.table.resizeColumnsToContents() self.table.resizeColumnsToContents()
if self.table.columnWidth(2) < 200:
self.table.setColumnWidth(2, 200)
# set up the cellChanged signal only after the table is filled # set up the cellChanged signal only after the table is filled
self.table.cellChanged.connect(self.cell_changed) self.table.cellChanged.connect(self.cell_changed)
@ -236,9 +243,10 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
id = self.table.item(row, 0).data(Qt.UserRole).toInt()[0] id = self.table.item(row, 0).data(Qt.UserRole).toInt()[0]
aut = unicode(self.table.item(row, 0).text()).strip() aut = unicode(self.table.item(row, 0).text()).strip()
sort = unicode(self.table.item(row, 1).text()).strip() sort = unicode(self.table.item(row, 1).text()).strip()
orig_aut,orig_sort = self.authors[id] link = unicode(self.table.item(row, 2).text()).strip()
if orig_aut != aut or orig_sort != sort: orig_aut,orig_sort,orig_link = self.authors[id]
self.result.append((id, orig_aut, aut, sort)) if orig_aut != aut or orig_sort != sort or orig_link != link:
self.result.append((id, orig_aut, aut, sort, link))
def do_recalc_author_sort(self): def do_recalc_author_sort(self):
self.table.cellChanged.disconnect() self.table.cellChanged.disconnect()
@ -276,6 +284,6 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
c.setText(author_to_author_sort(aut)) c.setText(author_to_author_sort(aut))
item = c item = c
else: else:
item = self.table.item(row, 1) item = self.table.item(row, col)
self.table.setCurrentItem(item) self.table.setCurrentItem(item)
self.table.scrollToItem(item) self.table.scrollToItem(item)

View File

@ -90,6 +90,7 @@ class BooksModel(QAbstractTableModel): # {{{
self.ids_to_highlight_set = set() self.ids_to_highlight_set = set()
self.current_highlighted_idx = None self.current_highlighted_idx = None
self.highlight_only = False self.highlight_only = False
self.current_row = -1
self.colors = frozenset([unicode(c) for c in QColor.colorNames()]) self.colors = frozenset([unicode(c) for c in QColor.colorNames()])
self.read_config() self.read_config()
@ -172,6 +173,7 @@ class BooksModel(QAbstractTableModel): # {{{
self.color_cache = defaultdict(dict) self.color_cache = defaultdict(dict)
for row in rows: for row in rows:
if row == current_row: if row == current_row:
self.current_row = row
self.new_bookdisplay_data.emit( self.new_bookdisplay_data.emit(
self.get_book_display_info(row)) self.get_book_display_info(row))
self.dataChanged.emit(self.index(row, 0), self.index(row, self.dataChanged.emit(self.index(row, 0), self.index(row,
@ -329,6 +331,8 @@ class BooksModel(QAbstractTableModel): # {{{
def refresh(self, reset=True): def refresh(self, reset=True):
self.db.refresh(field=None) self.db.refresh(field=None)
self.resort(reset=reset) self.resort(reset=reset)
if self.current_row >= 0:
self.new_bookdisplay_data.emit(self.get_book_display_info(self.current_row))
def reset(self): def reset(self):
self.color_cache = defaultdict(dict) self.color_cache = defaultdict(dict)
@ -368,12 +372,14 @@ class BooksModel(QAbstractTableModel): # {{{
def current_changed(self, current, previous, emit_signal=True): def current_changed(self, current, previous, emit_signal=True):
if current.isValid(): if current.isValid():
idx = current.row() self.current_row = idx = current.row()
data = self.get_book_display_info(idx) data = self.get_book_display_info(idx)
if emit_signal: if emit_signal:
self.new_bookdisplay_data.emit(data) self.new_bookdisplay_data.emit(data)
else: else:
return data return data
else:
self.current_row = -1
def get_book_info(self, index): def get_book_info(self, index):
if isinstance(index, int): if isinstance(index, int):

View File

@ -2081,12 +2081,14 @@ class TagBrowserMixin(object): # {{{
editor = EditAuthorsDialog(parent, db, id, select_sort) editor = EditAuthorsDialog(parent, db, id, select_sort)
d = editor.exec_() d = editor.exec_()
if d: if d:
for (id, old_author, new_author, new_sort) in editor.result: for (id, old_author, new_author, new_sort, new_link) in editor.result:
if old_author != new_author: if old_author != new_author:
# The id might change if the new author already exists # The id might change if the new author already exists
id = db.rename_author(id, new_author) id = db.rename_author(id, new_author)
db.set_sort_field_for_author(id, unicode(new_sort), db.set_sort_field_for_author(id, unicode(new_sort),
commit=False, notify=False) commit=False, notify=False)
db.set_link_field_for_author(id, unicode(new_link),
commit=False, notify=False)
db.commit() db.commit()
self.library_view.model().refresh() self.library_view.model().refresh()
self.tags_view.recount() self.tags_view.recount()

View File

@ -367,7 +367,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
'uuid', 'uuid',
'has_cover', 'has_cover',
('au_map', 'authors', 'author', ('au_map', 'authors', 'author',
'aum_sortconcat(link.id, authors.name, authors.sort)'), 'aum_sortconcat(link.id, authors.name, authors.sort, authors.link)'),
'last_modified', 'last_modified',
'(SELECT identifiers_concat(type, val) FROM identifiers WHERE identifiers.book=books.id) identifiers', '(SELECT identifiers_concat(type, val) FROM identifiers WHERE identifiers.book=books.id) identifiers',
] ]
@ -894,13 +894,17 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
aut_list = [] aut_list = []
aum = [] aum = []
aus = {} aus = {}
for (author, author_sort) in aut_list: aul = {}
aum.append(author.replace('|', ',')) for (author, author_sort, link) in aut_list:
aus[author] = author_sort.replace('|', ',') aut = author.replace('|', ',')
aum.append(aut)
aus[aut] = author_sort.replace('|', ',')
aul[aut] = link
mi.title = row[fm['title']] mi.title = row[fm['title']]
mi.authors = aum mi.authors = aum
mi.author_sort = row[fm['author_sort']] mi.author_sort = row[fm['author_sort']]
mi.author_sort_map = aus mi.author_sort_map = aus
mi.author_link_map = aul
mi.comments = row[fm['comments']] mi.comments = row[fm['comments']]
mi.publisher = row[fm['publisher']] mi.publisher = row[fm['publisher']]
mi.timestamp = row[fm['timestamp']] mi.timestamp = row[fm['timestamp']]
@ -2002,13 +2006,13 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
def authors_with_sort_strings(self, id, index_is_id=False): def authors_with_sort_strings(self, id, index_is_id=False):
id = id if index_is_id else self.id(id) id = id if index_is_id else self.id(id)
aut_strings = self.conn.get(''' aut_strings = self.conn.get('''
SELECT authors.id, authors.name, authors.sort SELECT authors.id, authors.name, authors.sort, authors.link
FROM authors, books_authors_link as bl FROM authors, books_authors_link as bl
WHERE bl.book=? and authors.id=bl.author WHERE bl.book=? and authors.id=bl.author
ORDER BY bl.id''', (id,)) ORDER BY bl.id''', (id,))
result = [] result = []
for (id_, author, sort,) in aut_strings: for (id_, author, sort, link) in aut_strings:
result.append((id_, author.replace('|', ','), sort)) result.append((id_, author.replace('|', ','), sort, link))
return result return result
# Given a book, return the author_sort string for authors of the book # Given a book, return the author_sort string for authors of the book
@ -2048,7 +2052,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
aum = self.authors_with_sort_strings(id_, index_is_id=True) aum = self.authors_with_sort_strings(id_, index_is_id=True)
self.data.set(id_, self.FIELD_MAP['au_map'], self.data.set(id_, self.FIELD_MAP['au_map'],
':#:'.join([':::'.join((au.replace(',', '|'), aus)) for (_, au, aus) in aum]), ':#:'.join([':::'.join((au.replace(',', '|'), aus, aul))
for (_, au, aus, aul) in aum]),
row_is_id=True) row_is_id=True)
def _set_authors(self, id, authors, allow_case_change=False): def _set_authors(self, id, authors, allow_case_change=False):
@ -2399,7 +2404,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
self.conn.commit() self.conn.commit()
def get_authors_with_ids(self): def get_authors_with_ids(self):
result = self.conn.get('SELECT id,name,sort FROM authors') result = self.conn.get('SELECT id,name,sort,link FROM authors')
if not result: if not result:
return [] return []
return result return result
@ -2410,6 +2415,13 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
(author,), all=False) (author,), all=False)
return result return result
def set_link_field_for_author(self, aid, link, commit=True, notify=False):
if not link:
link = ''
self.conn.execute('UPDATE authors SET link=? WHERE id=?', (link.strip(), aid))
if commit:
self.conn.commit()
def set_sort_field_for_author(self, old_id, new_sort, commit=True, notify=False): def set_sort_field_for_author(self, old_id, new_sort, commit=True, notify=False):
self.conn.execute('UPDATE authors SET sort=? WHERE id=?', \ self.conn.execute('UPDATE authors SET sort=? WHERE id=?', \
(new_sort.strip(), old_id)) (new_sort.strip(), old_id))

View File

@ -600,4 +600,14 @@ class SchemaUpgrade(object):
with open(os.path.join(bdir, fname), 'wb') as f: with open(os.path.join(bdir, fname), 'wb') as f:
f.write(script) f.write(script)
def upgrade_version_20(self):
'''
Add a link column to the authors table.
'''
script = '''
ALTER TABLE authors ADD COLUMN link TEXT NON NULL DEFAULT "";
'''
self.conn.executescript(script)

View File

@ -144,9 +144,9 @@ class AumSortedConcatenate(object):
def __init__(self): def __init__(self):
self.ans = {} self.ans = {}
def step(self, ndx, author, sort): def step(self, ndx, author, sort, link):
if author is not None: if author is not None:
self.ans[ndx] = author + ':::' + sort self.ans[ndx] = ':::'.join((author, sort, link))
def finalize(self): def finalize(self):
keys = self.ans.keys() keys = self.ans.keys()
@ -229,7 +229,7 @@ class DBThread(Thread):
load_c_extensions(self.conn) load_c_extensions(self.conn)
self.conn.row_factory = sqlite.Row if self.row_factory else lambda cursor, row : list(row) self.conn.row_factory = sqlite.Row if self.row_factory else lambda cursor, row : list(row)
self.conn.create_aggregate('concat', 1, Concatenate) self.conn.create_aggregate('concat', 1, Concatenate)
self.conn.create_aggregate('aum_sortconcat', 3, AumSortedConcatenate) self.conn.create_aggregate('aum_sortconcat', 4, AumSortedConcatenate)
self.conn.create_collation('PYNOCASE', partial(pynocase, self.conn.create_collation('PYNOCASE', partial(pynocase,
encoding=encoding)) encoding=encoding))
self.conn.create_function('title_sort', 1, title_sort) self.conn.create_function('title_sort', 1, title_sort)