Fix #7643 ("Copy Structure" command). Add more tweaks to control how the enxt available series number is calculated (#7892). Add a tweak to control layout of custom metadata edit panel (#7920). Allow editing of title sort via the Edit metadata dialog.

This commit is contained in:
Kovid Goyal 2010-12-17 10:15:55 -07:00
commit f414aaf447
12 changed files with 445 additions and 207 deletions

View File

@ -12,13 +12,24 @@ defaults.
# The algorithm used to assign a new book in an existing series a series number.
# New series numbers assigned using this tweak are always integer values, except
# if a constant non-integer is specified.
# Possible values are:
# next - Next available number
# next - First available integer larger than the largest existing number
# first_free - First available integer larger than 0
# next_free - First available integer larger than the smallest existing number
# last_free - First available integer smaller than the largest existing number
# Return largest existing + 1 if no free number is found
# const - Assign the number 1 always
# a number - Assign that number always. The number is not in quotes. Note that
# 0.0 can be used here.
# Examples:
# series_index_auto_increment = 'next'
# series_index_auto_increment = 'next_free'
# series_index_auto_increment = 16.5
series_index_auto_increment = 'next'
# The algorithm used to copy author to author_sort
# Possible values are:
# invert: use "fn ln" -> "ln, fn" (the original algorithm)
@ -235,3 +246,9 @@ doubleclick_on_library_view = 'open_viewer'
# Example: locale_for_sorting = 'fr' -- sort using French rules.
# Example: locale_for_sorting = 'nb' -- sort using Norwegian rules.
locale_for_sorting = ''
# Set whether to use one or two columns for custom metadata when editing
# metadata one book at a time. If True, then the fields are laid out using two
# columns. If False, one column is used.
metadata_single_use_2_cols_for_custom_fields = True

View File

@ -303,7 +303,7 @@ class Series(Base):
if val == '':
val = s_index = None
elif s_index == 0.0:
if tweaks['series_index_auto_increment'] == 'next':
if tweaks['series_index_auto_increment'] != 'const':
s_index = self.db.get_next_cc_series_num_for(val,
num=self.col_id)
else:
@ -572,7 +572,6 @@ class BulkSeries(BulkBase):
val = None if clear else self.normalize_ui_val(val)
if clear or val != '':
extras = []
next_index = self.db.get_next_cc_series_num_for(val, num=self.col_id)
for book_id in book_ids:
if clear:
extras.append(None)
@ -581,9 +580,8 @@ class BulkSeries(BulkBase):
if force_start:
s_index = at_value
at_value += 1
elif tweaks['series_index_auto_increment'] == 'next':
s_index = next_index
next_index += 1
elif tweaks['series_index_auto_increment'] != 'const':
s_index = self.db.get_next_cc_series_num_for(val, num=self.col_id)
else:
s_index = 1.0
else:

View File

