mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Manage tags/authors/etc dialogs: Allow searching and filtering the list of items. Fixes #1879134 [[Enhancement] Add filters to all the Category editor (Authors, Series, Publishers and Tags)](https://bugs.launchpad.net/calibre/+bug/1879134)
Merge branch 'master' of https://github.com/cbhaley/calibre
This commit is contained in:
commit
a74ed3ae64
@ -7,14 +7,17 @@ __license__ = 'GPL v3'
|
|||||||
|
|
||||||
from PyQt5.Qt import (Qt, QDialog, QTableWidgetItem, QAbstractItemView, QIcon,
|
from PyQt5.Qt import (Qt, QDialog, QTableWidgetItem, QAbstractItemView, QIcon,
|
||||||
QDialogButtonBox, QFrame, QLabel, QTimer, QMenu, QApplication,
|
QDialogButtonBox, QFrame, QLabel, QTimer, QMenu, QApplication,
|
||||||
QByteArray, QItemDelegate)
|
QByteArray, QItemDelegate, QAction)
|
||||||
|
|
||||||
from calibre.ebooks.metadata import author_to_author_sort, string_to_authors
|
from calibre.ebooks.metadata import author_to_author_sort, string_to_authors
|
||||||
from calibre.gui2 import error_dialog, gprefs
|
from calibre.gui2 import error_dialog, gprefs
|
||||||
from calibre.gui2.dialogs.edit_authors_dialog_ui import Ui_EditAuthorsDialog
|
from calibre.gui2.dialogs.edit_authors_dialog_ui import Ui_EditAuthorsDialog
|
||||||
from calibre.utils.icu import sort_key
|
from calibre.utils.config import prefs
|
||||||
|
from calibre.utils.icu import sort_key, primary_contains, contains
|
||||||
from polyglot.builtins import unicode_type
|
from polyglot.builtins import unicode_type
|
||||||
|
|
||||||
|
QT_HIDDEN_CLEAR_ACTION = '_q_qlineeditclearaction'
|
||||||
|
|
||||||
|
|
||||||
class tableItem(QTableWidgetItem):
|
class tableItem(QTableWidgetItem):
|
||||||
|
|
||||||
@ -92,23 +95,33 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
|||||||
hh.sectionClicked.connect(self.do_sort)
|
hh.sectionClicked.connect(self.do_sort)
|
||||||
hh.setSortIndicatorShown(True)
|
hh.setSortIndicatorShown(True)
|
||||||
|
|
||||||
# set up the search box
|
# set up the search & filter boxes
|
||||||
self.find_box.initialize('manage_authors_search')
|
self.find_box.initialize('manage_authors_search')
|
||||||
self.find_box.lineEdit().returnPressed.connect(self.do_find)
|
le = self.find_box.lineEdit()
|
||||||
|
ac = le.findChild(QAction, QT_HIDDEN_CLEAR_ACTION)
|
||||||
|
if ac is not None:
|
||||||
|
ac.triggered.connect(self.clear_find)
|
||||||
|
le.returnPressed.connect(self.do_find)
|
||||||
self.find_box.editTextChanged.connect(self.find_text_changed)
|
self.find_box.editTextChanged.connect(self.find_text_changed)
|
||||||
self.find_button.clicked.connect(self.do_find)
|
self.find_button.clicked.connect(self.do_find)
|
||||||
self.find_button.setDefault(True)
|
self.find_button.setDefault(True)
|
||||||
|
|
||||||
l = QLabel(self.table)
|
self.filter_box.initialize('manage_authors_filter')
|
||||||
self.not_found_label = l
|
le = self.filter_box.lineEdit()
|
||||||
|
ac = le.findChild(QAction, QT_HIDDEN_CLEAR_ACTION)
|
||||||
|
if ac is not None:
|
||||||
|
ac.triggered.connect(self.clear_filter)
|
||||||
|
self.filter_box.lineEdit().returnPressed.connect(self.do_filter)
|
||||||
|
self.filter_button.clicked.connect(self.do_filter)
|
||||||
|
|
||||||
|
self.not_found_label = l = QLabel(self.table)
|
||||||
l.setFrameStyle(QFrame.StyledPanel)
|
l.setFrameStyle(QFrame.StyledPanel)
|
||||||
l.setAutoFillBackground(True)
|
l.setAutoFillBackground(True)
|
||||||
l.setText(_('No matches found'))
|
l.setText(_('No matches found'))
|
||||||
l.setAlignment(Qt.AlignVCenter)
|
l.setAlignment(Qt.AlignVCenter)
|
||||||
l.resize(l.sizeHint())
|
l.resize(l.sizeHint())
|
||||||
l.move(10,20)
|
l.move(10, 2)
|
||||||
l.setVisible(False)
|
l.setVisible(False)
|
||||||
self.not_found_label.move(40, 40)
|
|
||||||
self.not_found_label_timer = QTimer()
|
self.not_found_label_timer = QTimer()
|
||||||
self.not_found_label_timer.setSingleShot(True)
|
self.not_found_label_timer.setSingleShot(True)
|
||||||
self.not_found_label_timer.timeout.connect(
|
self.not_found_label_timer.timeout.connect(
|
||||||
@ -131,6 +144,11 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
|||||||
'link': v['link']}
|
'link': v['link']}
|
||||||
|
|
||||||
self.edited_icon = QIcon(I('modified.png'))
|
self.edited_icon = QIcon(I('modified.png'))
|
||||||
|
if prefs['use_primary_find_in_search']:
|
||||||
|
self.string_contains = primary_contains
|
||||||
|
else:
|
||||||
|
self.string_contains = contains
|
||||||
|
|
||||||
self.last_sorted_by = 'sort'
|
self.last_sorted_by = 'sort'
|
||||||
self.author_order = 1
|
self.author_order = 1
|
||||||
self.author_sort_order = 0
|
self.author_sort_order = 0
|
||||||
@ -140,9 +158,19 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
|||||||
def use_vl_changed(self, x):
|
def use_vl_changed(self, x):
|
||||||
self.show_table(None, None, None)
|
self.show_table(None, None, None)
|
||||||
|
|
||||||
|
def clear_filter(self):
|
||||||
|
self.filter_box.setText('')
|
||||||
|
self.show_table(None, None, None)
|
||||||
|
|
||||||
|
def do_filter(self):
|
||||||
|
self.show_table(None, None, None)
|
||||||
|
|
||||||
def show_table(self, id_to_select, select_sort, select_link):
|
def show_table(self, id_to_select, select_sort, select_link):
|
||||||
auts_to_show = [t[0] for t in
|
filter_text = icu_lower(unicode_type(self.filter_box.text()))
|
||||||
self.find_aut_func(use_virtual_library=self.apply_vl_checkbox.isChecked())]
|
auts_to_show = []
|
||||||
|
for t in self.find_aut_func(use_virtual_library=self.apply_vl_checkbox.isChecked()):
|
||||||
|
if self.string_contains(filter_text, icu_lower(t[1])):
|
||||||
|
auts_to_show.append(t[0])
|
||||||
self.table.blockSignals(True)
|
self.table.blockSignals(True)
|
||||||
self.table.clear()
|
self.table.clear()
|
||||||
self.table.setColumnCount(3)
|
self.table.setColumnCount(3)
|
||||||
@ -184,13 +212,13 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
|||||||
self.table.setHorizontalHeaderLabels([_('Author'), _('Author sort'), _('Link')])
|
self.table.setHorizontalHeaderLabels([_('Author'), _('Author sort'), _('Link')])
|
||||||
|
|
||||||
if self.last_sorted_by == 'sort':
|
if self.last_sorted_by == 'sort':
|
||||||
self.author_sort_order = 1 if self.author_sort_order == 0 else 0
|
self.author_sort_order = 1 - self.author_sort_order
|
||||||
self.do_sort_by_author_sort()
|
self.do_sort_by_author_sort()
|
||||||
elif self.last_sorted_by == 'author':
|
elif self.last_sorted_by == 'author':
|
||||||
self.author_order = 1 if self.author_order == 0 else 0
|
self.author_order = 1 - self.author_order
|
||||||
self.do_sort_by_author()
|
self.do_sort_by_author()
|
||||||
else:
|
else:
|
||||||
self.link_order = 1 if self.link_order == 0 else 0
|
self.link_order = 1 - self.link_order
|
||||||
self.do_sort_by_link()
|
self.do_sort_by_link()
|
||||||
|
|
||||||
# Position on the desired item
|
# Position on the desired item
|
||||||
@ -308,6 +336,11 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
|||||||
def not_found_label_timer_event(self):
|
def not_found_label_timer_event(self):
|
||||||
self.not_found_label.setVisible(False)
|
self.not_found_label.setVisible(False)
|
||||||
|
|
||||||
|
def clear_find(self):
|
||||||
|
self.find_box.setText('')
|
||||||
|
self.start_find_pos = -1
|
||||||
|
self.do_find()
|
||||||
|
|
||||||
def find_text_changed(self):
|
def find_text_changed(self):
|
||||||
self.start_find_pos = -1
|
self.start_find_pos = -1
|
||||||
|
|
||||||
@ -319,9 +352,11 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
|||||||
self.buttonBox.button(QDialogButtonBox.Ok).setAutoDefault(False)
|
self.buttonBox.button(QDialogButtonBox.Ok).setAutoDefault(False)
|
||||||
self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(False)
|
self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(False)
|
||||||
self.buttonBox.button(QDialogButtonBox.Cancel).setAutoDefault(False)
|
self.buttonBox.button(QDialogButtonBox.Cancel).setAutoDefault(False)
|
||||||
st = icu_lower(unicode_type(self.find_box.currentText()))
|
|
||||||
|
|
||||||
for i in range(0, self.table.rowCount()*2):
|
st = icu_lower(unicode_type(self.find_box.currentText()))
|
||||||
|
if not st:
|
||||||
|
return
|
||||||
|
for _ in range(0, self.table.rowCount()*2):
|
||||||
self.start_find_pos = (self.start_find_pos + 1) % (self.table.rowCount()*2)
|
self.start_find_pos = (self.start_find_pos + 1) % (self.table.rowCount()*2)
|
||||||
r = (self.start_find_pos//2) % self.table.rowCount()
|
r = (self.start_find_pos//2) % self.table.rowCount()
|
||||||
c = self.start_find_pos % 2
|
c = self.start_find_pos % 2
|
||||||
@ -405,8 +440,8 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
|||||||
item = self.table.item(row, col)
|
item = self.table.item(row, col)
|
||||||
item.setIcon(self.edited_icon)
|
item.setIcon(self.edited_icon)
|
||||||
if col == 1:
|
if col == 1:
|
||||||
self.authors[id_]['sort'] = item.text()
|
self.authors[id_]['sort'] = unicode_type(item.text())
|
||||||
else:
|
else:
|
||||||
self.authors[id_]['link'] = item.text()
|
self.authors[id_]['link'] = unicode_type(item.text())
|
||||||
self.table.setCurrentItem(item)
|
self.table.setCurrentItem(item)
|
||||||
self.table.scrollToItem(item)
|
self.table.scrollToItem(item)
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item >
|
<item >
|
||||||
<layout class="QHBoxLayout" name="">
|
<layout class="QGridLayout" name="">
|
||||||
<item>
|
<item row="0" column="0">
|
||||||
<widget class="QLabel">
|
<widget class="QLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Search for:</string>
|
<string>&Search for:</string>
|
||||||
@ -32,7 +32,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="0" column="1">
|
||||||
<widget class="HistoryLineEdit" name="find_box">
|
<widget class="HistoryLineEdit" name="find_box">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
@ -40,16 +40,19 @@
|
|||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
<property name="clearButtonEnabled">
|
||||||
</item>
|
<bool>true</bool>
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="find_button">
|
|
||||||
<property name="text">
|
|
||||||
<string>F&ind</string>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="0" column="2">
|
||||||
|
<widget class="QPushButton" name="find_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>S&earch</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="3">
|
||||||
<spacer>
|
<spacer>
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
@ -62,15 +65,49 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="0" column="4">
|
||||||
<widget class="QCheckBox" name="apply_vl_checkbox">
|
<widget class="QCheckBox" name="apply_vl_checkbox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><p>Show authors only if they appear in the
|
<string><p>Only show authors in the
|
||||||
current Virtual library. Edits already done may be hidden but will
|
current Virtual library. Edits already done may be hidden but will
|
||||||
not be forgotten.</p></string>
|
not be forgotten.</p></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Show only available items in current Virtual library</string>
|
<string>Only show authors in the current &virtual library</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Filter &By:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>filter_box</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="HistoryLineEdit" name="filter_box">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>200</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><p>Only show authors that contain the text in this box.
|
||||||
|
The match ignores case.</p></string>
|
||||||
|
</property>
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QPushButton" name="filter_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>Fi&lter</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -5,16 +5,19 @@ from __future__ import absolute_import, division, print_function, unicode_litera
|
|||||||
|
|
||||||
from PyQt5.Qt import (Qt, QDialog, QTableWidgetItem, QIcon, QByteArray, QSize,
|
from PyQt5.Qt import (Qt, QDialog, QTableWidgetItem, QIcon, QByteArray, QSize,
|
||||||
QDialogButtonBox, QTableWidget, QItemDelegate, QApplication,
|
QDialogButtonBox, QTableWidget, QItemDelegate, QApplication,
|
||||||
pyqtSignal)
|
pyqtSignal, QAction, QFrame, QLabel, QTimer)
|
||||||
|
|
||||||
from calibre.gui2.dialogs.tag_list_editor_ui import Ui_TagListEditor
|
from calibre.gui2.dialogs.tag_list_editor_ui import Ui_TagListEditor
|
||||||
from calibre.gui2.complete2 import EditWithComplete
|
from calibre.gui2.complete2 import EditWithComplete
|
||||||
from calibre.gui2.dialogs.confirm_delete import confirm
|
from calibre.gui2.dialogs.confirm_delete import confirm
|
||||||
from calibre.gui2.widgets import EnLineEdit
|
from calibre.gui2.widgets import EnLineEdit
|
||||||
from calibre.gui2 import question_dialog, error_dialog, gprefs
|
from calibre.gui2 import question_dialog, error_dialog, gprefs
|
||||||
from calibre.utils.icu import sort_key
|
from calibre.utils.config import prefs
|
||||||
|
from calibre.utils.icu import sort_key, contains, primary_contains
|
||||||
from polyglot.builtins import unicode_type
|
from polyglot.builtins import unicode_type
|
||||||
|
|
||||||
|
QT_HIDDEN_CLEAR_ACTION = '_q_qlineeditclearaction'
|
||||||
|
|
||||||
|
|
||||||
class NameTableWidgetItem(QTableWidgetItem):
|
class NameTableWidgetItem(QTableWidgetItem):
|
||||||
|
|
||||||
@ -137,6 +140,7 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
|||||||
|
|
||||||
# Put the category name into the title bar
|
# Put the category name into the title bar
|
||||||
t = self.windowTitle()
|
t = self.windowTitle()
|
||||||
|
self.category_name = cat_name
|
||||||
self.setWindowTitle(t + ' (' + cat_name + ')')
|
self.setWindowTitle(t + ' (' + cat_name + ')')
|
||||||
# Remove help icon on title bar
|
# Remove help icon on title bar
|
||||||
icon = self.windowIcon()
|
icon = self.windowIcon()
|
||||||
@ -161,16 +165,14 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
|||||||
self.get_book_ids = get_book_ids
|
self.get_book_ids = get_book_ids
|
||||||
self.text_before_editing = ''
|
self.text_before_editing = ''
|
||||||
|
|
||||||
# Set up the column headings
|
|
||||||
self.down_arrow_icon = QIcon(I('arrow-down.png'))
|
|
||||||
self.up_arrow_icon = QIcon(I('arrow-up.png'))
|
|
||||||
self.blank_icon = QIcon(I('blank.png'))
|
|
||||||
|
|
||||||
# Capture clicks on the horizontal header to sort the table columns
|
# Capture clicks on the horizontal header to sort the table columns
|
||||||
hh = self.table.horizontalHeader()
|
hh = self.table.horizontalHeader()
|
||||||
hh.setSectionsClickable(True)
|
|
||||||
hh.sectionClicked.connect(self.header_clicked)
|
|
||||||
hh.sectionResized.connect(self.table_column_resized)
|
hh.sectionResized.connect(self.table_column_resized)
|
||||||
|
hh.setSectionsClickable(True)
|
||||||
|
hh.sectionClicked.connect(self.do_sort)
|
||||||
|
hh.setSortIndicatorShown(True)
|
||||||
|
|
||||||
|
self.last_sorted_by = 'name'
|
||||||
self.name_order = 0
|
self.name_order = 0
|
||||||
self.count_order = 1
|
self.count_order = 1
|
||||||
self.was_order = 1
|
self.was_order = 1
|
||||||
@ -180,12 +182,10 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
|||||||
self.edit_delegate.editing_started.connect(self.start_editing)
|
self.edit_delegate.editing_started.connect(self.start_editing)
|
||||||
self.table.setItemDelegateForColumn(0, self.edit_delegate)
|
self.table.setItemDelegateForColumn(0, self.edit_delegate)
|
||||||
|
|
||||||
# Add the data
|
if prefs['use_primary_find_in_search']:
|
||||||
select_item = self.fill_in_table(None, tag_to_match)
|
self.string_contains = primary_contains
|
||||||
|
else:
|
||||||
# Scroll to the selected item if there is one
|
self.string_contains = contains
|
||||||
if select_item is not None:
|
|
||||||
self.table.setCurrentItem(select_item)
|
|
||||||
|
|
||||||
self.delete_button.clicked.connect(self.delete_tags)
|
self.delete_button.clicked.connect(self.delete_tags)
|
||||||
self.rename_button.clicked.connect(self.rename_tag)
|
self.rename_button.clicked.connect(self.rename_tag)
|
||||||
@ -198,8 +198,35 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
|||||||
self.buttonBox.accepted.connect(self.accepted)
|
self.buttonBox.accepted.connect(self.accepted)
|
||||||
|
|
||||||
self.search_box.initialize('tag_list_search_box_' + cat_name)
|
self.search_box.initialize('tag_list_search_box_' + cat_name)
|
||||||
self.search_button.clicked.connect(self.all_matching_clicked)
|
le = self.search_box.lineEdit()
|
||||||
|
ac = le.findChild(QAction, QT_HIDDEN_CLEAR_ACTION)
|
||||||
|
if ac is not None:
|
||||||
|
ac.triggered.connect(self.clear_search)
|
||||||
|
le.returnPressed.connect(self.do_search)
|
||||||
|
self.search_box.textChanged.connect(self.search_text_changed)
|
||||||
|
self.search_button.clicked.connect(self.do_search)
|
||||||
self.search_button.setDefault(True)
|
self.search_button.setDefault(True)
|
||||||
|
l = QLabel(self.table)
|
||||||
|
self.not_found_label = l
|
||||||
|
l.setFrameStyle(QFrame.StyledPanel)
|
||||||
|
l.setAutoFillBackground(True)
|
||||||
|
l.setText(_('No matches found'))
|
||||||
|
l.setAlignment(Qt.AlignVCenter)
|
||||||
|
l.resize(l.sizeHint())
|
||||||
|
l.move(10, 0)
|
||||||
|
l.setVisible(False)
|
||||||
|
self.not_found_label_timer = QTimer()
|
||||||
|
self.not_found_label_timer.setSingleShot(True)
|
||||||
|
self.not_found_label_timer.timeout.connect(
|
||||||
|
self.not_found_label_timer_event, type=Qt.QueuedConnection)
|
||||||
|
|
||||||
|
self.filter_box.initialize('tag_list_filter_box_' + cat_name)
|
||||||
|
le = self.filter_box.lineEdit()
|
||||||
|
ac = le.findChild(QAction, QT_HIDDEN_CLEAR_ACTION)
|
||||||
|
if ac is not None:
|
||||||
|
ac.triggered.connect(self.clear_filter)
|
||||||
|
le.returnPressed.connect(self.do_filter)
|
||||||
|
self.filter_button.clicked.connect(self.do_filter)
|
||||||
|
|
||||||
self.apply_vl_checkbox.clicked.connect(self.vl_box_changed)
|
self.apply_vl_checkbox.clicked.connect(self.vl_box_changed)
|
||||||
|
|
||||||
@ -213,14 +240,43 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
|||||||
self.resize(self.sizeHint()+QSize(150, 100))
|
self.resize(self.sizeHint()+QSize(150, 100))
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
# Add the data
|
||||||
|
self.search_item_row = -1
|
||||||
|
self.fill_in_table(None, tag_to_match)
|
||||||
|
|
||||||
def vl_box_changed(self):
|
def vl_box_changed(self):
|
||||||
|
self.search_item_row = -1
|
||||||
self.fill_in_table(None, None)
|
self.fill_in_table(None, None)
|
||||||
|
|
||||||
|
def do_search(self):
|
||||||
|
self.not_found_label.setVisible(False)
|
||||||
|
find_text = icu_lower(unicode_type(self.search_box.currentText()))
|
||||||
|
if not find_text:
|
||||||
|
return
|
||||||
|
for _ in range(0, self.table.rowCount()):
|
||||||
|
r = self.search_item_row = (self.search_item_row + 1) % self.table.rowCount()
|
||||||
|
if self.string_contains(find_text,
|
||||||
|
self.all_tags[self.ordered_tags[r]]['cur_name']):
|
||||||
|
self.table.setCurrentItem(self.table.item(r, 0))
|
||||||
|
self.table.setFocus(True)
|
||||||
|
return
|
||||||
|
# Nothing found. Pop up the little dialog for 1.5 seconds
|
||||||
|
self.not_found_label.setVisible(True)
|
||||||
|
self.not_found_label_timer.start(1500)
|
||||||
|
|
||||||
|
def search_text_changed(self):
|
||||||
|
self.search_item_row = -1
|
||||||
|
|
||||||
|
def clear_search(self):
|
||||||
|
self.search_item_row = -1
|
||||||
|
self.search_box.setText('')
|
||||||
|
|
||||||
def fill_in_table(self, tags, tag_to_match):
|
def fill_in_table(self, tags, tag_to_match):
|
||||||
data = self.get_book_ids(self.apply_vl_checkbox.isChecked())
|
data = self.get_book_ids(self.apply_vl_checkbox.isChecked())
|
||||||
self.all_tags = {}
|
self.all_tags = {}
|
||||||
|
filter_text = icu_lower(unicode_type(self.filter_box.text()))
|
||||||
for k,v,count in data:
|
for k,v,count in data:
|
||||||
|
if not filter_text or self.string_contains(filter_text, icu_lower(v)):
|
||||||
self.all_tags[v] = {'key': k, 'count': count, 'cur_name': v,
|
self.all_tags[v] = {'key': k, 'count': count, 'cur_name': v,
|
||||||
'is_deleted': k in self.to_delete}
|
'is_deleted': k in self.to_delete}
|
||||||
self.original_names[k] = v
|
self.original_names[k] = v
|
||||||
@ -234,18 +290,14 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
|||||||
self.table.blockSignals(True)
|
self.table.blockSignals(True)
|
||||||
self.table.clear()
|
self.table.clear()
|
||||||
self.table.setColumnCount(3)
|
self.table.setColumnCount(3)
|
||||||
self.name_col = QTableWidgetItem(_('Tag'))
|
self.name_col = QTableWidgetItem(self.category_name)
|
||||||
self.table.setHorizontalHeaderItem(0, self.name_col)
|
self.table.setHorizontalHeaderItem(0, self.name_col)
|
||||||
self.name_col.setIcon(self.up_arrow_icon)
|
|
||||||
self.count_col = QTableWidgetItem(_('Count'))
|
self.count_col = QTableWidgetItem(_('Count'))
|
||||||
self.table.setHorizontalHeaderItem(1, self.count_col)
|
self.table.setHorizontalHeaderItem(1, self.count_col)
|
||||||
self.count_col.setIcon(self.blank_icon)
|
|
||||||
self.was_col = QTableWidgetItem(_('Was'))
|
self.was_col = QTableWidgetItem(_('Was'))
|
||||||
self.table.setHorizontalHeaderItem(2, self.was_col)
|
self.table.setHorizontalHeaderItem(2, self.was_col)
|
||||||
self.count_col.setIcon(self.blank_icon)
|
|
||||||
|
|
||||||
self.table.setRowCount(len(tags))
|
self.table.setRowCount(len(tags))
|
||||||
|
|
||||||
for row,tag in enumerate(tags):
|
for row,tag in enumerate(tags):
|
||||||
item = NameTableWidgetItem()
|
item = NameTableWidgetItem()
|
||||||
item.set_is_deleted(self.all_tags[tag]['is_deleted'])
|
item.set_is_deleted(self.all_tags[tag]['is_deleted'])
|
||||||
@ -260,7 +312,6 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
|||||||
self.table.setItem(row, 0, item)
|
self.table.setItem(row, 0, item)
|
||||||
if tag == tag_to_match:
|
if tag == tag_to_match:
|
||||||
select_item = item
|
select_item = item
|
||||||
|
|
||||||
item = CountTableWidgetItem(self.all_tags[tag]['count'])
|
item = CountTableWidgetItem(self.all_tags[tag]['count'])
|
||||||
# only the name column can be selected
|
# only the name column can be selected
|
||||||
item.setFlags(item.flags() & ~(Qt.ItemIsSelectable|Qt.ItemIsEditable))
|
item.setFlags(item.flags() & ~(Qt.ItemIsSelectable|Qt.ItemIsEditable))
|
||||||
@ -271,27 +322,31 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
|||||||
if _id in self.to_rename or _id in self.to_delete:
|
if _id in self.to_rename or _id in self.to_delete:
|
||||||
item.setData(Qt.DisplayRole, tag)
|
item.setData(Qt.DisplayRole, tag)
|
||||||
self.table.setItem(row, 2, item)
|
self.table.setItem(row, 2, item)
|
||||||
self.table.blockSignals(False)
|
|
||||||
return select_item
|
|
||||||
|
|
||||||
def all_matching_clicked(self):
|
if self.last_sorted_by == 'name':
|
||||||
for i in range(0, self.table.rowCount()):
|
self.table.sortByColumn(0, self.name_order)
|
||||||
item = self.table.item(i, 0)
|
elif self.last_sorted_by == 'count':
|
||||||
tag = item.initial_text()
|
self.table.sortByColumn(1, self.count_order)
|
||||||
self.all_tags[tag]['cur_name'] = item.text()
|
else:
|
||||||
self.all_tags[tag]['is_deleted'] = item.is_deleted
|
self.table.sortByColumn(2, self.was_order)
|
||||||
search_for = icu_lower(unicode_type(self.search_box.text()))
|
|
||||||
if len(search_for) == 0:
|
if select_item is not None:
|
||||||
|
self.table.setCurrentItem(select_item)
|
||||||
|
self.start_find_pos = select_item.row()
|
||||||
|
else:
|
||||||
|
self.table.setCurrentCell(0, 0)
|
||||||
|
self.start_find_pos = -1
|
||||||
|
self.table.blockSignals(False)
|
||||||
|
|
||||||
|
def not_found_label_timer_event(self):
|
||||||
|
self.not_found_label.setVisible(False)
|
||||||
|
|
||||||
|
def clear_filter(self):
|
||||||
|
self.filter_box.setText('')
|
||||||
|
self.fill_in_table(None, None)
|
||||||
|
|
||||||
|
def do_filter(self):
|
||||||
self.fill_in_table(None, None)
|
self.fill_in_table(None, None)
|
||||||
result = []
|
|
||||||
for k in self.ordered_tags:
|
|
||||||
tag = self.all_tags[k]
|
|
||||||
if (
|
|
||||||
search_for in icu_lower(unicode_type(tag['cur_name'])) or
|
|
||||||
search_for in icu_lower(unicode_type(self.original_names.get(tag['key'], '')))
|
|
||||||
):
|
|
||||||
result.append(k)
|
|
||||||
self.fill_in_table(result, None)
|
|
||||||
|
|
||||||
def table_column_resized(self, col, old, new):
|
def table_column_resized(self, col, old, new):
|
||||||
self.table_column_widths = []
|
self.table_column_widths = []
|
||||||
@ -445,37 +500,23 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
|||||||
if row >= 0:
|
if row >= 0:
|
||||||
self.table.scrollToItem(self.table.item(row, 0))
|
self.table.scrollToItem(self.table.item(row, 0))
|
||||||
|
|
||||||
def header_clicked(self, idx):
|
def do_sort(self, section):
|
||||||
if idx == 0:
|
(self.do_sort_by_name, self.do_sort_by_count, self.do_sort_by_was)[section]()
|
||||||
self.do_sort_by_name()
|
|
||||||
elif idx == 1:
|
|
||||||
self.do_sort_by_count()
|
|
||||||
else:
|
|
||||||
self.do_sort_by_was()
|
|
||||||
|
|
||||||
def do_sort_by_name(self):
|
def do_sort_by_name(self):
|
||||||
self.name_order = 1 if self.name_order == 0 else 0
|
self.name_order = 1 - self.name_order
|
||||||
|
self.last_sorted_by = 'name'
|
||||||
self.table.sortByColumn(0, self.name_order)
|
self.table.sortByColumn(0, self.name_order)
|
||||||
self.name_col.setIcon(self.down_arrow_icon if self.name_order
|
|
||||||
else self.up_arrow_icon)
|
|
||||||
self.count_col.setIcon(self.blank_icon)
|
|
||||||
self.was_col.setIcon(self.blank_icon)
|
|
||||||
|
|
||||||
def do_sort_by_count(self):
|
def do_sort_by_count(self):
|
||||||
self.count_order = 1 if self.count_order == 0 else 0
|
self.count_order = 1 - self.count_order
|
||||||
|
self.last_sorted_by = 'count'
|
||||||
self.table.sortByColumn(1, self.count_order)
|
self.table.sortByColumn(1, self.count_order)
|
||||||
self.count_col.setIcon(self.down_arrow_icon if self.count_order
|
|
||||||
else self.up_arrow_icon)
|
|
||||||
self.name_col.setIcon(self.blank_icon)
|
|
||||||
self.was_col.setIcon(self.blank_icon)
|
|
||||||
|
|
||||||
def do_sort_by_was(self):
|
def do_sort_by_was(self):
|
||||||
self.was_order = 1 if self.was_order == 0 else 0
|
self.was_order = 1 - self.was_order
|
||||||
|
self.last_sorted_by = 'count'
|
||||||
self.table.sortByColumn(2, self.was_order)
|
self.table.sortByColumn(2, self.was_order)
|
||||||
self.was_col.setIcon(self.down_arrow_icon if self.was_order
|
|
||||||
else self.up_arrow_icon)
|
|
||||||
self.name_col.setIcon(self.blank_icon)
|
|
||||||
self.count_col.setIcon(self.blank_icon)
|
|
||||||
|
|
||||||
def accepted(self):
|
def accepted(self):
|
||||||
self.save_geometry()
|
self.save_geometry()
|
||||||
|
@ -18,9 +18,7 @@
|
|||||||
<normaloff>:/images/chapters.png</normaloff>:/images/chapters.png</iconset>
|
<normaloff>:/images/chapters.png</normaloff>:/images/chapters.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout">
|
<layout class="QGridLayout">
|
||||||
<item row="0" column="0" colspan="2">
|
<item row="0" column="0">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_11">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Search for:</string>
|
<string>&Search for:</string>
|
||||||
@ -30,29 +28,29 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="0" column="1">
|
||||||
<widget class="HistoryLineEdit" name="search_box">
|
<widget class="HistoryLineEdit" name="search_box">
|
||||||
<property name="sizePolicy">
|
<property name="minimumSize">
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
<size>
|
||||||
<horstretch>100</horstretch>
|
<width>200</width>
|
||||||
<verstretch>0</verstretch>
|
<height>0</height>
|
||||||
</sizepolicy>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Search for an item in the Tag column</string>
|
<string>Search for an item in the first column</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="clearButtonEnabled">
|
<property name="clearButtonEnabled">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="0" column="2">
|
||||||
<widget class="QPushButton" name="search_button">
|
<widget class="QPushButton" name="search_button">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Display items containing the search string</string>
|
<string>Find items containing the search string</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Find</string>
|
<string>S&earch</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../../../../resources/images.qrc">
|
<iconset resource="../../../../resources/images.qrc">
|
||||||
@ -60,9 +58,20 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
<item row="0" column="3">
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0" colspan="3">
|
<item row="0" column="4">
|
||||||
<widget class="QCheckBox" name="apply_vl_checkbox">
|
<widget class="QCheckBox" name="apply_vl_checkbox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><p>Show items only if they appear in the
|
<string><p>Show items only if they appear in the
|
||||||
@ -70,7 +79,47 @@
|
|||||||
not be forgotten.</p></string>
|
not be forgotten.</p></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Show only available items in current Virtual library</string>
|
<string>Only show items in the current &virtual library</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Filter by:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>filter_box</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="HistoryLineEdit" name="filter_box">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>200</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Filter items using the text in this box</string>
|
||||||
|
</property>
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QPushButton" name="filter_button">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Show only items containing this text</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>F&ilter</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../../../resources/images.qrc">
|
||||||
|
<normaloff>:/images/search.png</normaloff>:/images/search.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -147,7 +196,7 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="2" column="1" colspan="4">
|
||||||
<widget class="QTableWidget" name="table">
|
<widget class="QTableWidget" name="table">
|
||||||
<property name="alternatingRowColors">
|
<property name="alternatingRowColors">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
@ -160,7 +209,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0" colspan="2">
|
<item row="3" column="0" colspan="5">
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
<property name="standardButtons">
|
<property name="standardButtons">
|
||||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user