mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
SONY driver: Allow sorting of collections by arbitrary field via a new tweak. Use the same title casing algorithm in al places. Fix bulk edit of dual state boolean columns
This commit is contained in:
commit
c66f55e7c3
@ -106,7 +106,8 @@ title_sort_articles=r'^(A|The|An)\s+'
|
|||||||
auto_connect_to_folder = ''
|
auto_connect_to_folder = ''
|
||||||
|
|
||||||
|
|
||||||
# Specify renaming rules for sony collections. Collections on Sonys are named
|
# Specify renaming rules for sony collections. This tweak is only applicable if
|
||||||
|
# metadata management is set to automatic. Collections on Sonys are named
|
||||||
# depending upon whether the field is standard or custom. A collection derived
|
# depending upon whether the field is standard or custom. A collection derived
|
||||||
# from a standard field is named for the value in that field. For example, if
|
# from a standard field is named for the value in that field. For example, if
|
||||||
# the standard 'series' column contains the name 'Darkover', then the series
|
# the standard 'series' column contains the name 'Darkover', then the series
|
||||||
@ -137,6 +138,24 @@ auto_connect_to_folder = ''
|
|||||||
sony_collection_renaming_rules={}
|
sony_collection_renaming_rules={}
|
||||||
|
|
||||||
|
|
||||||
|
# Specify how sony collections are sorted. This tweak is only applicable if
|
||||||
|
# metadata management is set to automatic. You can indicate which metadata is to
|
||||||
|
# be used to sort on a collection-by-collection basis. The format of the tweak
|
||||||
|
# is a list of metadata fields from which collections are made, followed by the
|
||||||
|
# name of the metadata field containing the sort value.
|
||||||
|
# Example: The following indicates that collections built from pubdate and tags
|
||||||
|
# are to be sorted by the value in the custom column '#mydate', that collections
|
||||||
|
# built from 'series' are to be sorted by 'series_index', and that all other
|
||||||
|
# collections are to be sorted by title. If a collection metadata field is not
|
||||||
|
# named, then if it is a series- based collection it is sorted by series order,
|
||||||
|
# otherwise it is sorted by title order.
|
||||||
|
# [(['pubdate', 'tags'],'#mydate'), (['series'],'series_index'), (['*'], 'title')]
|
||||||
|
# Note that the bracketing and parentheses are required. The syntax is
|
||||||
|
# [ ( [list of fields], sort field ) , ( [ list of fields ] , sort field ) ]
|
||||||
|
# Default: empty (no rules), so no collection attributes are named.
|
||||||
|
sony_collection_sorting_rules = []
|
||||||
|
|
||||||
|
|
||||||
# Create search terms to apply a query across several built-in search terms.
|
# Create search terms to apply a query across several built-in search terms.
|
||||||
# Syntax: {'new term':['existing term 1', 'term 2', ...], 'new':['old'...] ...}
|
# Syntax: {'new term':['existing term 1', 'term 2', ...], 'new':['old'...] ...}
|
||||||
# Example: create the term 'myseries' that when used as myseries:foo would
|
# Example: create the term 'myseries' that when used as myseries:foo would
|
||||||
|
@ -99,6 +99,13 @@ class CollectionsBookList(BookList):
|
|||||||
def supports_collections(self):
|
def supports_collections(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def in_category_sort_rules(self, attr):
|
||||||
|
sorts = tweaks['sony_collection_sorting_rules']
|
||||||
|
for attrs,sortattr in sorts:
|
||||||
|
if attr in attrs or '*' in attrs:
|
||||||
|
return sortattr
|
||||||
|
return None
|
||||||
|
|
||||||
def compute_category_name(self, attr, category, field_meta):
|
def compute_category_name(self, attr, category, field_meta):
|
||||||
renames = tweaks['sony_collection_renaming_rules']
|
renames = tweaks['sony_collection_renaming_rules']
|
||||||
attr_name = renames.get(attr, None)
|
attr_name = renames.get(attr, None)
|
||||||
@ -116,6 +123,7 @@ class CollectionsBookList(BookList):
|
|||||||
from calibre.devices.usbms.driver import debug_print
|
from calibre.devices.usbms.driver import debug_print
|
||||||
debug_print('Starting get_collections:', prefs['manage_device_metadata'])
|
debug_print('Starting get_collections:', prefs['manage_device_metadata'])
|
||||||
debug_print('Renaming rules:', tweaks['sony_collection_renaming_rules'])
|
debug_print('Renaming rules:', tweaks['sony_collection_renaming_rules'])
|
||||||
|
debug_print('Sorting rules:', tweaks['sony_collection_sorting_rules'])
|
||||||
|
|
||||||
# Complexity: we can use renaming rules only when using automatic
|
# Complexity: we can use renaming rules only when using automatic
|
||||||
# management. Otherwise we don't always have the metadata to make the
|
# management. Otherwise we don't always have the metadata to make the
|
||||||
@ -171,6 +179,7 @@ class CollectionsBookList(BookList):
|
|||||||
else:
|
else:
|
||||||
val = [val]
|
val = [val]
|
||||||
|
|
||||||
|
sort_attr = self.in_category_sort_rules(attr)
|
||||||
for category in val:
|
for category in val:
|
||||||
is_series = False
|
is_series = False
|
||||||
if doing_dc:
|
if doing_dc:
|
||||||
@ -199,22 +208,41 @@ class CollectionsBookList(BookList):
|
|||||||
|
|
||||||
if cat_name not in collections:
|
if cat_name not in collections:
|
||||||
collections[cat_name] = {}
|
collections[cat_name] = {}
|
||||||
if is_series:
|
if use_renaming_rules and sort_attr:
|
||||||
|
sort_val = book.get(sort_attr, None)
|
||||||
|
collections[cat_name][lpath] = \
|
||||||
|
(book, sort_val, book.get('title_sort', 'zzzz'))
|
||||||
|
elif is_series:
|
||||||
if doing_dc:
|
if doing_dc:
|
||||||
collections[cat_name][lpath] = \
|
collections[cat_name][lpath] = \
|
||||||
(book, book.get('series_index', sys.maxint))
|
(book, book.get('series_index', sys.maxint), '')
|
||||||
else:
|
else:
|
||||||
collections[cat_name][lpath] = \
|
collections[cat_name][lpath] = \
|
||||||
(book, book.get(attr+'_index', sys.maxint))
|
(book, book.get(attr+'_index', sys.maxint), '')
|
||||||
else:
|
else:
|
||||||
if lpath not in collections[cat_name]:
|
if lpath not in collections[cat_name]:
|
||||||
collections[cat_name][lpath] = \
|
collections[cat_name][lpath] = \
|
||||||
(book, book.get('title_sort', 'zzzz'))
|
(book, book.get('title_sort', 'zzzz'), '')
|
||||||
# Sort collections
|
# Sort collections
|
||||||
result = {}
|
result = {}
|
||||||
|
|
||||||
|
def none_cmp(xx, yy):
|
||||||
|
x = xx[1]
|
||||||
|
y = yy[1]
|
||||||
|
if x is None and y is None:
|
||||||
|
return cmp(xx[2], yy[2])
|
||||||
|
if x is None:
|
||||||
|
return 1
|
||||||
|
if y is None:
|
||||||
|
return -1
|
||||||
|
c = cmp(x, y)
|
||||||
|
if c != 0:
|
||||||
|
return c
|
||||||
|
return cmp(xx[2], yy[2])
|
||||||
|
|
||||||
for category, lpaths in collections.items():
|
for category, lpaths in collections.items():
|
||||||
books = lpaths.values()
|
books = lpaths.values()
|
||||||
books.sort(cmp=lambda x,y:cmp(x[1], y[1]))
|
books.sort(cmp=none_cmp)
|
||||||
result[category] = [x[0] for x in books]
|
result[category] = [x[0] for x in books]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -429,7 +429,38 @@ class BulkBase(Base):
|
|||||||
self.db.set_custom_bulk(book_ids, val, num=self.col_id, notify=notify)
|
self.db.set_custom_bulk(book_ids, val, num=self.col_id, notify=notify)
|
||||||
|
|
||||||
class BulkBool(BulkBase, Bool):
|
class BulkBool(BulkBase, Bool):
|
||||||
pass
|
|
||||||
|
def get_initial_value(self, book_ids):
|
||||||
|
value = None
|
||||||
|
for book_id in book_ids:
|
||||||
|
val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True)
|
||||||
|
if tweaks['bool_custom_columns_are_tristate'] == 'no' and val is None:
|
||||||
|
val = False
|
||||||
|
if value is not None and value != val:
|
||||||
|
return None
|
||||||
|
value = val
|
||||||
|
return value
|
||||||
|
|
||||||
|
def setup_ui(self, parent):
|
||||||
|
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent),
|
||||||
|
QComboBox(parent)]
|
||||||
|
w = self.widgets[1]
|
||||||
|
items = [_('Yes'), _('No'), _('Undefined')]
|
||||||
|
icons = [I('ok.png'), I('list_remove.png'), I('blank.png')]
|
||||||
|
for icon, text in zip(icons, items):
|
||||||
|
w.addItem(QIcon(icon), text)
|
||||||
|
|
||||||
|
def setter(self, val):
|
||||||
|
val = {None: 2, False: 1, True: 0}[val]
|
||||||
|
self.widgets[1].setCurrentIndex(val)
|
||||||
|
|
||||||
|
def commit(self, book_ids, notify=False):
|
||||||
|
val = self.gui_val
|
||||||
|
val = self.normalize_ui_val(val)
|
||||||
|
if val != self.initial_val:
|
||||||
|
if tweaks['bool_custom_columns_are_tristate'] == 'no' and val is None:
|
||||||
|
val = False
|
||||||
|
self.db.set_custom_bulk(book_ids, val, num=self.col_id, notify=notify)
|
||||||
|
|
||||||
class BulkInt(BulkBase, Int):
|
class BulkInt(BulkBase, Int):
|
||||||
pass
|
pass
|
||||||
|
@ -16,6 +16,7 @@ from calibre.gui2.custom_column_widgets import populate_metadata_page
|
|||||||
from calibre.gui2 import error_dialog
|
from calibre.gui2 import error_dialog
|
||||||
from calibre.gui2.progress_indicator import ProgressIndicator
|
from calibre.gui2.progress_indicator import ProgressIndicator
|
||||||
from calibre.utils.config import dynamic
|
from calibre.utils.config import dynamic
|
||||||
|
from calibre.utils.titlecase import titlecase
|
||||||
|
|
||||||
class MyBlockingBusy(QDialog):
|
class MyBlockingBusy(QDialog):
|
||||||
|
|
||||||
@ -50,6 +51,7 @@ class MyBlockingBusy(QDialog):
|
|||||||
self.start()
|
self.start()
|
||||||
|
|
||||||
self.args = args
|
self.args = args
|
||||||
|
self.series_start_value = None
|
||||||
self.db = db
|
self.db = db
|
||||||
self.ids = ids
|
self.ids = ids
|
||||||
self.error = None
|
self.error = None
|
||||||
@ -115,7 +117,7 @@ class MyBlockingBusy(QDialog):
|
|||||||
aum = [a.strip().replace('|', ',') for a in aum.split(',')]
|
aum = [a.strip().replace('|', ',') for a in aum.split(',')]
|
||||||
new_title = authors_to_string(aum)
|
new_title = authors_to_string(aum)
|
||||||
if do_title_case:
|
if do_title_case:
|
||||||
new_title = new_title.title()
|
new_title = titlecase(new_title)
|
||||||
self.db.set_title(id, new_title, notify=False)
|
self.db.set_title(id, new_title, notify=False)
|
||||||
title_set = True
|
title_set = True
|
||||||
if title:
|
if title:
|
||||||
@ -123,7 +125,7 @@ class MyBlockingBusy(QDialog):
|
|||||||
self.db.set_authors(id, new_authors, notify=False)
|
self.db.set_authors(id, new_authors, notify=False)
|
||||||
if do_title_case and not title_set:
|
if do_title_case and not title_set:
|
||||||
title = self.db.title(id, index_is_id=True)
|
title = self.db.title(id, index_is_id=True)
|
||||||
self.db.set_title(id, title.title(), notify=False)
|
self.db.set_title(id, titlecase(title), notify=False)
|
||||||
if au:
|
if au:
|
||||||
self.db.set_authors(id, string_to_authors(au), notify=False)
|
self.db.set_authors(id, string_to_authors(au), notify=False)
|
||||||
elif self.current_phase == 2:
|
elif self.current_phase == 2:
|
||||||
@ -147,8 +149,10 @@ class MyBlockingBusy(QDialog):
|
|||||||
|
|
||||||
if do_series:
|
if do_series:
|
||||||
if do_series_restart:
|
if do_series_restart:
|
||||||
next = series_start_value
|
if self.series_start_value is None:
|
||||||
series_start_value += 1
|
self.series_start_value = series_start_value
|
||||||
|
next = self.series_start_value
|
||||||
|
self.series_start_value += 1
|
||||||
else:
|
else:
|
||||||
next = self.db.get_next_series_num_for(series)
|
next = self.db.get_next_series_num_for(series)
|
||||||
self.db.set_series(id, series, notify=False, commit=False)
|
self.db.set_series(id, series, notify=False, commit=False)
|
||||||
@ -179,7 +183,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
|||||||
s_r_functions = { '' : lambda x: x,
|
s_r_functions = { '' : lambda x: x,
|
||||||
_('Lower Case') : lambda x: x.lower(),
|
_('Lower Case') : lambda x: x.lower(),
|
||||||
_('Upper Case') : lambda x: x.upper(),
|
_('Upper Case') : lambda x: x.upper(),
|
||||||
_('Title Case') : lambda x: x.title(),
|
_('Title Case') : lambda x: titlecase(x),
|
||||||
}
|
}
|
||||||
|
|
||||||
s_r_match_modes = [ _('Character match'),
|
s_r_match_modes = [ _('Character match'),
|
||||||
|
@ -7,6 +7,7 @@ Created on 23 Sep 2010
|
|||||||
import re, string, traceback
|
import re, string, traceback
|
||||||
|
|
||||||
from calibre.constants import DEBUG
|
from calibre.constants import DEBUG
|
||||||
|
from calibre.utils.titlecase import titlecase
|
||||||
|
|
||||||
class TemplateFormatter(string.Formatter):
|
class TemplateFormatter(string.Formatter):
|
||||||
'''
|
'''
|
||||||
@ -81,7 +82,7 @@ class TemplateFormatter(string.Formatter):
|
|||||||
functions = {
|
functions = {
|
||||||
'uppercase' : (0, lambda s,x: x.upper()),
|
'uppercase' : (0, lambda s,x: x.upper()),
|
||||||
'lowercase' : (0, lambda s,x: x.lower()),
|
'lowercase' : (0, lambda s,x: x.lower()),
|
||||||
'titlecase' : (0, lambda s,x: x.title()),
|
'titlecase' : (0, lambda s,x: titlecase(x)),
|
||||||
'capitalize' : (0, lambda s,x: x.capitalize()),
|
'capitalize' : (0, lambda s,x: x.capitalize()),
|
||||||
'contains' : (3, _contains),
|
'contains' : (3, _contains),
|
||||||
'ifempty' : (1, _ifempty),
|
'ifempty' : (1, _ifempty),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user