@ -32,6 +32,11 @@ class ChooseLibrary(QDialog, Ui_Dialog):
loc = unicode(self.old_location.text()).format(lp)
self.old_location.setText(loc)
self.browse_button.clicked.connect(self.choose_loc)
self.empty_library.toggled.connect(self.empty_library_toggled)
self.copy_structure.setEnabled(False)
def empty_library_toggled(self, to_what):
self.copy_structure.setEnabled(to_what)
def choose_loc(self, *args):
loc = choose_dir(self, 'choose library location',
@ -64,7 +69,7 @@ class ChooseLibrary(QDialog, Ui_Dialog):
def perform_action(self, ac, loc):
if ac in ('new', 'existing'):
prefs['library_path'] = loc
self.callback(loc)
self.callback(loc, copy_structure=self.copy_structure.isChecked())
else:
move_library(self.db.library_path, loc, self.parent(),
self.callback)

View File

@ -49,12 +49,27 @@
</widget>
</item>
<item row="5" column="0" colspan="3">
<layout class="QHBoxLayout" name="hbox1">
<item>
<widget class="QRadioButton" name="empty_library">
<property name="text">
<string>&amp;Create an empty library at the new location</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="copy_structure">
<property name="text">
<string>&amp;Copy structure from the current library</string>
</property>
<property name="toolTip">
<string>Copy the custom columns, saved searches, column widths, plugboards,
user categories, and other information from the old to the new library</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="0" colspan="3">
<widget class="QRadioButton" name="move_library">
<property name="text">

View File

@ -23,7 +23,7 @@ from calibre.gui2.dialogs.tag_editor import TagEditor
from calibre.gui2.widgets import ProgressIndicator
from calibre.ebooks import BOOK_EXTENSIONS
from calibre.ebooks.metadata import string_to_authors, \
authors_to_string, check_isbn
authors_to_string, check_isbn, title_sort
from calibre.ebooks.metadata.covers import download_cover
from calibre.ebooks.metadata.meta import get_metadata
from calibre.ebooks.metadata import MetaInformation
@ -444,13 +444,24 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
self.cover_fetcher = None
self.bc_box.layout().setAlignment(self.cover, Qt.AlignCenter|Qt.AlignHCenter)
base = unicode(self.author_sort.toolTip())
self.ok_aus_tooltip = '<p>' + textwrap.fill(base+'<br><br>'+
ok_tooltip = '<p>' + textwrap.fill(base+'<br><br>'+
_(' The green color indicates that the current '
'author sort matches the current author'))
self.bad_aus_tooltip = '<p>'+textwrap.fill(base + '<br><br>'+
bad_tooltip = '<p>'+textwrap.fill(base + '<br><br>'+
_(' The red color indicates that the current '
'author sort does not match the current author'))
'author sort does not match the current author. '
'No action is required if this is what you want.'))
self.aus_tooltips = (ok_tooltip, bad_tooltip)
base = unicode(self.title_sort.toolTip())
ok_tooltip = '<p>' + textwrap.fill(base+'<br><br>'+
_(' The green color indicates that the current '
'title sort matches the current title'))
bad_tooltip = '<p>'+textwrap.fill(base + '<br><br>'+
_(' The red color warns that the current '
'title sort does not match the current title. '
'No action is required if this is what you want.'))
self.ts_tooltips = (ok_tooltip, bad_tooltip)
self.row_delta = 0
if prev:
self.prev_button = QPushButton(QIcon(I('back.png')), _('Previous'),
@ -506,7 +517,13 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
self.remove_unused_series)
QObject.connect(self.auto_author_sort, SIGNAL('clicked()'),
self.deduce_author_sort)
QObject.connect(self.auto_title_sort, SIGNAL('clicked()'),
self.deduce_title_sort)
self.trim_cover_button.clicked.connect(self.trim_cover)
self.connect(self.title_sort, SIGNAL('textChanged(const QString&)'),
self.title_sort_box_changed)
self.connect(self.title, SIGNAL('textChanged(const QString&)'),
self.title_box_changed)
self.connect(self.author_sort, SIGNAL('textChanged(const QString&)'),
self.author_sort_box_changed)
self.connect(self.authors, SIGNAL('editTextChanged(const QString&)'),
@ -523,6 +540,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
self.title.setText(db.title(row))
self.title_sort.setText(db.title_sort(row))
isbn = db.isbn(self.id, index_is_id=True)
if not isbn:
isbn = ''
@ -598,8 +616,8 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
w = self.central_widget.widget(1)
layout = w.layout()
self.custom_column_widgets, self.__cc_spacers = \
populate_metadata_page(layout, self.db, self.id,
parent=w, bulk=False, two_column=True)
populate_metadata_page(layout, self.db, self.id, parent=w, bulk=False,
two_column=tweaks['metadata_single_use_2_cols_for_custom_fields'])
self.__custom_col_layouts = [layout]
ans = self.custom_column_widgets
for i in range(len(ans)-1):
@ -610,27 +628,40 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
for c in range(2, len(ans[i].widgets), 2):
w.setTabOrder(ans[i].widgets[c-1], ans[i].widgets[c+1])
def title_box_changed(self, txt):
ts = unicode(txt)
ts = title_sort(ts)
self.mark_box_as_ok(control = self.title_sort, tt=self.ts_tooltips,
normal=(unicode(self.title_sort.text()) == ts))
def title_sort_box_changed(self, txt):
ts = unicode(txt)
self.mark_box_as_ok(control = self.title_sort, tt=self.ts_tooltips,
normal=(title_sort(unicode(self.title.text())) == ts))
def authors_box_changed(self, txt):
aus = unicode(txt)
aus = re.sub(r'\s+et al\.$', '', aus)
aus = self.db.author_sort_from_authors(string_to_authors(aus))
self.mark_author_sort(normal=(unicode(self.author_sort.text()) == aus))
self.mark_box_as_ok(control = self.author_sort, tt=self.aus_tooltips,
normal=(unicode(self.author_sort.text()) == aus))
def author_sort_box_changed(self, txt):
au = unicode(self.authors.text())
au = re.sub(r'\s+et al\.$', '', au)
au = self.db.author_sort_from_authors(string_to_authors(au))
self.mark_author_sort(normal=(au == txt))
self.mark_box_as_ok(control = self.author_sort, tt=self.aus_tooltips,
normal=(au == txt))
def mark_author_sort(self, normal=True):
def mark_box_as_ok(self, control, tt, normal=True):
if normal:
col = 'rgb(0, 255, 0, 20%)'
else:
col = 'rgb(255, 0, 0, 20%)'
self.author_sort.setStyleSheet('QLineEdit { color: black; '
control.setStyleSheet('QLineEdit { color: black; '
'background-color: %s; }'%col)
tt = self.ok_aus_tooltip if normal else self.bad_aus_tooltip
self.author_sort.setToolTip(tt)
tt = tt[0] if normal else tt[1]
control.setToolTip(tt)
def validate_isbn(self, isbn):
isbn = unicode(isbn).strip()
@ -652,12 +683,16 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
authors = string_to_authors(au)
self.author_sort.setText(self.db.author_sort_from_authors(authors))
def deduce_title_sort(self):
ts = unicode(self.title.text())
self.title_sort.setText(title_sort(ts))
def swap_title_author(self):
title = self.title.text()
self.title.setText(self.authors.text())
self.authors.setText(title)
self.author_sort.setText('')
self.deduce_author_sort()
self.deduce_title_sort()
def initialize_combos(self):
self.initalize_authors()
@ -804,7 +839,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
series = unicode(self.series.text()).strip()
if series and series != self.original_series_name:
ns = 1
if tweaks['series_index_auto_increment'] == 'next':
if tweaks['series_index_auto_increment'] != 'const':
ns = self.db.get_next_series_num_for(series)
self.series_index.setValue(ns)
self.original_series_name = series
@ -838,6 +873,10 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
title = unicode(self.title.text()).strip()
if title != self.original_title:
self.db.set_title(self.id, title, notify=False)
# This must be after setting the title because of the DB update trigger
ts = unicode(self.title_sort.text()).strip()
if ts:
self.db.set_title_sort(self.id, ts, notify=False, commit=False)
au = unicode(self.authors.text()).strip()
if au and au != self.original_author:
self.db.set_authors(self.id, string_to_authors(au), notify=False)

View File

@ -100,27 +100,27 @@
</property>
</widget>
</item>
<item row="0" column="2" rowspan="2">
<widget class="QToolButton" name="swap_button">
<property name="toolTip">
<string>Swap the author and title</string>
</property>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>...</string>
<string>Title &amp;sort: </string>
</property>
<property name="icon">
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/swap.png</normaloff>:/images/swap.png</iconset>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
<property name="buddy">
<cstring>title_sort</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
<item row="1" column="1">
<widget class="EnLineEdit" name="title_sort">
<property name="toolTip">
<string>Specify how this book should be sorted when by title. For example, The Exorcist might be sorted as Exorcist, The.</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>&amp;Author(s): </string>
@ -133,7 +133,14 @@
</property>
</widget>
</item>
<item row="2" column="0">
<item row="2" column="1">
<widget class="EnComboBox" name="authors">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Author S&amp;ort: </string>
@ -146,9 +153,7 @@
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<item row="3" column="1">
<widget class="EnLineEdit" name="author_sort">
<property name="toolTip">
<string>Specify how the author(s) of this book should be sorted. For example Charles Dickens should be sorted as Dickens, Charles.
@ -156,24 +161,7 @@ If the box is colored green, then text matches the individual author's sort stri
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="auto_author_sort">
<property name="toolTip">
<string>Automatically create the author sort entry based on the current author entry.
Using this button to create author sort will change author sort from red to green.</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/auto_author_sort.png</normaloff>:/images/auto_author_sort.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0">
<item row="4" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>&amp;Rating:</string>
@ -186,7 +174,7 @@ Using this button to create author sort will change author sort from red to gree
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<item row="4" column="1" colspan="2">
<widget class="QSpinBox" name="rating">
<property name="toolTip">
<string>Rating of this book. 0-5 stars</string>
@ -205,7 +193,7 @@ Using this button to create author sort will change author sort from red to gree
</property>
</widget>
</item>
<item row="4" column="0">
<item row="5" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>&amp;Publisher: </string>
@ -218,7 +206,14 @@ Using this button to create author sort will change author sort from red to gree
</property>
</widget>
</item>
<item row="5" column="0">
<item row="5" column="1" colspan="2">
<widget class="EnComboBox" name="publisher">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Ta&amp;gs: </string>
@ -231,32 +226,7 @@ Using this button to create author sort will change author sort from red to gree
</property>
</widget>
</item>
<item row="5" column="1" colspan="2">
<layout class="QHBoxLayout" name="_2">
<item>
<widget class="TagsLineEdit" name="tags">
<property name="toolTip">
<string>Tags categorize the book. This is particularly useful while searching. &lt;br&gt;&lt;br&gt;They can be any words or phrases, separated by commas.</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="tag_editor_button">
<property name="toolTip">
<string>Open Tag Editor</string>
</property>
<property name="text">
<string>Open Tag Editor</string>
</property>
<property name="icon">
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/chapters.png</normaloff>:/images/chapters.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="0">
<item row="7" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>&amp;Series:</string>
@ -272,7 +242,7 @@ Using this button to create author sort will change author sort from red to gree
</property>
</widget>
</item>
<item row="6" column="1" colspan="2">
<item row="7" column="1">
<layout class="QHBoxLayout" name="_3">
<property name="spacing">
<number>5</number>
@ -293,7 +263,215 @@ Using this button to create author sort will change author sort from red to gree
</property>
</widget>
</item>
</layout>
</item>
<item row="8" column="1" colspan="2">
<widget class="QDoubleSpinBox" name="series_index">
<property name="enabled">
<bool>false</bool>
</property>
<property name="prefix">
<string>Book </string>
</property>
<property name="maximum">
<double>9999.989999999999782</double>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>IS&amp;BN:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>isbn</cstring>
</property>
</widget>
</item>
<item row="9" column="1" colspan="2">
<widget class="QLineEdit" name="isbn"/>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>&amp;Date:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>date</cstring>
</property>
</widget>
</item>
<item row="10" column="1" colspan="2">
<widget class="QDateEdit" name="date">
<property name="displayFormat">
<string>dd MMM yyyy</string>
</property>
<property name="calendarPopup">
<bool>true</bool>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Publishe&amp;d:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>pubdate</cstring>
</property>
</widget>
</item>
<item row="11" column="1" colspan="2">
<widget class="QDateEdit" name="pubdate">
<property name="displayFormat">
<string>MMM yyyy</string>
</property>
<property name="calendarPopup">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="2" rowspan="4">
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="auto_title_sort">
<property name="toolTip">
<string>Automatically create the author sort entry based on the current author entry.
Using this button to create author sort will change author sort from red to green.</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/auto_author_sort.png</normaloff>:/images/auto_author_sort.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="swap_button">
<property name="toolTip">
<string>Swap the author and title</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/swap.png</normaloff>:/images/swap.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="auto_author_sort">
<property name="toolTip">
<string>Automatically create the title sort entry based on the current title entry.
Using this button to create title sort will change title sort from red to green.</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/auto_author_sort.png</normaloff>:/images/auto_author_sort.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="6" column="1">
<layout class="QHBoxLayout" name="_2">
<item>
<widget class="TagsLineEdit" name="tags">
<property name="toolTip">
<string>Tags categorize the book. This is particularly useful while searching. &lt;br&gt;&lt;br&gt;They can be any words or phrases, separated by commas.</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="2">
<widget class="QToolButton" name="tag_editor_button">
<property name="toolTip">
<string>Open Tag Editor</string>
</property>
<property name="text">
<string>Open Tag Editor</string>
</property>
<property name="icon">
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/chapters.png</normaloff>:/images/chapters.png</iconset>
</property>
</widget>
</item>
<item row="7" column="2">
<widget class="QToolButton" name="remove_series_button">
<property name="toolTip">
<string>Remove unused series (Series that have no books)</string>
@ -308,97 +486,13 @@ Using this button to create author sort will change author sort from red to gree
</widget>
</item>
</layout>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_9">
<item>
<widget class="QPushButton" name="fetch_metadata_button">
<property name="text">
<string>IS&amp;BN:</string>
<string>&amp;Fetch metadata from server</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>isbn</cstring>
</property>
</widget>
</item>
<item row="8" column="1" colspan="2">
<widget class="QLineEdit" name="isbn"/>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Publishe&amp;d:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>pubdate</cstring>
</property>
</widget>
</item>
<item row="4" column="1" colspan="2">
<widget class="EnComboBox" name="publisher">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="7" column="1" colspan="2">
<widget class="QDoubleSpinBox" name="series_index">
<property name="enabled">
<bool>false</bool>
</property>
<property name="prefix">
<string>Book </string>
</property>
<property name="maximum">
<double>9999.989999999999782</double>
</property>
</widget>
</item>
<item row="10" column="1" colspan="2">
<widget class="QDateEdit" name="pubdate">
<property name="displayFormat">
<string>MMM yyyy</string>
</property>
<property name="calendarPopup">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="EnComboBox" name="authors">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="9" column="1" colspan="2">
<widget class="QDateEdit" name="date">
<property name="displayFormat">
<string>dd MMM yyyy</string>
</property>
<property name="calendarPopup">
<bool>true</bool>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>&amp;Date:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>date</cstring>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
@ -420,13 +514,6 @@ Using this button to create author sort will change author sort from red to gree
</layout>
</widget>
</item>
<item>
<widget class="QPushButton" name="fetch_metadata_button">
<property name="text">
<string>&amp;Fetch metadata from server</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="layoutWidget_2">
@ -744,10 +831,12 @@ Using this button to create author sort will change author sort from red to gree
</customwidgets>
<tabstops>
<tabstop>title</tabstop>
<tabstop>auto_title_sort</tabstop>
<tabstop>title_sort</tabstop>
<tabstop>swap_button</tabstop>
<tabstop>authors</tabstop>
<tabstop>author_sort</tabstop>
<tabstop>auto_author_sort</tabstop>
<tabstop>author_sort</tabstop>
<tabstop>rating</tabstop>
<tabstop>publisher</tabstop>
<tabstop>tags</tabstop>
@ -758,20 +847,22 @@ Using this button to create author sort will change author sort from red to gree
<tabstop>isbn</tabstop>
<tabstop>date</tabstop>
<tabstop>pubdate</tabstop>
<tabstop>comments</tabstop>
<tabstop>fetch_metadata_button</tabstop>
<tabstop>add_format_button</tabstop>
<tabstop>remove_format_button</tabstop>
<tabstop>comments</tabstop>
<tabstop>button_set_cover</tabstop>
<tabstop>button_set_metadata</tabstop>
<tabstop>formats</tabstop>
<tabstop>add_format_button</tabstop>
<tabstop>remove_format_button</tabstop>
<tabstop>cover_path</tabstop>
<tabstop>cover_button</tabstop>
<tabstop>trim_cover_button</tabstop>
<tabstop>reset_cover</tabstop>
<tabstop>fetch_cover_button</tabstop>
<tabstop>generate_cover_button</tabstop>
<tabstop>button_box</tabstop>
<tabstop>scrollArea</tabstop>
<tabstop>central_widget</tabstop>
<tabstop>button_box</tabstop>
</tabstops>
<resources>
<include location="../../../../resources/images.qrc"/>

View File

@ -772,7 +772,7 @@ class BooksModel(QAbstractTableModel): # {{{
self.db.set_series_index(id, float(match.group(1)))
val = pat.sub('', val).strip()
elif val:
if tweaks['series_index_auto_increment'] == 'next':
if tweaks['series_index_auto_increment'] != 'const':
ni = self.db.get_next_series_num_for(val)
if ni != 1:
self.db.set_series_index(id, ni)

View File

@ -378,13 +378,16 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
def booklists(self):
return self.memory_view.model().db, self.card_a_view.model().db, self.card_b_view.model().db
def library_moved(self, newloc):
def library_moved(self, newloc, copy_structure=False):
if newloc is None: return
default_prefs = None
try:
olddb = self.library_view.model().db
if copy_structure:
default_prefs = olddb.prefs
except:
olddb = None
db = LibraryDatabase2(newloc)
db = LibraryDatabase2(newloc, default_prefs=default_prefs)
if self.content_server is not None:
self.content_server.set_database(db)
self.library_path = newloc

View File

@ -707,7 +707,7 @@ def parse_series_string(db, label, value):
val = pat.sub('', val).strip()
s_index = float(match.group(1))
elif val:
if tweaks['series_index_auto_increment'] == 'next':
if tweaks['series_index_auto_increment'] != 'const':
s_index = db.get_next_cc_series_num_for(val, label=label)
else:
s_index = 1.0

View File

@ -8,12 +8,12 @@ __docformat__ = 'restructuredtext en'
import json, re
from functools import partial
from math import floor
from calibre import prints
from calibre.constants import preferred_encoding
from calibre.library.field_metadata import FieldMetadata
from calibre.utils.date import parse_date
from calibre.utils.config import tweaks
class CustomColumns(object):
@ -261,15 +261,15 @@ class CustomColumns(object):
series_id = self.conn.get('SELECT id from %s WHERE value=?'%table,
(series,), all=False)
if series_id is None:
if isinstance(tweaks['series_index_auto_increment'], (int, float)):
return float(tweaks['series_index_auto_increment'])
return 1.0
# get the label of the associated series number table
series_num = self.conn.get('''
SELECT MAX({lt}.extra) FROM {lt}
series_indices = self.conn.get('''
SELECT {lt}.extra FROM {lt}
WHERE {lt}.book IN (SELECT book FROM {lt} where value=?)
'''.format(lt=lt), (series_id,), all=False)
if series_num is None:
return 1.0
return floor(series_num+1)
ORDER BY {lt}.extra
'''.format(lt=lt), (series_id,))
return self._get_next_series_num_for_list(series_indices)
def all_custom(self, label=None, num=None):
if label is not None:

View File

@ -8,7 +8,7 @@ The database used to store ebook metadata
'''
import os, sys, shutil, cStringIO, glob, time, functools, traceback, re
from itertools import repeat
from math import floor
from math import ceil
from Queue import Queue
from PyQt4.QtGui import QImage
@ -113,7 +113,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
def exists_at(cls, path):
return path and os.path.exists(os.path.join(path, 'metadata.db'))
def __init__(self, library_path, row_factory=False):
def __init__(self, library_path, row_factory=False, default_prefs=None):
self.field_metadata = FieldMetadata()
self.dirtied_queue = Queue()
if not os.path.exists(library_path):
@ -127,10 +127,29 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if isinstance(self.dbpath, unicode) and not iswindows:
self.dbpath = self.dbpath.encode(filesystem_encoding)
apply_default_prefs = not os.path.exists(self.dbpath)
self.connect()
self.is_case_sensitive = not iswindows and not isosx and \
not os.path.exists(self.dbpath.replace('metadata.db', 'MeTAdAtA.dB'))
SchemaUpgrade.__init__(self)
# if we are to copy the prefs and structure from some other DB, then
# we need to do it before we call initialize_dynamic
if apply_default_prefs and default_prefs is not None:
dbprefs = DBPrefs(self)
for key in default_prefs:
# be sure that prefs not to be copied are listed below
if key in ['news_to_be_synced']:
continue
try:
dbprefs[key] = default_prefs[key]
except:
pass # ignore options that don't exist anymore
fmvals = [f for f in default_prefs['field_metadata'].values() if f['is_custom']]
for f in fmvals:
self.create_custom_column(f['label'], f['name'], f['datatype'],
f['is_multiple'] is not None, f['is_editable'], f['display'])
self.initialize_dynamic()
def get_property(self, idx, index_is_id=False, loc=-1):
@ -1365,14 +1384,42 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
series_id = self.conn.get('SELECT id from series WHERE name=?',
(series,), all=False)
if series_id is None:
if isinstance(tweaks['series_index_auto_increment'], (int, float)):
return float(tweaks['series_index_auto_increment'])
return 1.0
series_num = self.conn.get(
('SELECT MAX(series_index) FROM books WHERE id IN '
'(SELECT book FROM books_series_link where series=?)'),
(series_id,), all=False)
if series_num is None:
series_indices = self.conn.get(
('SELECT series_index FROM books WHERE id IN '
'(SELECT book FROM books_series_link where series=?) '
'ORDER BY series_index'),
(series_id,))
return self._get_next_series_num_for_list(series_indices)
def _get_next_series_num_for_list(self, series_indices):
if not series_indices:
if isinstance(tweaks['series_index_auto_increment'], (int, float)):
return float(tweaks['series_index_auto_increment'])
return 1.0
series_indices = [x[0] for x in series_indices]
if tweaks['series_index_auto_increment'] == 'next':
return series_indices[-1] + 1
if tweaks['series_index_auto_increment'] == 'first_free':
for i in range(1, 10000):
if i not in series_indices:
return i
# really shouldn't get here.
if tweaks['series_index_auto_increment'] == 'next_free':
for i in range(int(ceil(series_indices[0])), 10000):
if i not in series_indices:
return i
# really shouldn't get here.
if tweaks['series_index_auto_increment'] == 'last_free':
for i in range(int(ceil(series_indices[-1])), 0, -1):
if i not in series_indices:
return i
return series_indices[-1] + 1
if isinstance(tweaks['series_index_auto_increment'], (int, float)):
return float(tweaks['series_index_auto_increment'])
return 1.0
return floor(series_num+1)
def set(self, row, column, val):
'''
@ -1565,6 +1612,20 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if notify:
self.notify('metadata', [id])
def set_title_sort(self, id, title_sort_, notify=True, commit=True):
if not title_sort_:
return False
if isbytestring(title_sort_):
title_sort_ = title_sort_.decode(preferred_encoding, 'replace')
self.conn.execute('UPDATE books SET sort=? WHERE id=?', (title_sort_, id))
self.data.set(id, self.FIELD_MAP['sort'], title_sort_, row_is_id=True)
self.dirtied([id], commit=False)
if commit:
self.conn.commit()
if notify:
self.notify('metadata', [id])
return True
def _set_title(self, id, title):
if not title:
return False
@ -1746,18 +1807,17 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
FROM books, books_series_link as lt
WHERE books.id = lt.book AND lt.series=?
ORDER BY books.series_index''', (old_id,))
# Get the next series index
index = self.get_next_series_num_for(new_name)
# Now update the link table
self.conn.execute('''UPDATE books_series_link
SET series=?
WHERE series=?''',(new_id, old_id,))
# Now set the indices
for (book_id,) in books:
# Get the next series index
index = self.get_next_series_num_for(new_name)
self.conn.execute('''UPDATE books
SET series_index=?
WHERE id=?''',(index, book_id,))
index = index + 1
self.dirty_books_referencing('series', new_id, commit=False)
self.conn.commit()

View File

@ -429,3 +429,13 @@ class SchemaUpgrade(object):
'Remove commas from tags'
self.conn.execute("UPDATE tags SET name=REPLACE(name, ',', ';')")
def upgrade_version_16(self):
self.conn.executescript('''
DROP TRIGGER IF EXISTS books_update_trg;
CREATE TRIGGER books_update_trg
AFTER UPDATE ON books
BEGIN
UPDATE books SET sort=title_sort(NEW.title)
WHERE id=NEW.id AND OLD.title <> NEW.title;
END;
''')