mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge from trunk
This commit is contained in:
commit
38b418de1b
@ -2,24 +2,23 @@
|
||||
__license__ = 'GPL v3'
|
||||
__author__ = 'Luis Hernandez'
|
||||
__copyright__ = 'Luis Hernandez<tolyluis@gmail.com>'
|
||||
description = 'Diario local de Talavera de la Reina - v1.2 - 27 Jan 2011'
|
||||
__version__ = 'v1.0'
|
||||
__date__ = '01 Feb 2011'
|
||||
|
||||
'''
|
||||
http://www.latribunadetalavera.es/
|
||||
http://www.promecal.es/
|
||||
'''
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class AdvancedUserRecipe1294946868(BasicNewsRecipe):
|
||||
|
||||
title = u'La Tribuna de Talavera'
|
||||
title = u'La Tribuna de'
|
||||
publisher = u'Grupo PROMECAL'
|
||||
|
||||
__author__ = 'Luis Hernández'
|
||||
description = 'Diario local de Talavera de la Reina'
|
||||
cover_url = 'http://www.latribunadetalavera.es/entorno/mancheta.gif'
|
||||
description = 'Varios diarios locales del grupo PROMECAL'
|
||||
|
||||
oldest_article = 5
|
||||
oldest_article = 3
|
||||
max_articles_per_feed = 50
|
||||
|
||||
remove_javascript = True
|
||||
@ -27,7 +26,7 @@ class AdvancedUserRecipe1294946868(BasicNewsRecipe):
|
||||
use_embedded_content = False
|
||||
|
||||
encoding = 'utf-8'
|
||||
language = 'es'
|
||||
language = 'es_ES'
|
||||
timefmt = '[%a, %d %b, %Y]'
|
||||
|
||||
keep_only_tags = [
|
||||
@ -39,7 +38,20 @@ class AdvancedUserRecipe1294946868(BasicNewsRecipe):
|
||||
remove_tags_before = dict(name='div' , attrs={'class':['comparte']})
|
||||
remove_tags_after = dict(name='div' , attrs={'id':['relacionadas']})
|
||||
|
||||
extra_css = ' p{text-align: justify; font-size: 100%} body{ text-align: left; font-family: serif; font-size: 100% } h1{ font-family: sans-serif; font-size:150%; font-weight: 700; text-align: justify; } h2{ font-family: sans-serif; font-size:120%; font-weight: 600; text-align: justify } h3{ font-family: sans-serif; font-size:60%; font-weight: 600; text-align: left } h4{ font-family: sans-serif; font-size:80%; font-weight: 600; text-align: left } h5{ font-family: sans-serif; font-size:70%; font-weight: 600; text-align: left }img{margin-bottom: 0.4em} '
|
||||
remove_tags = [
|
||||
dict(name='div', attrs={'id':['relacionadas']})
|
||||
,dict(name='h3')
|
||||
,dict(name='h5')
|
||||
]
|
||||
|
||||
extra_css = """
|
||||
p{text-align: justify; font-size: 100%}
|
||||
body{text-align: left; font-family: serif; font-size: 100%}
|
||||
h1{font-family: sans; font-size:150%; font-weight: bold; text-align: justify;}
|
||||
h2{font-family: sans-serif; font-size:85%; font-style: italic; text-align: justify;}
|
||||
h4{font-family: sans; font-size:75%; font-weight: bold; text-align: center;}
|
||||
img{margin-bottom: 0.4em}
|
||||
"""
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for alink in soup.findAll('a'):
|
||||
@ -48,4 +60,15 @@ class AdvancedUserRecipe1294946868(BasicNewsRecipe):
|
||||
alink.replaceWith(tstr)
|
||||
return soup
|
||||
|
||||
feeds = [(u'Portada', u'http://www.latribunadetalavera.es/rss.html')]
|
||||
|
||||
feeds = [
|
||||
(u'Albacete', u'http://www.latribunadealbacete.es/rss.html')
|
||||
,(u'Avila', u'http://www.diariodeavila.es/rss.html')
|
||||
,(u'Burgos', u'http://www.diariodeburgos.es/rss.html')
|
||||
,(u'Ciudad Real', u'http://www.latribunadeciudadreal.es/rss.html')
|
||||
,(u'Palencia', u'http://www.diariopalentino.es/rss.html')
|
||||
,(u'Puertollano', u'http://www.latribunadepuertollano.es/rss.html')
|
||||
,(u'Talavera de la Reina', u'http://www.latribunadetalavera.es/rss.html')
|
||||
,(u'Toledo', u'http://www.latribunadetoledo.es/rss.html')
|
||||
,(u'Valladolid', u'http://www.eldiadevalladolid.com/rss.html')
|
||||
]
|
||||
|
@ -160,7 +160,7 @@ class EditMetadataAction(InterfaceAction):
|
||||
break
|
||||
|
||||
changed.add(d.id)
|
||||
changed |= d.books_to_refresh
|
||||
self.gui.library_view.model().refresh_ids(list(d.books_to_refresh))
|
||||
if d.row_delta == 0:
|
||||
break
|
||||
current_row += d.row_delta
|
||||
|
@ -64,8 +64,6 @@ class CompleteWindow(QListView): # {{{
|
||||
|
||||
def do_selected(self, idx=None):
|
||||
idx = self.currentIndex() if idx is None else idx
|
||||
#if not idx.isValid() and self.model().rowCount() > 0:
|
||||
# idx = self.model().index(0)
|
||||
if idx.isValid():
|
||||
data = unicode(self.model().data(idx, Qt.DisplayRole))
|
||||
self.completion_selected.emit(data)
|
||||
@ -81,6 +79,9 @@ class CompleteWindow(QListView): # {{{
|
||||
self.hide()
|
||||
return True
|
||||
elif key in (Qt.Key_Enter, Qt.Key_Return, Qt.Key_Tab):
|
||||
if key == Qt.Key_Tab and not self.currentIndex().isValid():
|
||||
if self.model().rowCount() > 0:
|
||||
self.setCurrentIndex(self.model().index(0))
|
||||
self.do_selected()
|
||||
return True
|
||||
elif key in (Qt.Key_Up, Qt.Key_Down, Qt.Key_PageUp,
|
||||
@ -197,6 +198,9 @@ class MultiCompleteLineEdit(QLineEdit):
|
||||
return True # Filter this event since the cw is visible
|
||||
return QLineEdit.eventFilter(self, o, e)
|
||||
|
||||
def hide_completion_window(self):
|
||||
self.complete_window.hide()
|
||||
|
||||
|
||||
def text_edited(self, *args):
|
||||
self.update_completions()
|
||||
|
@ -70,9 +70,6 @@ class MetadataWidget(Widget, Ui_Form):
|
||||
def initialize_metadata_options(self):
|
||||
self.initialize_combos()
|
||||
self.author.editTextChanged.connect(self.deduce_author_sort)
|
||||
self.author.set_separator('&')
|
||||
self.author.set_space_before_sep(True)
|
||||
self.author.update_items_cache(self.db.all_author_names())
|
||||
|
||||
mi = self.db.get_metadata(self.book_id, index_is_id=True)
|
||||
self.title.setText(mi.title)
|
||||
@ -109,6 +106,9 @@ class MetadataWidget(Widget, Ui_Form):
|
||||
def initalize_authors(self):
|
||||
all_authors = self.db.all_authors()
|
||||
all_authors.sort(key=lambda x : sort_key(x[1]))
|
||||
self.author.set_separator('&')
|
||||
self.author.set_space_before_sep(True)
|
||||
self.author.update_items_cache(self.db.all_author_names())
|
||||
|
||||
for i in all_authors:
|
||||
id, name = i
|
||||
@ -124,6 +124,8 @@ class MetadataWidget(Widget, Ui_Form):
|
||||
def initialize_series(self):
|
||||
all_series = self.db.all_series()
|
||||
all_series.sort(key=lambda x : sort_key(x[1]))
|
||||
self.series.set_separator(None)
|
||||
self.series.update_items_cache([x[1] for x in all_series])
|
||||
|
||||
for i in all_series:
|
||||
id, name = i
|
||||
@ -133,6 +135,8 @@ class MetadataWidget(Widget, Ui_Form):
|
||||
def initialize_publisher(self):
|
||||
all_publishers = self.db.all_publishers()
|
||||
all_publishers.sort(key=lambda x : sort_key(x[1]))
|
||||
self.publisher.set_separator(None)
|
||||
self.publisher.update_items_cache([x[1] for x in all_publishers])
|
||||
|
||||
for i in all_publishers:
|
||||
id, name = i
|
||||
|
@ -190,7 +190,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="CompleteLineEdit" name="tags">
|
||||
<widget class="MultiCompleteLineEdit" name="tags">
|
||||
<property name="toolTip">
|
||||
<string>Tags categorize the book. This is particularly useful while searching. <br><br>They can be any words or phrases, separated by commas.</string>
|
||||
</property>
|
||||
@ -213,7 +213,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="EnComboBox" name="series">
|
||||
<widget class="MultiCompleteComboBox" name="series">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>10</horstretch>
|
||||
@ -248,14 +248,14 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="EnComboBox" name="publisher">
|
||||
<widget class="MultiCompleteComboBox" name="publisher">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="CompleteComboBox" name="author">
|
||||
<widget class="MultiCompleteComboBox" name="author">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
@ -277,19 +277,14 @@
|
||||
<header>widgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>EnComboBox</class>
|
||||
<class>MultiCompleteComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>widgets.h</header>
|
||||
<header>calibre/gui2/complete.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>CompleteComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>widgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>CompleteLineEdit</class>
|
||||
<class>MultiCompleteLineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>widgets.h</header>
|
||||
<header>calibre/gui2/complete.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ImageView</class>
|
||||
|
@ -14,7 +14,7 @@ from PyQt4.Qt import QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateEdit, \
|
||||
QPushButton
|
||||
|
||||
from calibre.utils.date import qt_to_dt, now
|
||||
from calibre.gui2.widgets import CompleteLineEdit, EnComboBox
|
||||
from calibre.gui2.complete import MultiCompleteLineEdit, MultiCompleteComboBox
|
||||
from calibre.gui2.comments_editor import Editor as CommentsEditor
|
||||
from calibre.gui2 import UNDEFINED_QDATE, error_dialog
|
||||
from calibre.utils.config import tweaks
|
||||
@ -228,10 +228,12 @@ class Text(Base):
|
||||
values = self.all_values = list(self.db.all_custom(num=self.col_id))
|
||||
values.sort(key=sort_key)
|
||||
if self.col_metadata['is_multiple']:
|
||||
w = CompleteLineEdit(parent, values)
|
||||
w = MultiCompleteLineEdit(parent)
|
||||
w.update_items_cache(values)
|
||||
w.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
|
||||
else:
|
||||
w = EnComboBox(parent)
|
||||
w = MultiCompleteComboBox(parent)
|
||||
w.set_separator(None)
|
||||
w.setSizeAdjustPolicy(w.AdjustToMinimumContentsLengthWithIcon)
|
||||
w.setMinimumContentsLength(25)
|
||||
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent), w]
|
||||
@ -240,9 +242,10 @@ class Text(Base):
|
||||
val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True)
|
||||
self.initial_val = val
|
||||
val = self.normalize_db_val(val)
|
||||
self.widgets[1].update_items_cache(self.all_values)
|
||||
|
||||
if self.col_metadata['is_multiple']:
|
||||
self.setter(val)
|
||||
self.widgets[1].update_items_cache(self.all_values)
|
||||
else:
|
||||
idx = None
|
||||
for i, c in enumerate(self.all_values):
|
||||
@ -276,7 +279,7 @@ class Series(Base):
|
||||
def setup_ui(self, parent):
|
||||
values = self.all_values = list(self.db.all_custom(num=self.col_id))
|
||||
values.sort(key=sort_key)
|
||||
w = EnComboBox(parent)
|
||||
w = MultiCompleteComboBox(parent)
|
||||
w.setSizeAdjustPolicy(w.AdjustToMinimumContentsLengthWithIcon)
|
||||
w.setMinimumContentsLength(25)
|
||||
self.name_widget = w
|
||||
@ -305,6 +308,7 @@ class Series(Base):
|
||||
if c == val:
|
||||
idx = i
|
||||
self.name_widget.addItem(c)
|
||||
self.name_widget.update_items_cache(self.all_values)
|
||||
self.name_widget.setEditText('')
|
||||
if idx is not None:
|
||||
self.widgets[1].setCurrentIndex(idx)
|
||||
@ -670,7 +674,7 @@ class BulkDateTime(BulkBase):
|
||||
class BulkSeries(BulkBase):
|
||||
|
||||
def setup_ui(self, parent):
|
||||
self.make_widgets(parent, EnComboBox)
|
||||
self.make_widgets(parent, MultiCompleteComboBox)
|
||||
values = self.all_values = list(self.db.all_custom(num=self.col_id))
|
||||
values.sort(key=sort_key)
|
||||
self.main_widget.setSizeAdjustPolicy(self.main_widget.AdjustToMinimumContentsLengthWithIcon)
|
||||
@ -705,6 +709,8 @@ class BulkSeries(BulkBase):
|
||||
|
||||
def initialize(self, book_id):
|
||||
self.idx_widget.setChecked(False)
|
||||
self.main_widget.set_separator(None)
|
||||
self.main_widget.update_items_cache(self.all_values)
|
||||
for c in self.all_values:
|
||||
self.main_widget.addItem(c)
|
||||
self.main_widget.setEditText('')
|
||||
@ -795,7 +801,8 @@ class RemoveTags(QWidget):
|
||||
layout.setSpacing(5)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
self.tags_box = CompleteLineEdit(parent, values)
|
||||
self.tags_box = MultiCompleteLineEdit(parent)
|
||||
self.tags_box.update_items_cache(values)
|
||||
layout.addWidget(self.tags_box, stretch=3)
|
||||
self.checkbox = QCheckBox(_('Remove all tags'), parent)
|
||||
layout.addWidget(self.checkbox)
|
||||
@ -816,7 +823,7 @@ class BulkText(BulkBase):
|
||||
values = self.all_values = list(self.db.all_custom(num=self.col_id))
|
||||
values.sort(key=sort_key)
|
||||
if self.col_metadata['is_multiple']:
|
||||
self.make_widgets(parent, CompleteLineEdit,
|
||||
self.make_widgets(parent, MultiCompleteLineEdit,
|
||||
extra_label_text=_('tags to add'))
|
||||
self.main_widget.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
|
||||
self.adding_widget = self.main_widget
|
||||
@ -829,16 +836,16 @@ class BulkText(BulkBase):
|
||||
w.tags_box.textChanged.connect(self.a_c_checkbox_changed)
|
||||
w.checkbox.stateChanged.connect(self.a_c_checkbox_changed)
|
||||
else:
|
||||
self.make_widgets(parent, EnComboBox)
|
||||
self.make_widgets(parent, MultiCompleteComboBox)
|
||||
self.main_widget.set_separator(None)
|
||||
self.main_widget.setSizeAdjustPolicy(
|
||||
self.main_widget.AdjustToMinimumContentsLengthWithIcon)
|
||||
self.main_widget.setMinimumContentsLength(25)
|
||||
self.ignore_change_signals = False
|
||||
|
||||
def initialize(self, book_ids):
|
||||
if self.col_metadata['is_multiple']:
|
||||
self.main_widget.update_items_cache(self.all_values)
|
||||
else:
|
||||
self.main_widget.update_items_cache(self.all_values)
|
||||
if not self.col_metadata['is_multiple']:
|
||||
val = self.get_initial_value(book_ids)
|
||||
self.initial_val = val = self.normalize_db_val(val)
|
||||
idx = None
|
||||
|
@ -7,8 +7,8 @@ __license__ = 'GPL v3'
|
||||
from PyQt4.Qt import QDialog, QGridLayout, QLabel, QDialogButtonBox, \
|
||||
QApplication, QSpinBox, QToolButton, QIcon
|
||||
from calibre.ebooks.metadata import authors_to_string, string_to_authors
|
||||
from calibre.gui2.widgets import CompleteComboBox
|
||||
from calibre.utils.icu import sort_key
|
||||
from calibre.gui2.complete import MultiCompleteComboBox
|
||||
|
||||
class AddEmptyBookDialog(QDialog):
|
||||
|
||||
@ -32,7 +32,7 @@ class AddEmptyBookDialog(QDialog):
|
||||
self.author_label = QLabel(_('Set the author of the new books to:'))
|
||||
self._layout.addWidget(self.author_label, 2, 0, 1, 2)
|
||||
|
||||
self.authors_combo = CompleteComboBox(self)
|
||||
self.authors_combo = MultiCompleteComboBox(self)
|
||||
self.authors_combo.setSizeAdjustPolicy(
|
||||
self.authors_combo.AdjustToMinimumContentsLengthWithIcon)
|
||||
self.authors_combo.setEditable(True)
|
||||
|
@ -764,6 +764,8 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog):
|
||||
def initialize_series(self):
|
||||
all_series = self.db.all_series()
|
||||
all_series.sort(key=lambda x : sort_key(x[1]))
|
||||
self.series.set_separator(None)
|
||||
self.series.update_items_cache([x[1] for x in all_series])
|
||||
|
||||
for i in all_series:
|
||||
id, name = i
|
||||
@ -773,6 +775,8 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog):
|
||||
def initialize_publisher(self):
|
||||
all_publishers = self.db.all_publishers()
|
||||
all_publishers.sort(key=lambda x : sort_key(x[1]))
|
||||
self.publisher.set_separator(None)
|
||||
self.publisher.update_items_cache([x[1] for x in all_publishers])
|
||||
|
||||
for i in all_publishers:
|
||||
id, name = i
|
||||
|
@ -76,7 +76,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="CompleteComboBox" name="authors">
|
||||
<widget class="MultiCompleteComboBox" name="authors">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
@ -175,7 +175,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="EnComboBox" name="publisher">
|
||||
<widget class="MultiCompleteComboBox" name="publisher">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
@ -195,7 +195,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="CompleteLineEdit" name="tags">
|
||||
<widget class="MultiCompleteLineEdit" name="tags">
|
||||
<property name="toolTip">
|
||||
<string>Tags categorize the book. This is particularly useful while searching. <br><br>They can be any words or phrases, separated by commas.</string>
|
||||
</property>
|
||||
@ -229,7 +229,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="CompleteLineEdit" name="remove_tags">
|
||||
<widget class="MultiCompleteLineEdit" name="remove_tags">
|
||||
<property name="toolTip">
|
||||
<string>Comma separated list of tags to remove from the books. </string>
|
||||
</property>
|
||||
@ -262,7 +262,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="EnComboBox" name="series">
|
||||
<widget class="MultiCompleteComboBox" name="series">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
@ -1072,19 +1072,14 @@ not multiple and the destination field is multiple</string>
|
||||
<header>widgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>EnComboBox</class>
|
||||
<class>MultiCompleteComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>widgets.h</header>
|
||||
<header>calibre/gui2/complete.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>CompleteComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>widgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>CompleteLineEdit</class>
|
||||
<class>MultiCompleteLineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>widgets.h</header>
|
||||
<header>calibre/gui2/complete.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>HistoryLineEdit</class>
|
||||
|
@ -740,6 +740,8 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
self.series.setSizeAdjustPolicy(self.series.AdjustToContentsOnFirstShow)
|
||||
all_series = self.db.all_series()
|
||||
all_series.sort(key=lambda x : sort_key(x[1]))
|
||||
self.series.set_separator(None)
|
||||
self.series.update_items_cache([x[1] for x in all_series])
|
||||
series_id = self.db.series_id(self.row)
|
||||
idx, c = None, 0
|
||||
for i in all_series:
|
||||
@ -757,6 +759,8 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
def initialize_publisher(self):
|
||||
all_publishers = self.db.all_publishers()
|
||||
all_publishers.sort(key=lambda x : sort_key(x[1]))
|
||||
self.publisher.set_separator(None)
|
||||
self.publisher.update_items_cache([x[1] for x in all_publishers])
|
||||
publisher_id = self.db.publisher_id(self.row)
|
||||
idx, c = None, 0
|
||||
for i in all_publishers:
|
||||
|
@ -240,7 +240,7 @@ Using this button to create author sort will change author sort from red to gree
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="CompleteComboBox" name="authors">
|
||||
<widget class="MultiCompleteComboBox" name="authors">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
@ -313,7 +313,7 @@ If the box is colored green, then text matches the individual author's sort stri
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1" colspan="2">
|
||||
<widget class="EnComboBox" name="publisher">
|
||||
<widget class="MultiCompleteComboBox" name="publisher">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
@ -335,7 +335,7 @@ If the box is colored green, then text matches the individual author's sort stri
|
||||
<item row="6" column="1">
|
||||
<layout class="QHBoxLayout" name="_2">
|
||||
<item>
|
||||
<widget class="CompleteLineEdit" name="tags">
|
||||
<widget class="MultiCompleteLineEdit" name="tags">
|
||||
<property name="toolTip">
|
||||
<string>Tags categorize the book. This is particularly useful while searching. <br><br>They can be any words or phrases, separated by commas.</string>
|
||||
</property>
|
||||
@ -379,7 +379,7 @@ If the box is colored green, then text matches the individual author's sort stri
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="EnComboBox" name="series">
|
||||
<widget class="MultiCompleteComboBox" name="series">
|
||||
<property name="toolTip">
|
||||
<string>List of known series. You can add new series.</string>
|
||||
</property>
|
||||
@ -837,19 +837,14 @@ If the box is colored green, then text matches the individual author's sort stri
|
||||
<header>widgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>EnComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>widgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>CompleteLineEdit</class>
|
||||
<class>MultiCompleteLineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>widgets.h</header>
|
||||
<header>calibre/gui2/complete.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>CompleteComboBox</class>
|
||||
<class>MultiCompleteComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>widgets.h</header>
|
||||
<header>calibre/gui2/complete.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>FormatList</class>
|
||||
|
@ -3,7 +3,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
import re, copy
|
||||
|
||||
from PyQt4.Qt import QDialog, QDialogButtonBox, QCompleter, Qt
|
||||
from PyQt4.Qt import QDialog, QDialogButtonBox
|
||||
|
||||
from calibre.gui2.dialogs.search_ui import Ui_Dialog
|
||||
from calibre.library.caches import CONTAINS_MATCH, EQUALS_MATCH
|
||||
@ -29,20 +29,18 @@ class SearchDialog(QDialog, Ui_Dialog):
|
||||
name = name.strip().replace('|', ',')
|
||||
self.authors_box.addItem(name)
|
||||
self.authors_box.setEditText('')
|
||||
self.authors_box.completer().setCompletionMode(QCompleter.PopupCompletion)
|
||||
self.authors_box.setAutoCompletionCaseSensitivity(Qt.CaseInsensitive)
|
||||
self.authors_box.set_separator('&')
|
||||
self.authors_box.set_space_before_sep(True)
|
||||
self.authors_box.update_items_cache(db.all_author_names())
|
||||
|
||||
all_series = db.all_series()
|
||||
all_series.sort(key=lambda x : sort_key(x[1]))
|
||||
self.series_box.set_separator(None)
|
||||
self.series_box.update_items_cache([x[1] for x in all_series])
|
||||
for i in all_series:
|
||||
id, name = i
|
||||
self.series_box.addItem(name)
|
||||
self.series_box.setEditText('')
|
||||
self.series_box.completer().setCompletionMode(QCompleter.PopupCompletion)
|
||||
self.series_box.setAutoCompletionCaseSensitivity(Qt.CaseInsensitive)
|
||||
|
||||
all_tags = db.all_tags()
|
||||
self.tags_box.update_items_cache(all_tags)
|
||||
|
@ -265,21 +265,21 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="CompleteComboBox" name="authors_box">
|
||||
<widget class="MultiCompleteComboBox" name="authors_box">
|
||||
<property name="toolTip">
|
||||
<string>Enter an author's name. Only one author can be used.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="EnComboBox" name="series_box">
|
||||
<widget class="MultiCompleteComboBox" name="series_box">
|
||||
<property name="toolTip">
|
||||
<string>Enter a series name, without an index. Only one series name can be used.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="CompleteLineEdit" name="tags_box">
|
||||
<widget class="MultiCompleteLineEdit" name="tags_box">
|
||||
<property name="toolTip">
|
||||
<string>Enter tags separated by spaces</string>
|
||||
</property>
|
||||
@ -355,19 +355,14 @@
|
||||
<header>widgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>EnComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>widgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>CompleteLineEdit</class>
|
||||
<class>MultiCompleteLineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>widgets.h</header>
|
||||
<header>calibre/gui2/complete.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>CompleteComboBox</class>
|
||||
<class>MultiCompleteComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>widgets.h</header>
|
||||
<header>calibre/gui2/complete.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
|
@ -156,6 +156,7 @@ class AuthorsEdit(MultiCompleteComboBox):
|
||||
|
||||
def __init__(self, parent):
|
||||
self.dialog = parent
|
||||
self.books_to_refresh = set([])
|
||||
MultiCompleteComboBox.__init__(self, parent)
|
||||
self.setToolTip(self.TOOLTIP)
|
||||
self.setWhatsThis(self.TOOLTIP)
|
||||
@ -166,6 +167,7 @@ class AuthorsEdit(MultiCompleteComboBox):
|
||||
return _('Unknown')
|
||||
|
||||
def initialize(self, db, id_):
|
||||
self.books_to_refresh = set([])
|
||||
all_authors = db.all_authors()
|
||||
all_authors.sort(key=lambda x : sort_key(x[1]))
|
||||
for i in all_authors:
|
||||
@ -185,7 +187,8 @@ class AuthorsEdit(MultiCompleteComboBox):
|
||||
|
||||
def commit(self, db, id_):
|
||||
authors = self.current_val
|
||||
db.set_authors(id_, authors, notify=False)
|
||||
self.books_to_refresh |= db.set_authors(id_, authors, notify=False,
|
||||
allow_case_change=True)
|
||||
return True
|
||||
|
||||
@dynamic_property
|
||||
@ -824,6 +827,7 @@ class TagsEdit(MultiCompleteLineEdit): # {{{
|
||||
|
||||
def __init__(self, parent):
|
||||
MultiCompleteLineEdit.__init__(self, parent)
|
||||
self.books_to_refresh = set([])
|
||||
self.setToolTip(self.TOOLTIP)
|
||||
self.setWhatsThis(self.TOOLTIP)
|
||||
|
||||
@ -838,6 +842,7 @@ class TagsEdit(MultiCompleteLineEdit): # {{{
|
||||
return property(fget=fget, fset=fset)
|
||||
|
||||
def initialize(self, db, id_):
|
||||
self.books_to_refresh = set([])
|
||||
tags = db.tags(id_, index_is_id=True)
|
||||
tags = tags.split(',') if tags else []
|
||||
self.current_val = tags
|
||||
@ -866,7 +871,9 @@ class TagsEdit(MultiCompleteLineEdit): # {{{
|
||||
|
||||
|
||||
def commit(self, db, id_):
|
||||
db.set_tags(id_, self.current_val, notify=False, commit=False)
|
||||
self.books_to_refresh |= db.set_tags(
|
||||
id_, self.current_val, notify=False, commit=False,
|
||||
allow_case_change=True)
|
||||
return True
|
||||
|
||||
# }}}
|
||||
|
@ -31,6 +31,8 @@ class MetadataSingleDialogBase(ResizableDialog):
|
||||
def __init__(self, db, parent=None):
|
||||
self.db = db
|
||||
self.changed = set([])
|
||||
self.books_to_refresh = set([])
|
||||
self.rows_to_refresh = set([])
|
||||
ResizableDialog.__init__(self, parent)
|
||||
|
||||
def setupUi(self, *args): # {{{
|
||||
@ -192,6 +194,7 @@ class MetadataSingleDialogBase(ResizableDialog):
|
||||
|
||||
def __call__(self, id_):
|
||||
self.book_id = id_
|
||||
self.books_to_refresh = set([])
|
||||
for widget in self.basic_metadata_widgets:
|
||||
widget.initialize(self.db, id_)
|
||||
for widget in self.custom_metadata_widgets:
|
||||
@ -295,6 +298,8 @@ class MetadataSingleDialogBase(ResizableDialog):
|
||||
try:
|
||||
if not widget.commit(self.db, self.book_id):
|
||||
return False
|
||||
self.books_to_refresh |= getattr(widget, 'books_to_refresh',
|
||||
set([]))
|
||||
except IOError, err:
|
||||
if err.errno == 13: # Permission denied
|
||||
import traceback
|
||||
@ -309,6 +314,10 @@ class MetadataSingleDialogBase(ResizableDialog):
|
||||
widget.commit(self.book_id)
|
||||
|
||||
self.db.commit()
|
||||
rows = self.db.refresh_ids(list(self.books_to_refresh))
|
||||
if rows:
|
||||
self.rows_to_refresh |= set(rows)
|
||||
|
||||
return True
|
||||
|
||||
def accept(self):
|
||||
@ -330,12 +339,14 @@ class MetadataSingleDialogBase(ResizableDialog):
|
||||
self.current_row = current_row
|
||||
if view_slot is not None:
|
||||
self.view_format.connect(view_slot)
|
||||
self.do_one()
|
||||
self.do_one(apply_changes=False)
|
||||
ret = self.exec_()
|
||||
self.break_cycles()
|
||||
return ret
|
||||
|
||||
def do_one(self, delta=0):
|
||||
def do_one(self, delta=0, apply_changes=True):
|
||||
if apply_changes:
|
||||
self.apply_changes()
|
||||
self.current_row += delta
|
||||
prev = next_ = None
|
||||
if self.current_row > 0:
|
||||
@ -353,6 +364,7 @@ class MetadataSingleDialogBase(ResizableDialog):
|
||||
self.prev_button.setVisible(prev is not None)
|
||||
self(self.db.id(self.row_list[self.current_row]))
|
||||
|
||||
|
||||
def break_cycles(self):
|
||||
# Break any reference cycles that could prevent python
|
||||
# from garbage collecting this dialog
|
||||
@ -618,7 +630,7 @@ class MetadataSingleDialogAlt(MetadataSingleDialogBase): # {{{
|
||||
def edit_metadata(db, row_list, current_row, parent=None, view_slot=None):
|
||||
d = MetadataSingleDialog(db, parent)
|
||||
d.start(row_list, current_row, view_slot=view_slot)
|
||||
return d.changed
|
||||
return d.changed, d.rows_to_refresh
|
||||
|
||||
if __name__ == '__main__':
|
||||
from PyQt4.Qt import QApplication
|
||||
|
@ -2153,6 +2153,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
tags = self.cleanup_tags(tags)
|
||||
books_to_refresh = set()
|
||||
for tag in (set(tags)-otags):
|
||||
case_changed = False
|
||||
tag = tag.strip()
|
||||
if not tag:
|
||||
continue
|
||||
@ -2170,8 +2171,6 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
if allow_case_change and etag != tag:
|
||||
self.conn.execute('UPDATE tags SET name=? WHERE id=?', (tag, tid))
|
||||
case_changed = True
|
||||
else:
|
||||
case_changed = False
|
||||
else:
|
||||
tid = self.conn.execute('INSERT INTO tags(name) VALUES(?)', (tag,)).lastrowid
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user