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:
|
if booklists[i] is not None:
|
||||||
blists[i] = booklists[i]
|
blists[i] = booklists[i]
|
||||||
opts = self.settings()
|
opts = self.settings()
|
||||||
collections = ['series', 'tags']
|
|
||||||
if opts.extra_customization:
|
if opts.extra_customization:
|
||||||
collections = [x.strip() for x in
|
collections = [x.strip() for x in
|
||||||
opts.extra_customization.split(',')]
|
opts.extra_customization.split(',')]
|
||||||
|
else:
|
||||||
|
collections = []
|
||||||
debug_print('PRS505: collection fields:', collections)
|
debug_print('PRS505: collection fields:', collections)
|
||||||
c.update(blists, collections)
|
c.update(blists, collections)
|
||||||
c.write()
|
c.write()
|
||||||
|
@ -38,9 +38,10 @@ class ConfigWidget(QWidget, Ui_ConfigWidget):
|
|||||||
self.opt_read_metadata.setChecked(self.settings.read_metadata)
|
self.opt_read_metadata.setChecked(self.settings.read_metadata)
|
||||||
else:
|
else:
|
||||||
self.opt_read_metadata.hide()
|
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)
|
self.extra_customization_label.setText(extra_customization_message)
|
||||||
self.opt_extra_customization.setText(settings.extra_customization)
|
if settings.extra_customization:
|
||||||
|
self.opt_extra_customization.setText(settings.extra_customization)
|
||||||
else:
|
else:
|
||||||
self.extra_customization_label.setVisible(False)
|
self.extra_customization_label.setVisible(False)
|
||||||
self.opt_extra_customization.setVisible(False)
|
self.opt_extra_customization.setVisible(False)
|
||||||
|
@ -3,6 +3,7 @@ __copyright__ = '2010, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
|
|
||||||
'''Dialog to create a new custom column'''
|
'''Dialog to create a new custom column'''
|
||||||
|
|
||||||
|
import re
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from PyQt4.QtCore import SIGNAL
|
from PyQt4.QtCore import SIGNAL
|
||||||
@ -94,8 +95,8 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn):
|
|||||||
col = unicode(self.column_name_box.text()).lower()
|
col = unicode(self.column_name_box.text()).lower()
|
||||||
if not col:
|
if not col:
|
||||||
return self.simple_error('', _('No lookup name was provided'))
|
return self.simple_error('', _('No lookup name was provided'))
|
||||||
if not col.isalnum() or not col[0].isalpha():
|
if re.match('^\w*$', col) is None or not col[0].isalpha():
|
||||||
return self.simple_error('', _('The label must contain only letters and digits, and start with a letter'))
|
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_heading = unicode(self.column_heading_box.text())
|
||||||
col_type = self.column_types[self.column_type_box.currentIndex()]['datatype']
|
col_type = self.column_types[self.column_type_box.currentIndex()]['datatype']
|
||||||
if col_type == '*text':
|
if col_type == '*text':
|
||||||
|
@ -63,8 +63,7 @@ class TagsView(QTreeView): # {{{
|
|||||||
|
|
||||||
def sort_changed(self, state):
|
def sort_changed(self, state):
|
||||||
config.set('sort_by_popularity', state == Qt.Checked)
|
config.set('sort_by_popularity', state == Qt.Checked)
|
||||||
self.model().refresh()
|
self.recount()
|
||||||
# self.search_restriction_set()
|
|
||||||
|
|
||||||
def set_search_restriction(self, s):
|
def set_search_restriction(self, s):
|
||||||
if s:
|
if s:
|
||||||
@ -197,7 +196,9 @@ class TagsView(QTreeView): # {{{
|
|||||||
ci = self.indexAt(QPoint(10, 10))
|
ci = self.indexAt(QPoint(10, 10))
|
||||||
path = self.model().path_for_index(ci) if self.is_visible(ci) else None
|
path = self.model().path_for_index(ci) if self.is_visible(ci) else None
|
||||||
try:
|
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
|
except: #Database connection could be closed if an integrity check is happening
|
||||||
pass
|
pass
|
||||||
if path:
|
if path:
|
||||||
@ -210,10 +211,16 @@ class TagsView(QTreeView): # {{{
|
|||||||
# gone, or if columns have been hidden or restored, we must rebuild the
|
# gone, or if columns have been hidden or restored, we must rebuild the
|
||||||
# model. Reason: it is much easier than reconstructing the browser tree.
|
# model. Reason: it is much easier than reconstructing the browser tree.
|
||||||
def set_new_model(self):
|
def set_new_model(self):
|
||||||
self._model = TagsModel(self.db, parent=self,
|
try:
|
||||||
hidden_categories=self.hidden_categories,
|
self._model = TagsModel(self.db, parent=self,
|
||||||
search_restriction=self.search_restriction)
|
hidden_categories=self.hidden_categories,
|
||||||
self.setModel(self._model)
|
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): # {{{
|
class TagTreeItem(object): # {{{
|
||||||
@ -323,18 +330,9 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
self.tags_view = parent
|
self.tags_view = parent
|
||||||
self.hidden_categories = hidden_categories
|
self.hidden_categories = hidden_categories
|
||||||
self.search_restriction = search_restriction
|
self.search_restriction = search_restriction
|
||||||
|
self.row_map = []
|
||||||
|
|
||||||
# Reconstruct the user categories, putting them into metadata
|
# get_node_tree cannot return None here, because row_map is empty
|
||||||
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'))
|
|
||||||
|
|
||||||
data = self.get_node_tree(config['sort_by_popularity'])
|
data = self.get_node_tree(config['sort_by_popularity'])
|
||||||
self.root_item = TagTreeItem()
|
self.root_item = TagTreeItem()
|
||||||
for i, r in enumerate(self.row_map):
|
for i, r in enumerate(self.row_map):
|
||||||
@ -355,9 +353,22 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
self.search_restriction = s
|
self.search_restriction = s
|
||||||
|
|
||||||
def get_node_tree(self, sort):
|
def get_node_tree(self, sort):
|
||||||
|
old_row_map = self.row_map[:]
|
||||||
self.row_map = []
|
self.row_map = []
|
||||||
self.categories = []
|
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:
|
if self.search_restriction:
|
||||||
data = self.db.get_categories(sort_on_count=sort,
|
data = self.db.get_categories(sort_on_count=sort,
|
||||||
icon_map=self.category_icon_map,
|
icon_map=self.category_icon_map,
|
||||||
@ -367,13 +378,19 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
|
|
||||||
tb_categories = self.db.field_metadata
|
tb_categories = self.db.field_metadata
|
||||||
for category in tb_categories:
|
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.row_map.append(category)
|
||||||
self.categories.append(tb_categories[category]['name'])
|
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
|
return data
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self):
|
||||||
data = self.get_node_tree(config['sort_by_popularity']) # get category data
|
data = self.get_node_tree(config['sort_by_popularity']) # get category data
|
||||||
|
if data is None:
|
||||||
|
return False
|
||||||
row_index = -1
|
row_index = -1
|
||||||
for i, r in enumerate(self.row_map):
|
for i, r in enumerate(self.row_map):
|
||||||
if self.hidden_categories and self.categories[i] in self.hidden_categories:
|
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)
|
tag.state = state_map.get(tag.name, 0)
|
||||||
t = TagTreeItem(parent=category, data=tag, icon_map=self.icon_state_map)
|
t = TagTreeItem(parent=category, data=tag, icon_map=self.icon_state_map)
|
||||||
self.endInsertRows()
|
self.endInsertRows()
|
||||||
|
return True
|
||||||
|
|
||||||
def columnCount(self, parent):
|
def columnCount(self, parent):
|
||||||
return 1
|
return 1
|
||||||
@ -408,6 +426,8 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
def setData(self, index, value, role=Qt.EditRole):
|
def setData(self, index, value, role=Qt.EditRole):
|
||||||
if not index.isValid():
|
if not index.isValid():
|
||||||
return NONE
|
return NONE
|
||||||
|
# set up to position at the category label
|
||||||
|
path = self.path_for_index(self.parent(index))
|
||||||
val = unicode(value.toString())
|
val = unicode(value.toString())
|
||||||
if not val:
|
if not val:
|
||||||
error_dialog(self.tags_view, _('Item is blank'),
|
error_dialog(self.tags_view, _('Item is blank'),
|
||||||
@ -439,7 +459,12 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
label=self.db.field_metadata[key]['label'])
|
label=self.db.field_metadata[key]['label'])
|
||||||
self.tags_view.tag_item_renamed.emit()
|
self.tags_view.tag_item_renamed.emit()
|
||||||
item.tag.name = val
|
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
|
return True
|
||||||
|
|
||||||
def headerData(self, *args):
|
def headerData(self, *args):
|
||||||
|
@ -854,7 +854,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
r = unicode(r)
|
r = unicode(r)
|
||||||
if r is not None and r != '':
|
if r is not None and r != '':
|
||||||
self.restriction_in_effect = True
|
self.restriction_in_effect = True
|
||||||
restriction = "search:%s"%(r)
|
restriction = 'search:"%s"'%(r)
|
||||||
else:
|
else:
|
||||||
self.restriction_in_effect = False
|
self.restriction_in_effect = False
|
||||||
restriction = ''
|
restriction = ''
|
||||||
@ -1557,7 +1557,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
if not confirm('<p>'+_('The selected books will be '
|
if not confirm('<p>'+_('The selected books will be '
|
||||||
'<b>permanently deleted</b> '
|
'<b>permanently deleted</b> '
|
||||||
'from your device. Are you sure?')
|
'from your device. Are you sure?')
|
||||||
+'</p>', 'library_delete_books', self):
|
+'</p>', 'device_delete_books', self):
|
||||||
return
|
return
|
||||||
if self.stack.currentIndex() == 1:
|
if self.stack.currentIndex() == 1:
|
||||||
view = self.memory_view
|
view = self.memory_view
|
||||||
|
@ -192,7 +192,7 @@ class CustomColumns(object):
|
|||||||
# check if item exists
|
# check if item exists
|
||||||
new_id = self.conn.get(
|
new_id = self.conn.get(
|
||||||
'SELECT id FROM %s WHERE value=?'%table, (new_name,), all=False)
|
'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))
|
self.conn.execute('UPDATE %s SET value=? WHERE id=?'%table, (new_name, old_id))
|
||||||
else:
|
else:
|
||||||
# New id exists. If the column is_multiple, then process like
|
# 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(
|
new_id = self.conn.get(
|
||||||
'''SELECT id from tags
|
'''SELECT id from tags
|
||||||
WHERE name=?''', (new_name,), all=False)
|
WHERE name=?''', (new_name,), all=False)
|
||||||
if new_id is None:
|
if new_id is None or old_id == new_id:
|
||||||
# easy case. Simply rename the tag
|
# 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=?
|
self.conn.execute('''UPDATE tags SET name=?
|
||||||
WHERE id=?''', (new_name, old_id))
|
WHERE id=?''', (new_name, old_id))
|
||||||
else:
|
else:
|
||||||
@ -1041,7 +1042,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
new_id = self.conn.get(
|
new_id = self.conn.get(
|
||||||
'''SELECT id from series
|
'''SELECT id from series
|
||||||
WHERE name=?''', (new_name,), all=False)
|
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=?',
|
self.conn.execute('UPDATE series SET name=? WHERE id=?',
|
||||||
(new_name, old_id))
|
(new_name, old_id))
|
||||||
else:
|
else:
|
||||||
@ -1086,7 +1087,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
new_id = self.conn.get(
|
new_id = self.conn.get(
|
||||||
'''SELECT id from publishers
|
'''SELECT id from publishers
|
||||||
WHERE name=?''', (new_name,), all=False)
|
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
|
# New name doesn't exist. Simply change the old name
|
||||||
self.conn.execute('UPDATE publishers SET name=? WHERE id=?', \
|
self.conn.execute('UPDATE publishers SET name=? WHERE id=?', \
|
||||||
(new_name, old_id))
|
(new_name, old_id))
|
||||||
@ -1113,22 +1114,34 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
new_name = new_name.replace(',', '|')
|
new_name = new_name.replace(',', '|')
|
||||||
|
|
||||||
# Get the list of books we must fix up, one way or the other
|
# 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
|
# check if the new author already exists
|
||||||
new_id = self.conn.get('SELECT id from authors WHERE name=?',
|
new_id = self.conn.get('SELECT id from authors WHERE name=?',
|
||||||
(new_name,), all=False)
|
(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
|
# No name clash. Go ahead and update the author's name
|
||||||
self.conn.execute('UPDATE authors SET name=? WHERE id=?',
|
self.conn.execute('UPDATE authors SET name=? WHERE id=?',
|
||||||
(new_name, old_id))
|
(new_name, old_id))
|
||||||
else:
|
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
|
# Author exists. To fix this, we must replace all the authors
|
||||||
# instead of replacing the one. Reason: db integrity checks can stop
|
# instead of replacing the one. Reason: db integrity checks can stop
|
||||||
# the rename process, which would leave everything half-done. We
|
# the rename process, which would leave everything half-done. We
|
||||||
# can't do it the same way as tags (delete and add) because author
|
# can't do it the same way as tags (delete and add) because author
|
||||||
# order is important.
|
# order is important.
|
||||||
for (book_id,) in books:
|
|
||||||
|
for book_id in books:
|
||||||
# Get the existing list of authors
|
# Get the existing list of authors
|
||||||
authors = self.conn.get('''
|
authors = self.conn.get('''
|
||||||
SELECT author from books_authors_link
|
SELECT author from books_authors_link
|
||||||
@ -1139,7 +1152,6 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
# with the new one while we are at it
|
# with the new one while we are at it
|
||||||
for i,aut in enumerate(authors):
|
for i,aut in enumerate(authors):
|
||||||
authors[i] = aut[0] if aut[0] != old_id else new_id
|
authors[i] = aut[0] if aut[0] != old_id else new_id
|
||||||
|
|
||||||
# Delete the existing authors list
|
# Delete the existing authors list
|
||||||
self.conn.execute('''DELETE FROM books_authors_link
|
self.conn.execute('''DELETE FROM books_authors_link
|
||||||
WHERE book=?''',(book_id,))
|
WHERE book=?''',(book_id,))
|
||||||
@ -1154,11 +1166,12 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
# metadata. Ignore it.
|
# metadata. Ignore it.
|
||||||
pass
|
pass
|
||||||
# Now delete the old author from the DB
|
# 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.execute('DELETE FROM authors WHERE id=?', (old_id,))
|
||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
# the authors are now changed, either by changing the author's name
|
# 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.
|
# 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
|
# First, must refresh the cache to see the new authors
|
||||||
self.data.refresh_ids(self, [book_id])
|
self.data.refresh_ids(self, [book_id])
|
||||||
# now fix the filesystem paths
|
# now fix the filesystem paths
|
||||||
@ -1168,14 +1181,17 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
SELECT authors.name
|
SELECT authors.name
|
||||||
FROM authors, books_authors_link as bl
|
FROM authors, books_authors_link as bl
|
||||||
WHERE bl.book = ? and bl.author = authors.id
|
WHERE bl.book = ? and bl.author = authors.id
|
||||||
|
ORDER BY bl.id
|
||||||
''' , (book_id,))
|
''' , (book_id,))
|
||||||
# unpack the double-list structure
|
# unpack the double-list structure
|
||||||
for i,aut in enumerate(authors):
|
for i,aut in enumerate(authors):
|
||||||
authors[i] = aut[0]
|
authors[i] = aut[0]
|
||||||
ss = authors_to_sort_string(authors)
|
ss = authors_to_sort_string(authors)
|
||||||
|
# Change the '|'s to ','
|
||||||
|
ss = ss.replace('|', ',')
|
||||||
self.conn.execute('''UPDATE books
|
self.conn.execute('''UPDATE books
|
||||||
SET author_sort=?
|
SET author_sort=?
|
||||||
WHERE id=?''', (ss, old_id))
|
WHERE id=?''', (ss, book_id))
|
||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
# the caller will do a general refresh, so we don't need to
|
# the caller will do a general refresh, so we don't need to
|
||||||
# do one here
|
# do one here
|
||||||
|
Loading…
x
Reference in New Issue
Block a user