mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge from trunk, and a couple of enumeration changes
This commit is contained in:
commit
d3993f7b6f
@ -38,7 +38,7 @@ class ANDROID(USBMS):
|
|||||||
0x227]},
|
0x227]},
|
||||||
|
|
||||||
# Samsung
|
# Samsung
|
||||||
0x04e8 : { 0x681d : [0x0222, 0x0224, 0x0400],
|
0x04e8 : { 0x681d : [0x0222, 0x0223, 0x0224, 0x0400],
|
||||||
0x681c : [0x0222, 0x0224, 0x0400],
|
0x681c : [0x0222, 0x0224, 0x0400],
|
||||||
0x6640 : [0x0100],
|
0x6640 : [0x0100],
|
||||||
},
|
},
|
||||||
@ -62,7 +62,8 @@ class ANDROID(USBMS):
|
|||||||
'GT-I5700', 'SAMSUNG', 'DELL', 'LINUX']
|
'GT-I5700', 'SAMSUNG', 'DELL', 'LINUX']
|
||||||
WINDOWS_MAIN_MEM = ['ANDROID_PHONE', 'A855', 'A853', 'INC.NEXUS_ONE',
|
WINDOWS_MAIN_MEM = ['ANDROID_PHONE', 'A855', 'A853', 'INC.NEXUS_ONE',
|
||||||
'__UMS_COMPOSITE', '_MB200', 'MASS_STORAGE', '_-_CARD', 'SGH-I897',
|
'__UMS_COMPOSITE', '_MB200', 'MASS_STORAGE', '_-_CARD', 'SGH-I897',
|
||||||
'GT-I9000', 'FILE-STOR_GADGET', 'SGH-T959', 'SAMSUNG_ANDROID']
|
'GT-I9000', 'FILE-STOR_GADGET', 'SGH-T959', 'SAMSUNG_ANDROID',
|
||||||
|
'SCH-I500_CARD']
|
||||||
WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'GT-I9000_CARD', 'SGH-I897',
|
WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'GT-I9000_CARD', 'SGH-I897',
|
||||||
'FILE-STOR_GADGET', 'SGH-T959', 'SAMSUNG_ANDROID']
|
'FILE-STOR_GADGET', 'SGH-T959', 'SAMSUNG_ANDROID']
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@ class SimilarBooksAction(InterfaceAction):
|
|||||||
for a in authors.split(',')]
|
for a in authors.split(',')]
|
||||||
join = ' or '
|
join = ' or '
|
||||||
if search:
|
if search:
|
||||||
self.gui.search.set_search_string(join.join(search))
|
self.gui.search.set_search_string(join.join(search),
|
||||||
|
store_in_history=True)
|
||||||
|
|
||||||
|
|
||||||
|
@ -316,7 +316,6 @@ class Enumeration(Base):
|
|||||||
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent),
|
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent),
|
||||||
QComboBox(parent)]
|
QComboBox(parent)]
|
||||||
w = self.widgets[1]
|
w = self.widgets[1]
|
||||||
print self.col_metadata['display']
|
|
||||||
vals = self.col_metadata['display']['enum_values']
|
vals = self.col_metadata['display']['enum_values']
|
||||||
w.addItem('')
|
w.addItem('')
|
||||||
for v in vals:
|
for v in vals:
|
||||||
@ -598,7 +597,6 @@ class BulkEnumeration(BulkBase, Enumeration):
|
|||||||
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent),
|
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent),
|
||||||
QComboBox(parent)]
|
QComboBox(parent)]
|
||||||
w = self.widgets[1]
|
w = self.widgets[1]
|
||||||
print self.col_metadata['display']
|
|
||||||
vals = self.col_metadata['display']['enum_values']
|
vals = self.col_metadata['display']['enum_values']
|
||||||
w.addItem('Do Not Change')
|
w.addItem('Do Not Change')
|
||||||
w.addItem('')
|
w.addItem('')
|
||||||
|
@ -255,7 +255,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
|||||||
fm = self.db.field_metadata
|
fm = self.db.field_metadata
|
||||||
for f in fm:
|
for f in fm:
|
||||||
if (f in ['author_sort'] or
|
if (f in ['author_sort'] or
|
||||||
(fm[f]['datatype'] in ['text', 'series']
|
(fm[f]['datatype'] in ['text', 'series', 'enumeration']
|
||||||
and fm[f].get('search_terms', None)
|
and fm[f].get('search_terms', None)
|
||||||
and f not in ['formats', 'ondevice', 'sort'])):
|
and f not in ['formats', 'ondevice', 'sort'])):
|
||||||
self.all_fields.append(f)
|
self.all_fields.append(f)
|
||||||
|
@ -92,7 +92,9 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn):
|
|||||||
if c['display'].get('date_format', None):
|
if c['display'].get('date_format', None):
|
||||||
self.date_format_box.setText(c['display'].get('date_format', ''))
|
self.date_format_box.setText(c['display'].get('date_format', ''))
|
||||||
elif ct == 'composite':
|
elif ct == 'composite':
|
||||||
self.composite_box.setText(c['display'].get('enum_values', ''))
|
self.composite_box.setText(c['display'].get('composite_template', ''))
|
||||||
|
elif ct == 'enumeration':
|
||||||
|
self.enum_box.setText(','.join(c['display'].get('enum_values', [])))
|
||||||
self.datatype_changed()
|
self.datatype_changed()
|
||||||
self.exec_()
|
self.exec_()
|
||||||
|
|
||||||
|
@ -158,7 +158,7 @@
|
|||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><p>Field template. Uses the same syntax as save templates.</string>
|
<string>Field template. Uses the same syntax as save templates.</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -202,12 +202,18 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Values</string>
|
<string>Values</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>enum_box</cstring>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="2">
|
<item row="6" column="2">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLineEdit" name="enum_box">
|
<widget class="QLineEdit" name="enum_box">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>A comma-separated list of valid values.</string>
|
||||||
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
|
@ -18,7 +18,7 @@ from calibre.gui2.dialogs.saved_search_editor import SavedSearchEditor
|
|||||||
from calibre.gui2.dialogs.search import SearchDialog
|
from calibre.gui2.dialogs.search import SearchDialog
|
||||||
from calibre.utils.search_query_parser import saved_searches
|
from calibre.utils.search_query_parser import saved_searches
|
||||||
|
|
||||||
class SearchLineEdit(QLineEdit):
|
class SearchLineEdit(QLineEdit): # {{{
|
||||||
key_pressed = pyqtSignal(object)
|
key_pressed = pyqtSignal(object)
|
||||||
|
|
||||||
def keyPressEvent(self, event):
|
def keyPressEvent(self, event):
|
||||||
@ -37,17 +37,23 @@ class SearchLineEdit(QLineEdit):
|
|||||||
def paste(self, *args):
|
def paste(self, *args):
|
||||||
self.parent().normalize_state()
|
self.parent().normalize_state()
|
||||||
return QLineEdit.paste(self)
|
return QLineEdit.paste(self)
|
||||||
|
# }}}
|
||||||
|
|
||||||
class SearchBox2(QComboBox):
|
class SearchBox2(QComboBox): # {{{
|
||||||
|
|
||||||
'''
|
'''
|
||||||
To use this class:
|
To use this class:
|
||||||
|
|
||||||
* Call initialize()
|
* Call initialize()
|
||||||
* Connect to the search() and cleared() signals from this widget.
|
* Connect to the search() and cleared() signals from this widget.
|
||||||
* Connect to the cleared() signal to know when the box content changes
|
* Connect to the changed() signal to know when the box content changes
|
||||||
* Connect to focus_to_library signal to be told to manually change focus
|
* Connect to focus_to_library() signal to be told to manually change focus
|
||||||
* Call search_done() after every search is complete
|
* Call search_done() after every search is complete
|
||||||
|
* Call set_search_string() to perform a search programmatically
|
||||||
|
* You can use the current_text property to get the current search text
|
||||||
|
Be aware that if you are using it in a slow connected to the
|
||||||
|
changed() signal, if the connection is not queued it will not be
|
||||||
|
accurate.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
INTERVAL = 1500 #: Time to wait before emitting search signal
|
INTERVAL = 1500 #: Time to wait before emitting search signal
|
||||||
@ -166,12 +172,13 @@ class SearchBox2(QComboBox):
|
|||||||
self.changed.emit()
|
self.changed.emit()
|
||||||
self.do_search()
|
self.do_search()
|
||||||
|
|
||||||
def do_search(self, *args):
|
def _do_search(self, store_in_history=True):
|
||||||
text = unicode(self.currentText()).strip()
|
text = unicode(self.currentText()).strip()
|
||||||
if not text:
|
if not text:
|
||||||
return self.clear()
|
return self.clear()
|
||||||
self.search.emit(text)
|
self.search.emit(text)
|
||||||
|
|
||||||
|
if store_in_history:
|
||||||
idx = self.findText(text, Qt.MatchFixedString)
|
idx = self.findText(text, Qt.MatchFixedString)
|
||||||
self.block_signals(True)
|
self.block_signals(True)
|
||||||
if idx < 0:
|
if idx < 0:
|
||||||
@ -185,30 +192,23 @@ class SearchBox2(QComboBox):
|
|||||||
config[self.opt_name] = [unicode(self.itemText(i)) for i in
|
config[self.opt_name] = [unicode(self.itemText(i)) for i in
|
||||||
range(self.count())]
|
range(self.count())]
|
||||||
|
|
||||||
|
def do_search(self, *args):
|
||||||
|
self._do_search()
|
||||||
|
|
||||||
def block_signals(self, yes):
|
def block_signals(self, yes):
|
||||||
self.blockSignals(yes)
|
self.blockSignals(yes)
|
||||||
self.line_edit.blockSignals(yes)
|
self.line_edit.blockSignals(yes)
|
||||||
|
|
||||||
def search_from_tokens(self, tokens, all):
|
def set_search_string(self, txt, store_in_history=False):
|
||||||
ans = u' '.join([u'%s:%s'%x for x in tokens])
|
|
||||||
if not all:
|
|
||||||
ans = '[' + ans + ']'
|
|
||||||
self.set_search_string(ans)
|
|
||||||
|
|
||||||
def search_from_tags(self, tags, all):
|
|
||||||
joiner = ' and ' if all else ' or '
|
|
||||||
self.set_search_string(joiner.join(tags))
|
|
||||||
|
|
||||||
def set_search_string(self, txt):
|
|
||||||
self.setFocus(Qt.OtherFocusReason)
|
self.setFocus(Qt.OtherFocusReason)
|
||||||
if not txt:
|
if not txt:
|
||||||
self.clear()
|
self.clear()
|
||||||
else:
|
else:
|
||||||
self.normalize_state()
|
self.normalize_state()
|
||||||
self.setEditText(txt)
|
self.setEditText(txt)
|
||||||
self.search.emit(txt)
|
|
||||||
self.line_edit.end(False)
|
self.line_edit.end(False)
|
||||||
self.initial_state = False
|
self.changed.emit()
|
||||||
|
self._do_search(store_in_history=store_in_history)
|
||||||
self.focus_to_library.emit()
|
self.focus_to_library.emit()
|
||||||
|
|
||||||
def search_as_you_type(self, enabled):
|
def search_as_you_type(self, enabled):
|
||||||
@ -217,7 +217,13 @@ class SearchBox2(QComboBox):
|
|||||||
def in_a_search(self):
|
def in_a_search(self):
|
||||||
return self._in_a_search
|
return self._in_a_search
|
||||||
|
|
||||||
class SavedSearchBox(QComboBox):
|
@property
|
||||||
|
def current_text(self):
|
||||||
|
return unicode(self.lineEdit().text())
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
class SavedSearchBox(QComboBox): # {{{
|
||||||
|
|
||||||
'''
|
'''
|
||||||
To use this class:
|
To use this class:
|
||||||
@ -329,13 +335,17 @@ class SavedSearchBox(QComboBox):
|
|||||||
return
|
return
|
||||||
self.search_box.set_search_string(saved_searches().lookup(unicode(self.currentText())))
|
self.search_box.set_search_string(saved_searches().lookup(unicode(self.currentText())))
|
||||||
|
|
||||||
class SearchBoxMixin(object):
|
# }}}
|
||||||
|
|
||||||
|
class SearchBoxMixin(object): # {{{
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.search.initialize('main_search_history', colorize=True,
|
self.search.initialize('main_search_history', colorize=True,
|
||||||
help_text=_('Search (For Advanced Search click the button to the left)'))
|
help_text=_('Search (For Advanced Search click the button to the left)'))
|
||||||
self.search.cleared.connect(self.search_box_cleared)
|
self.search.cleared.connect(self.search_box_cleared)
|
||||||
self.search.changed.connect(self.search_box_changed)
|
# Queued so that search.current_text will be correct
|
||||||
|
self.search.changed.connect(self.search_box_changed,
|
||||||
|
type=Qt.QueuedConnection)
|
||||||
self.search.focus_to_library.connect(self.focus_to_library)
|
self.search.focus_to_library.connect(self.focus_to_library)
|
||||||
self.clear_button.clicked.connect(self.search.clear_clicked)
|
self.clear_button.clicked.connect(self.search.clear_clicked)
|
||||||
self.advanced_search_button.clicked[bool].connect(self.do_advanced_search)
|
self.advanced_search_button.clicked[bool].connect(self.do_advanced_search)
|
||||||
@ -364,7 +374,7 @@ class SearchBoxMixin(object):
|
|||||||
|
|
||||||
def search_box_changed(self):
|
def search_box_changed(self):
|
||||||
self.saved_search.clear()
|
self.saved_search.clear()
|
||||||
self.tags_view.clear()
|
self.tags_view.conditional_clear(self.search.current_text)
|
||||||
|
|
||||||
def do_advanced_search(self, *args):
|
def do_advanced_search(self, *args):
|
||||||
d = SearchDialog(self, self.library_view.model().db)
|
d = SearchDialog(self, self.library_view.model().db)
|
||||||
@ -378,7 +388,9 @@ class SearchBoxMixin(object):
|
|||||||
def focus_to_library(self):
|
def focus_to_library(self):
|
||||||
self.current_view().setFocus(Qt.OtherFocusReason)
|
self.current_view().setFocus(Qt.OtherFocusReason)
|
||||||
|
|
||||||
class SavedSearchBoxMixin(object):
|
# }}}
|
||||||
|
|
||||||
|
class SavedSearchBoxMixin(object): # {{{
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.saved_search.changed.connect(self.saved_searches_changed)
|
self.saved_search.changed.connect(self.saved_searches_changed)
|
||||||
@ -417,3 +429,6 @@ class SavedSearchBoxMixin(object):
|
|||||||
if d.result() == d.Accepted:
|
if d.result() == d.Accepted:
|
||||||
self.saved_searches_changed()
|
self.saved_searches_changed()
|
||||||
self.saved_search.clear()
|
self.saved_search.clear()
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ class TagDelegate(QItemDelegate): # {{{
|
|||||||
class TagsView(QTreeView): # {{{
|
class TagsView(QTreeView): # {{{
|
||||||
|
|
||||||
refresh_required = pyqtSignal()
|
refresh_required = pyqtSignal()
|
||||||
tags_marked = pyqtSignal(object, object)
|
tags_marked = pyqtSignal(object)
|
||||||
user_category_edit = pyqtSignal(object)
|
user_category_edit = pyqtSignal(object)
|
||||||
tag_list_edit = pyqtSignal(object, object)
|
tag_list_edit = pyqtSignal(object, object)
|
||||||
saved_search_edit = pyqtSignal(object)
|
saved_search_edit = pyqtSignal(object)
|
||||||
@ -135,11 +135,21 @@ class TagsView(QTreeView): # {{{
|
|||||||
# swallow these to avoid toggling and editing at the same time
|
# swallow these to avoid toggling and editing at the same time
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def search_string(self):
|
||||||
|
tokens = self._model.tokens()
|
||||||
|
joiner = ' and ' if self.match_all else ' or '
|
||||||
|
return joiner.join(tokens)
|
||||||
|
|
||||||
def toggle(self, index):
|
def toggle(self, index):
|
||||||
modifiers = int(QApplication.keyboardModifiers())
|
modifiers = int(QApplication.keyboardModifiers())
|
||||||
exclusive = modifiers not in (Qt.CTRL, Qt.SHIFT)
|
exclusive = modifiers not in (Qt.CTRL, Qt.SHIFT)
|
||||||
if self._model.toggle(index, exclusive):
|
if self._model.toggle(index, exclusive):
|
||||||
self.tags_marked.emit(self._model.tokens(), self.match_all)
|
self.tags_marked.emit(self.search_string)
|
||||||
|
|
||||||
|
def conditional_clear(self, search_string):
|
||||||
|
if search_string != self.search_string:
|
||||||
|
self.clear()
|
||||||
|
|
||||||
def context_menu_handler(self, action=None, category=None,
|
def context_menu_handler(self, action=None, category=None,
|
||||||
key=None, index=None):
|
key=None, index=None):
|
||||||
@ -842,8 +852,7 @@ class TagBrowserMixin(object): # {{{
|
|||||||
self.library_view.model().count_changed_signal.connect(self.tags_view.recount)
|
self.library_view.model().count_changed_signal.connect(self.tags_view.recount)
|
||||||
self.tags_view.set_database(self.library_view.model().db,
|
self.tags_view.set_database(self.library_view.model().db,
|
||||||
self.tag_match, self.sort_by)
|
self.tag_match, self.sort_by)
|
||||||
self.tags_view.tags_marked.connect(self.search.search_from_tags)
|
self.tags_view.tags_marked.connect(self.search.set_search_string)
|
||||||
self.tags_view.tags_marked.connect(self.saved_search.clear)
|
|
||||||
self.tags_view.tag_list_edit.connect(self.do_tags_list_edit)
|
self.tags_view.tag_list_edit.connect(self.do_tags_list_edit)
|
||||||
self.tags_view.user_category_edit.connect(self.do_user_categories_edit)
|
self.tags_view.user_category_edit.connect(self.do_user_categories_edit)
|
||||||
self.tags_view.saved_search_edit.connect(self.do_saved_search_edit)
|
self.tags_view.saved_search_edit.connect(self.do_saved_search_edit)
|
||||||
|
@ -520,7 +520,7 @@ class ResultCache(SearchQueryParser): # {{{
|
|||||||
if len(self.field_metadata[x]['search_terms']):
|
if len(self.field_metadata[x]['search_terms']):
|
||||||
db_col[x] = self.field_metadata[x]['rec_index']
|
db_col[x] = self.field_metadata[x]['rec_index']
|
||||||
if self.field_metadata[x]['datatype'] not in \
|
if self.field_metadata[x]['datatype'] not in \
|
||||||
['composite', 'text', 'comments', 'series']:
|
['composite', 'text', 'comments', 'series', 'enumeration']:
|
||||||
exclude_fields.append(db_col[x])
|
exclude_fields.append(db_col[x])
|
||||||
col_datatype[db_col[x]] = self.field_metadata[x]['datatype']
|
col_datatype[db_col[x]] = self.field_metadata[x]['datatype']
|
||||||
is_multiple_cols[db_col[x]] = self.field_metadata[x]['is_multiple']
|
is_multiple_cols[db_col[x]] = self.field_metadata[x]['is_multiple']
|
||||||
@ -828,7 +828,7 @@ class SortKeyGenerator(object):
|
|||||||
sidx = record[sidx_fm['rec_index']]
|
sidx = record[sidx_fm['rec_index']]
|
||||||
val = (val, sidx)
|
val = (val, sidx)
|
||||||
|
|
||||||
elif dt in ('text', 'comments', 'composite'):
|
elif dt in ('text', 'comments', 'composite', 'enumeration'):
|
||||||
if val is None:
|
if val is None:
|
||||||
val = ''
|
val = ''
|
||||||
val = val.lower()
|
val = val.lower()
|
||||||
|
@ -440,6 +440,10 @@ class CustomColumns(object):
|
|||||||
val = self.custom_data_adapters[data['datatype']](val, data)
|
val = self.custom_data_adapters[data['datatype']](val, data)
|
||||||
|
|
||||||
if data['normalized']:
|
if data['normalized']:
|
||||||
|
if data['datatype'] == 'enumeration' and \
|
||||||
|
val not in data['display']['enum_values']:
|
||||||
|
print 'attempt to set enum to', val
|
||||||
|
return None
|
||||||
if not append or not data['is_multiple']:
|
if not append or not data['is_multiple']:
|
||||||
self.conn.execute('DELETE FROM %s WHERE book=?'%lt, (id_,))
|
self.conn.execute('DELETE FROM %s WHERE book=?'%lt, (id_,))
|
||||||
self.conn.execute(
|
self.conn.execute(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user