mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Fix customization of SONY driver plugin, where deleting all collections items causes the settign to disappear. Fix #5751 (Adding/Deleting Search does not refresh Left Pane Correctly) and distiguish between delete confirmation dialogs for deleting from library and device views
This commit is contained in:
commit
085c859327
@ -143,10 +143,11 @@ class PRS505(USBMS):
|
||||
if booklists[i] is not None:
|
||||
blists[i] = booklists[i]
|
||||
opts = self.settings()
|
||||
collections = ['series', 'tags']
|
||||
if opts.extra_customization:
|
||||
collections = [x.strip() for x in
|
||||
opts.extra_customization.split(',')]
|
||||
else:
|
||||
collections = []
|
||||
debug_print('PRS505: collection fields:', collections)
|
||||
c.update(blists, collections)
|
||||
c.write()
|
||||
|
@ -38,8 +38,9 @@ class ConfigWidget(QWidget, Ui_ConfigWidget):
|
||||
self.opt_read_metadata.setChecked(self.settings.read_metadata)
|
||||
else:
|
||||
self.opt_read_metadata.hide()
|
||||
if extra_customization_message and settings.extra_customization:
|
||||
if extra_customization_message:
|
||||
self.extra_customization_label.setText(extra_customization_message)
|
||||
if settings.extra_customization:
|
||||
self.opt_extra_customization.setText(settings.extra_customization)
|
||||
else:
|
||||
self.extra_customization_label.setVisible(False)
|
||||
|
@ -3,6 +3,7 @@ __copyright__ = '2010, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
'''Dialog to create a new custom column'''
|
||||
|
||||
import re
|
||||
from functools import partial
|
||||
|
||||
from PyQt4.QtCore import SIGNAL
|
||||
@ -94,8 +95,8 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn):
|
||||
col = unicode(self.column_name_box.text()).lower()
|
||||
if not col:
|
||||
return self.simple_error('', _('No lookup name was provided'))
|
||||
if not col.isalnum() or not col[0].isalpha():
|
||||
return self.simple_error('', _('The label must contain only letters and digits, and start with a letter'))
|
||||
if re.match('^\w*$', col) is None or not col[0].isalpha():
|
||||
return self.simple_error('', _('The label must contain only letters, digits and underscores, and start with a letter'))
|
||||
col_heading = unicode(self.column_heading_box.text())
|
||||
col_type = self.column_types[self.column_type_box.currentIndex()]['datatype']
|
||||
if col_type == '*text':
|
||||
|
@ -63,8 +63,7 @@ class TagsView(QTreeView): # {{{
|
||||
|
||||
def sort_changed(self, state):
|
||||
config.set('sort_by_popularity', state == Qt.Checked)
|
||||
self.model().refresh()
|
||||
# self.search_restriction_set()
|
||||
self.recount()
|
||||
|
||||
def set_search_restriction(self, s):
|
||||
if s:
|
||||
@ -197,7 +196,9 @@ class TagsView(QTreeView): # {{{
|
||||
ci = self.indexAt(QPoint(10, 10))
|
||||
path = self.model().path_for_index(ci) if self.is_visible(ci) else None
|
||||
try:
|
||||
self.model().refresh()
|
||||
if not self.model().refresh(): # categories changed!
|
||||
self.set_new_model()
|
||||
path = None
|
||||
except: #Database connection could be closed if an integrity check is happening
|
||||
pass
|
||||
if path:
|
||||
@ -210,10 +211,16 @@ class TagsView(QTreeView): # {{{
|
||||
# gone, or if columns have been hidden or restored, we must rebuild the
|
||||
# model. Reason: it is much easier than reconstructing the browser tree.
|
||||
def set_new_model(self):
|
||||
try:
|
||||
self._model = TagsModel(self.db, parent=self,
|
||||
hidden_categories=self.hidden_categories,
|
||||
search_restriction=self.search_restriction)
|
||||
self.setModel(self._model)
|
||||
except:
|
||||
# The DB must be gone. Set the model to None and hope that someone
|
||||
# will call set_database later. I don't know if this in fact works
|
||||
self._model = None
|
||||
self.setModel(None)
|
||||
# }}}
|
||||
|
||||
class TagTreeItem(object): # {{{
|
||||
@ -323,18 +330,9 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
self.tags_view = parent
|
||||
self.hidden_categories = hidden_categories
|
||||
self.search_restriction = search_restriction
|
||||
self.row_map = []
|
||||
|
||||
# Reconstruct the user categories, putting them into metadata
|
||||
tb_cats = self.db.field_metadata
|
||||
for k in tb_cats.keys():
|
||||
if tb_cats[k]['kind'] in ['user', 'search']:
|
||||
del tb_cats[k]
|
||||
for user_cat in sorted(prefs['user_categories'].keys()):
|
||||
cat_name = user_cat+':' # add the ':' to avoid name collision
|
||||
tb_cats.add_user_category(label=cat_name, name=user_cat)
|
||||
if len(saved_searches.names()):
|
||||
tb_cats.add_search_category(label='search', name=_('Searches'))
|
||||
|
||||
# get_node_tree cannot return None here, because row_map is empty
|
||||
data = self.get_node_tree(config['sort_by_popularity'])
|
||||
self.root_item = TagTreeItem()
|
||||
for i, r in enumerate(self.row_map):
|
||||
@ -355,9 +353,22 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
self.search_restriction = s
|
||||
|
||||
def get_node_tree(self, sort):
|
||||
old_row_map = self.row_map[:]
|
||||
self.row_map = []
|
||||
self.categories = []
|
||||
|
||||
# Reconstruct the user categories, putting them into metadata
|
||||
tb_cats = self.db.field_metadata
|
||||
for k in tb_cats.keys():
|
||||
if tb_cats[k]['kind'] in ['user', 'search']:
|
||||
del tb_cats[k]
|
||||
for user_cat in sorted(prefs['user_categories'].keys()):
|
||||
cat_name = user_cat+':' # add the ':' to avoid name collision
|
||||
tb_cats.add_user_category(label=cat_name, name=user_cat)
|
||||
if len(saved_searches.names()):
|
||||
tb_cats.add_search_category(label='search', name=_('Searches'))
|
||||
|
||||
# Now get the categories
|
||||
if self.search_restriction:
|
||||
data = self.db.get_categories(sort_on_count=sort,
|
||||
icon_map=self.category_icon_map,
|
||||
@ -367,13 +378,19 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
|
||||
tb_categories = self.db.field_metadata
|
||||
for category in tb_categories:
|
||||
if category in data: # They should always be there, but ...
|
||||
if category in data: # The search category can come and go
|
||||
self.row_map.append(category)
|
||||
self.categories.append(tb_categories[category]['name'])
|
||||
if len(old_row_map) != 0 and len(old_row_map) != len(self.row_map):
|
||||
# A category has been added or removed. We must force a rebuild of
|
||||
# the model
|
||||
return None
|
||||
return data
|
||||
|
||||
def refresh(self):
|
||||
data = self.get_node_tree(config['sort_by_popularity']) # get category data
|
||||
if data is None:
|
||||
return False
|
||||
row_index = -1
|
||||
for i, r in enumerate(self.row_map):
|
||||
if self.hidden_categories and self.categories[i] in self.hidden_categories:
|
||||
@ -395,6 +412,7 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
tag.state = state_map.get(tag.name, 0)
|
||||
t = TagTreeItem(parent=category, data=tag, icon_map=self.icon_state_map)
|
||||
self.endInsertRows()
|
||||
return True
|
||||
|
||||
def columnCount(self, parent):
|
||||
return 1
|
||||
@ -408,6 +426,8 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
def setData(self, index, value, role=Qt.EditRole):
|
||||
if not index.isValid():
|
||||
return NONE
|
||||
# set up to position at the category label
|
||||
path = self.path_for_index(self.parent(index))
|
||||
val = unicode(value.toString())
|
||||
if not val:
|
||||
error_dialog(self.tags_view, _('Item is blank'),
|
||||
@ -439,7 +459,12 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
label=self.db.field_metadata[key]['label'])
|
||||
self.tags_view.tag_item_renamed.emit()
|
||||
item.tag.name = val
|
||||
self.refresh()
|
||||
self.refresh() # Should work, because no categories can have disappeared
|
||||
if path:
|
||||
idx = self.index_for_path(path)
|
||||
if idx.isValid():
|
||||
self.tags_view.setCurrentIndex(idx)
|
||||
self.tags_view.scrollTo(idx, QTreeView.PositionAtCenter)
|
||||
return True
|
||||
|
||||
def headerData(self, *args):
|
||||
|
@ -854,7 +854,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
||||
r = unicode(r)
|
||||
if r is not None and r != '':
|
||||
self.restriction_in_effect = True
|
||||
restriction = "search:%s"%(r)
|
||||
restriction = 'search:"%s"'%(r)
|
||||
else:
|
||||
self.restriction_in_effect = False
|
||||
restriction = ''
|
||||
@ -1557,7 +1557,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
||||
if not confirm('<p>'+_('The selected books will be '
|
||||
'<b>permanently deleted</b> '
|
||||
'from your device. Are you sure?')
|
||||
+'</p>', 'library_delete_books', self):
|
||||
+'</p>', 'device_delete_books', self):
|
||||
return
|
||||
if self.stack.currentIndex() == 1:
|
||||
view = self.memory_view
|
||||
|
@ -192,7 +192,7 @@ class CustomColumns(object):
|
||||
# check if item exists
|
||||
new_id = self.conn.get(
|
||||
'SELECT id FROM %s WHERE value=?'%table, (new_name,), all=False)
|
||||
if new_id is None:
|
||||
if new_id is None or old_id == new_id:
|
||||
self.conn.execute('UPDATE %s SET value=? WHERE id=?'%table, (new_name, old_id))
|
||||
else:
|
||||
# New id exists. If the column is_multiple, then process like
|
||||
|
@ -1003,8 +1003,9 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
new_id = self.conn.get(
|
||||
'''SELECT id from tags
|
||||
WHERE name=?''', (new_name,), all=False)
|
||||
if new_id is None:
|
||||
# easy case. Simply rename the tag
|
||||
if new_id is None or old_id == new_id:
|
||||
# easy cases. Simply rename the tag. Do it even if equal, in case
|
||||
# there is a change of case
|
||||
self.conn.execute('''UPDATE tags SET name=?
|
||||
WHERE id=?''', (new_name, old_id))
|
||||
else:
|
||||
@ -1041,7 +1042,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
new_id = self.conn.get(
|
||||
'''SELECT id from series
|
||||
WHERE name=?''', (new_name,), all=False)
|
||||
if new_id is None:
|
||||
if new_id is None or old_id == new_id:
|
||||
self.conn.execute('UPDATE series SET name=? WHERE id=?',
|
||||
(new_name, old_id))
|
||||
else:
|
||||
@ -1086,7 +1087,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
new_id = self.conn.get(
|
||||
'''SELECT id from publishers
|
||||
WHERE name=?''', (new_name,), all=False)
|
||||
if new_id is None:
|
||||
if new_id is None or old_id == new_id:
|
||||
# New name doesn't exist. Simply change the old name
|
||||
self.conn.execute('UPDATE publishers SET name=? WHERE id=?', \
|
||||
(new_name, old_id))
|
||||
@ -1113,22 +1114,34 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
new_name = new_name.replace(',', '|')
|
||||
|
||||
# Get the list of books we must fix up, one way or the other
|
||||
books = self.conn.get('SELECT book from books_authors_link WHERE author=?', (old_id,))
|
||||
# Save the list so we can use it twice
|
||||
bks = self.conn.get('SELECT book from books_authors_link WHERE author=?', (old_id,))
|
||||
books = []
|
||||
for (book_id,) in bks:
|
||||
books.append(book_id)
|
||||
|
||||
# check if the new author already exists
|
||||
new_id = self.conn.get('SELECT id from authors WHERE name=?',
|
||||
(new_name,), all=False)
|
||||
if new_id is None:
|
||||
if new_id is None or old_id == new_id:
|
||||
# No name clash. Go ahead and update the author's name
|
||||
self.conn.execute('UPDATE authors SET name=? WHERE id=?',
|
||||
(new_name, old_id))
|
||||
else:
|
||||
# First check for the degenerate case -- changing a value to itself.
|
||||
# Update it in case there is a change of case, but do nothing else
|
||||
if old_id == new_id:
|
||||
self.conn.execute('UPDATE authors SET name=? WHERE id=?',
|
||||
(new_name, old_id))
|
||||
self.conn.commit()
|
||||
return
|
||||
# Author exists. To fix this, we must replace all the authors
|
||||
# instead of replacing the one. Reason: db integrity checks can stop
|
||||
# the rename process, which would leave everything half-done. We
|
||||
# can't do it the same way as tags (delete and add) because author
|
||||
# order is important.
|
||||
for (book_id,) in books:
|
||||
|
||||
for book_id in books:
|
||||
# Get the existing list of authors
|
||||
authors = self.conn.get('''
|
||||
SELECT author from books_authors_link
|
||||
@ -1139,7 +1152,6 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
# with the new one while we are at it
|
||||
for i,aut in enumerate(authors):
|
||||
authors[i] = aut[0] if aut[0] != old_id else new_id
|
||||
|
||||
# Delete the existing authors list
|
||||
self.conn.execute('''DELETE FROM books_authors_link
|
||||
WHERE book=?''',(book_id,))
|
||||
@ -1154,11 +1166,12 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
# metadata. Ignore it.
|
||||
pass
|
||||
# Now delete the old author from the DB
|
||||
bks = self.conn.get('SELECT book FROM books_authors_link WHERE author=?', (old_id,))
|
||||
self.conn.execute('DELETE FROM authors WHERE id=?', (old_id,))
|
||||
self.conn.commit()
|
||||
# the authors are now changed, either by changing the author's name
|
||||
# or replacing the author in the list. Now must fix up the books.
|
||||
for (book_id,) in books:
|
||||
for book_id in books:
|
||||
# First, must refresh the cache to see the new authors
|
||||
self.data.refresh_ids(self, [book_id])
|
||||
# now fix the filesystem paths
|
||||
@ -1168,14 +1181,17 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
SELECT authors.name
|
||||
FROM authors, books_authors_link as bl
|
||||
WHERE bl.book = ? and bl.author = authors.id
|
||||
ORDER BY bl.id
|
||||
''' , (book_id,))
|
||||
# unpack the double-list structure
|
||||
for i,aut in enumerate(authors):
|
||||
authors[i] = aut[0]
|
||||
ss = authors_to_sort_string(authors)
|
||||
# Change the '|'s to ','
|
||||
ss = ss.replace('|', ',')
|
||||
self.conn.execute('''UPDATE books
|
||||
SET author_sort=?
|
||||
WHERE id=?''', (ss, old_id))
|
||||
WHERE id=?''', (ss, book_id))
|
||||
self.conn.commit()
|
||||
# the caller will do a general refresh, so we don't need to
|
||||
# do one here
|
||||
|
Loading…
x
Reference in New Issue
Block a user