mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Make the Manage Tags/Publishers/etc. dialog show a column with counts for each item, to easily sort by number of items
This commit is contained in:
commit
b0d4315372
@ -13,7 +13,7 @@ from PyQt4.Qt import Qt, QMenu, QModelIndex, QTimer
|
||||
from calibre.gui2 import error_dialog, Dispatcher, question_dialog
|
||||
from calibre.gui2.dialogs.metadata_bulk import MetadataBulkDialog
|
||||
from calibre.gui2.dialogs.confirm_delete import confirm
|
||||
from calibre.gui2.dialogs.tag_list_editor import TagListEditor
|
||||
from calibre.gui2.dialogs.device_category_editor import DeviceCategoryEditor
|
||||
from calibre.gui2.actions import InterfaceAction
|
||||
from calibre.ebooks.metadata import authors_to_string
|
||||
from calibre.utils.icu import sort_key
|
||||
@ -441,7 +441,7 @@ class EditMetadataAction(InterfaceAction):
|
||||
def edit_device_collections(self, view, oncard=None):
|
||||
model = view.model()
|
||||
result = model.get_collections_with_ids()
|
||||
d = TagListEditor(self.gui, tag_to_match=None, data=result, key=sort_key)
|
||||
d = DeviceCategoryEditor(self.gui, tag_to_match=None, data=result, key=sort_key)
|
||||
d.exec_()
|
||||
if d.result() == d.Accepted:
|
||||
to_rename = d.to_rename # dict of new text to old ids
|
||||
|
124
src/calibre/gui2/dialogs/device_category_editor.py
Normal file
124
src/calibre/gui2/dialogs/device_category_editor.py
Normal file
@ -0,0 +1,124 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
from PyQt4.QtCore import Qt, QString
|
||||
from PyQt4.QtGui import QDialog, QListWidgetItem
|
||||
|
||||
from calibre.gui2.dialogs.device_category_editor_ui import Ui_DeviceCategoryEditor
|
||||
from calibre.gui2 import question_dialog, error_dialog
|
||||
|
||||
class ListWidgetItem(QListWidgetItem):
|
||||
|
||||
def __init__(self, txt):
|
||||
QListWidgetItem.__init__(self, txt)
|
||||
self.initial_value = QString(txt)
|
||||
self.current_value = QString(txt)
|
||||
self.previous_value = QString(txt)
|
||||
|
||||
def data(self, role):
|
||||
if role == Qt.DisplayRole:
|
||||
if self.initial_value != self.current_value:
|
||||
return _('%(curr)s (was %(initial)s)')%dict(
|
||||
curr=self.current_value, initial=self.initial_value)
|
||||
else:
|
||||
return self.current_value
|
||||
elif role == Qt.EditRole:
|
||||
return self.current_value
|
||||
else:
|
||||
return QListWidgetItem.data(self, role)
|
||||
|
||||
def setData(self, role, data):
|
||||
if role == Qt.EditRole:
|
||||
self.previous_value = self.current_value
|
||||
self.current_value = data.toString()
|
||||
QListWidgetItem.setData(self, role, data)
|
||||
|
||||
def text(self):
|
||||
return self.current_value
|
||||
|
||||
def initial_text(self):
|
||||
return self.initial_value
|
||||
|
||||
def previous_text(self):
|
||||
return self.previous_value
|
||||
|
||||
def setText(self, txt):
|
||||
self.current_value = txt
|
||||
QListWidgetItem.setText(txt)
|
||||
|
||||
class DeviceCategoryEditor(QDialog, Ui_DeviceCategoryEditor):
|
||||
|
||||
def __init__(self, window, tag_to_match, data, key):
|
||||
QDialog.__init__(self, window)
|
||||
Ui_DeviceCategoryEditor.__init__(self)
|
||||
self.setupUi(self)
|
||||
# Remove help icon on title bar
|
||||
icon = self.windowIcon()
|
||||
self.setWindowFlags(self.windowFlags()&(~Qt.WindowContextHelpButtonHint))
|
||||
self.setWindowIcon(icon)
|
||||
|
||||
self.to_rename = {}
|
||||
self.to_delete = set([])
|
||||
self.original_names = {}
|
||||
self.all_tags = {}
|
||||
|
||||
for k,v in data:
|
||||
self.all_tags[v] = k
|
||||
self.original_names[k] = v
|
||||
for tag in sorted(self.all_tags.keys(), key=key):
|
||||
item = ListWidgetItem(tag)
|
||||
item.setData(Qt.UserRole, self.all_tags[tag])
|
||||
item.setFlags (item.flags() | Qt.ItemIsEditable)
|
||||
self.available_tags.addItem(item)
|
||||
|
||||
if tag_to_match is not None:
|
||||
items = self.available_tags.findItems(tag_to_match, Qt.MatchExactly)
|
||||
if len(items) == 1:
|
||||
self.available_tags.setCurrentItem(items[0])
|
||||
|
||||
self.delete_button.clicked.connect(self.delete_tags)
|
||||
self.rename_button.clicked.connect(self.rename_tag)
|
||||
self.available_tags.itemDoubleClicked.connect(self._rename_tag)
|
||||
self.available_tags.itemChanged.connect(self.finish_editing)
|
||||
|
||||
def finish_editing(self, item):
|
||||
if not item.text():
|
||||
error_dialog(self, _('Item is blank'),
|
||||
_('An item cannot be set to nothing. Delete it instead.')).exec_()
|
||||
item.setText(item.previous_text())
|
||||
return
|
||||
if item.text() != item.initial_text():
|
||||
id_ = item.data(Qt.UserRole).toInt()[0]
|
||||
self.to_rename[id_] = unicode(item.text())
|
||||
|
||||
def rename_tag(self):
|
||||
item = self.available_tags.currentItem()
|
||||
self._rename_tag(item)
|
||||
|
||||
def _rename_tag(self, item):
|
||||
if item is None:
|
||||
error_dialog(self, _('No item selected'),
|
||||
_('You must select one item from the list of Available items.')).exec_()
|
||||
return
|
||||
self.available_tags.editItem(item)
|
||||
|
||||
def delete_tags(self):
|
||||
deletes = self.available_tags.selectedItems()
|
||||
if not deletes:
|
||||
error_dialog(self, _('No items selected'),
|
||||
_('You must select at least one item from the list.')).exec_()
|
||||
return
|
||||
ct = ', '.join([unicode(item.text()) for item in deletes])
|
||||
if not question_dialog(self, _('Are you sure?'),
|
||||
'<p>'+_('Are you sure you want to delete the following items?')+'<br>'+ct):
|
||||
return
|
||||
row = self.available_tags.row(deletes[0])
|
||||
for item in deletes:
|
||||
(id,ign) = item.data(Qt.UserRole).toInt()
|
||||
self.to_delete.add(id)
|
||||
self.available_tags.takeItem(self.available_tags.row(item))
|
||||
|
||||
if row >= self.available_tags.count():
|
||||
row = self.available_tags.count() - 1
|
||||
if row >= 0:
|
||||
self.available_tags.scrollToItem(self.available_tags.item(row))
|
166
src/calibre/gui2/dialogs/device_category_editor.ui
Normal file
166
src/calibre/gui2/dialogs/device_category_editor.ui
Normal file
@ -0,0 +1,166 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DeviceCategoryEditor</class>
|
||||
<widget class="QDialog" name="DeviceCategoryEditor">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>397</width>
|
||||
<height>335</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Category Editor</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset>
|
||||
<normaloff>:/images/chapters.png</normaloff>:/images/chapters.png</iconset>
|
||||
</property>
|
||||
<layout class="QGridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Items in use</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>available_tags</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QToolButton" name="delete_button">
|
||||
<property name="toolTip">
|
||||
<string>Delete item from database. This will unapply the item from all books and then remove it from the database.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/images/trash.png</normaloff>:/images/trash.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="rename_button">
|
||||
<property name="toolTip">
|
||||
<string>Rename the item in every book where it is used.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/images/edit_input.png</normaloff>:/images/edit_input.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+S</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="available_tags">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
<property name="centerButtons">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>DeviceCategoryEditor</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>DeviceCategoryEditor</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@ -1,16 +1,17 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
from PyQt4.QtCore import Qt, QString
|
||||
from PyQt4.QtGui import QDialog, QListWidgetItem
|
||||
from PyQt4.Qt import (Qt, QDialog, QTableWidgetItem, QIcon, QByteArray,
|
||||
QString, QSize)
|
||||
|
||||
from calibre.gui2.dialogs.tag_list_editor_ui import Ui_TagListEditor
|
||||
from calibre.gui2 import question_dialog, error_dialog
|
||||
from calibre.gui2 import question_dialog, error_dialog, gprefs
|
||||
from calibre.utils.icu import sort_key
|
||||
|
||||
class ListWidgetItem(QListWidgetItem):
|
||||
class NameTableWidgetItem(QTableWidgetItem):
|
||||
|
||||
def __init__(self, txt):
|
||||
QListWidgetItem.__init__(self, txt)
|
||||
QTableWidgetItem.__init__(self, txt)
|
||||
self.initial_value = QString(txt)
|
||||
self.current_value = QString(txt)
|
||||
self.previous_value = QString(txt)
|
||||
@ -25,13 +26,13 @@ class ListWidgetItem(QListWidgetItem):
|
||||
elif role == Qt.EditRole:
|
||||
return self.current_value
|
||||
else:
|
||||
return QListWidgetItem.data(self, role)
|
||||
return QTableWidgetItem.data(self, role)
|
||||
|
||||
def setData(self, role, data):
|
||||
if role == Qt.EditRole:
|
||||
self.previous_value = self.current_value
|
||||
self.current_value = data.toString()
|
||||
QListWidgetItem.setData(self, role, data)
|
||||
QTableWidgetItem.setData(self, role, data)
|
||||
|
||||
def text(self):
|
||||
return self.current_value
|
||||
@ -44,42 +45,138 @@ class ListWidgetItem(QListWidgetItem):
|
||||
|
||||
def setText(self, txt):
|
||||
self.current_value = txt
|
||||
QListWidgetItem.setText(txt)
|
||||
QTableWidgetItem.setText(txt)
|
||||
|
||||
def __ge__(self, other):
|
||||
return sort_key(unicode(self.text())) >= sort_key(unicode(other.text()))
|
||||
|
||||
def __lt__(self, other):
|
||||
return sort_key(unicode(self.text())) < sort_key(unicode(other.text()))
|
||||
|
||||
class CountTableWidgetItem(QTableWidgetItem):
|
||||
|
||||
def __init__(self, count):
|
||||
QTableWidgetItem.__init__(self, str(count))
|
||||
self._count = count
|
||||
|
||||
def __ge__(self, other):
|
||||
return self._count >= other._count
|
||||
|
||||
def __lt__(self, other):
|
||||
return self._count < other._count
|
||||
|
||||
|
||||
class TagListEditor(QDialog, Ui_TagListEditor):
|
||||
|
||||
def __init__(self, window, tag_to_match, data, key):
|
||||
def __init__(self, window, cat_name, tag_to_match, data, sorter):
|
||||
QDialog.__init__(self, window)
|
||||
Ui_TagListEditor.__init__(self)
|
||||
self.setupUi(self)
|
||||
|
||||
# Put the category name into the title bar
|
||||
t = self.windowTitle()
|
||||
self.setWindowTitle(t + ' (' + cat_name + ')')
|
||||
# Remove help icon on title bar
|
||||
icon = self.windowIcon()
|
||||
self.setWindowFlags(self.windowFlags()&(~Qt.WindowContextHelpButtonHint))
|
||||
self.setWindowIcon(icon)
|
||||
|
||||
# Get saved geometry info
|
||||
try:
|
||||
self.table_column_widths = \
|
||||
gprefs.get('tag_list_editor_table_widths', None)
|
||||
except:
|
||||
pass
|
||||
|
||||
# initialization
|
||||
self.to_rename = {}
|
||||
self.to_delete = set([])
|
||||
self.original_names = {}
|
||||
self.all_tags = {}
|
||||
self.counts = {}
|
||||
|
||||
for k,v in data:
|
||||
for k,v,count in data:
|
||||
self.all_tags[v] = k
|
||||
self.counts[v] = count
|
||||
self.original_names[k] = v
|
||||
for tag in sorted(self.all_tags.keys(), key=key):
|
||||
item = ListWidgetItem(tag)
|
||||
item.setData(Qt.UserRole, self.all_tags[tag])
|
||||
item.setFlags (item.flags() | Qt.ItemIsEditable)
|
||||
self.available_tags.addItem(item)
|
||||
|
||||
if tag_to_match is not None:
|
||||
items = self.available_tags.findItems(tag_to_match, Qt.MatchExactly)
|
||||
if len(items) == 1:
|
||||
self.available_tags.setCurrentItem(items[0])
|
||||
# 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'))
|
||||
|
||||
self.table.setColumnCount(2)
|
||||
self.name_col = QTableWidgetItem(_('Tag'))
|
||||
self.table.setHorizontalHeaderItem(0, self.name_col)
|
||||
self.name_col.setIcon(self.up_arrow_icon)
|
||||
self.count_col = QTableWidgetItem(_('Count'))
|
||||
self.table.setHorizontalHeaderItem(1, self.count_col)
|
||||
self.count_col.setIcon(self.blank_icon)
|
||||
|
||||
# Capture clicks on the horizontal header to sort the table columns
|
||||
hh = self.table.horizontalHeader();
|
||||
hh.setClickable(True)
|
||||
hh.sectionClicked.connect(self.header_clicked)
|
||||
hh.sectionResized.connect(self.table_column_resized)
|
||||
self.name_order = 0
|
||||
self.count_order = 1
|
||||
|
||||
# Add the data
|
||||
select_item = None
|
||||
self.table.setRowCount(len(self.all_tags))
|
||||
for row,tag in enumerate(sorted(self.all_tags.keys(), key=sorter)):
|
||||
item = NameTableWidgetItem(tag)
|
||||
item.setData(Qt.UserRole, self.all_tags[tag])
|
||||
item.setFlags (item.flags() | Qt.ItemIsSelectable | Qt.ItemIsEditable)
|
||||
self.table.setItem(row, 0, item)
|
||||
if tag == tag_to_match:
|
||||
select_item = item
|
||||
item = CountTableWidgetItem(self.counts[tag])
|
||||
# only the name column can be selected
|
||||
item.setFlags (item.flags() & ~Qt.ItemIsSelectable)
|
||||
self.table.setItem(row, 1, item)
|
||||
|
||||
# Scroll to the selected item if there is one
|
||||
if select_item is not None:
|
||||
self.table.setCurrentItem(select_item)
|
||||
|
||||
self.delete_button.clicked.connect(self.delete_tags)
|
||||
self.rename_button.clicked.connect(self.rename_tag)
|
||||
self.available_tags.itemDoubleClicked.connect(self._rename_tag)
|
||||
self.available_tags.itemChanged.connect(self.finish_editing)
|
||||
self.table.itemDoubleClicked.connect(self._rename_tag)
|
||||
self.table.itemChanged.connect(self.finish_editing)
|
||||
self.buttonBox.accepted.connect(self.accepted)
|
||||
|
||||
try:
|
||||
geom = gprefs.get('tag_list_editor_dialog_geometry', None)
|
||||
if geom is not None:
|
||||
self.restoreGeometry(QByteArray(geom))
|
||||
else:
|
||||
self.resize(self.sizeHint()+QSize(150, 100))
|
||||
except:
|
||||
pass
|
||||
|
||||
def table_column_resized(self, col, old, new):
|
||||
self.table_column_widths = []
|
||||
for c in range(0, self.table.columnCount()):
|
||||
self.table_column_widths.append(self.table.columnWidth(c))
|
||||
|
||||
def resizeEvent(self, *args):
|
||||
QDialog.resizeEvent(self, *args)
|
||||
if self.table_column_widths is not None:
|
||||
for c,w in enumerate(self.table_column_widths):
|
||||
self.table.setColumnWidth(c, w)
|
||||
else:
|
||||
# the vertical scroll bar might not be rendered, so might not yet
|
||||
# have a width. Assume 25. Not a problem because user-changed column
|
||||
# widths will be remembered
|
||||
w = self.table.width() - 25 - self.table.verticalHeader().width()
|
||||
w /= self.table.columnCount()
|
||||
for c in range(0, self.table.columnCount()):
|
||||
self.table.setColumnWidth(c, w)
|
||||
|
||||
def save_geometry(self):
|
||||
gprefs['tag_list_editor_table_widths'] = self.table_column_widths
|
||||
gprefs['tag_list_editor_dialog_geometry'] = bytearray(self.saveGeometry())
|
||||
|
||||
def finish_editing(self, item):
|
||||
if not item.text():
|
||||
@ -92,7 +189,7 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
||||
self.to_rename[id_] = unicode(item.text())
|
||||
|
||||
def rename_tag(self):
|
||||
item = self.available_tags.currentItem()
|
||||
item = self.table.item(self.table.currentRow(), 0)
|
||||
self._rename_tag(item)
|
||||
|
||||
def _rename_tag(self, item):
|
||||
@ -100,25 +197,48 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
||||
error_dialog(self, _('No item selected'),
|
||||
_('You must select one item from the list of Available items.')).exec_()
|
||||
return
|
||||
self.available_tags.editItem(item)
|
||||
self.table.editItem(item)
|
||||
|
||||
def delete_tags(self):
|
||||
deletes = self.available_tags.selectedItems()
|
||||
deletes = self.table.selectedItems()
|
||||
if not deletes:
|
||||
error_dialog(self, _('No items selected'),
|
||||
_('You must select at least one items from the list.')).exec_()
|
||||
_('You must select at least one item from the list.')).exec_()
|
||||
return
|
||||
ct = ', '.join([unicode(item.text()) for item in deletes])
|
||||
if not question_dialog(self, _('Are your sure?'),
|
||||
'<p>'+_('Are you certain you want to delete the following items?')+'<br>'+ct):
|
||||
if not question_dialog(self, _('Are you sure?'),
|
||||
'<p>'+_('Are you sure you want to delete the following items?')+'<br>'+ct):
|
||||
return
|
||||
row = self.available_tags.row(deletes[0])
|
||||
row = self.table.row(deletes[0])
|
||||
for item in deletes:
|
||||
(id,ign) = item.data(Qt.UserRole).toInt()
|
||||
self.to_delete.add(id)
|
||||
self.available_tags.takeItem(self.available_tags.row(item))
|
||||
self.table.removeRow(self.table.row(item))
|
||||
|
||||
if row >= self.available_tags.count():
|
||||
row = self.available_tags.count() - 1
|
||||
if row >= self.table.rowCount():
|
||||
row = self.table.rowCount() - 1
|
||||
if row >= 0:
|
||||
self.available_tags.scrollToItem(self.available_tags.item(row))
|
||||
self.table.scrollToItem(self.table.item(row, 0))
|
||||
|
||||
def header_clicked(self, idx):
|
||||
if idx == 0:
|
||||
self.do_sort_by_name()
|
||||
else:
|
||||
self.do_sort_by_count()
|
||||
|
||||
def do_sort_by_name(self):
|
||||
self.name_order = 1 if self.name_order == 0 else 0
|
||||
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)
|
||||
|
||||
def do_sort_by_count (self):
|
||||
self.count_order = 1 if self.count_order == 0 else 0
|
||||
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)
|
||||
|
||||
def accepted(self):
|
||||
self.save_geometry()
|
||||
|
@ -20,33 +20,6 @@
|
||||
<layout class="QGridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Items in use</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>available_tags</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
@ -97,7 +70,7 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="available_tags">
|
||||
<widget class="QTableWidget" name="table">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
|
@ -500,6 +500,7 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
if i < len(components)-1:
|
||||
t = copy.copy(tag)
|
||||
t.original_name = '.'.join(components[:i+1])
|
||||
t.count = 0
|
||||
if key != 'search':
|
||||
# This 'manufactured' intermediate node can
|
||||
# be searched, but cannot be edited.
|
||||
@ -524,6 +525,12 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
for category in self.category_nodes:
|
||||
process_one_node(category, state_map.get(category.category_key, {}))
|
||||
|
||||
def get_category_editor_data(self, category):
|
||||
for cat in self.root_item.children:
|
||||
if cat.category_key == category:
|
||||
return [(t.tag.id, t.tag.original_name, t.tag.count)
|
||||
for t in cat.child_tags() if t.tag.count > 0]
|
||||
|
||||
# Drag'n Drop {{{
|
||||
def mimeTypes(self):
|
||||
return ["application/calibre+from_library",
|
||||
|
@ -196,26 +196,20 @@ class TagBrowserMixin(object): # {{{
|
||||
Open the 'manage_X' dialog where X == category. If tag is not None, the
|
||||
dialog will position the editor on that item.
|
||||
'''
|
||||
db=self.library_view.model().db
|
||||
if category == 'tags':
|
||||
result = db.get_tags_with_ids()
|
||||
key = sort_key
|
||||
elif category == 'series':
|
||||
result = db.get_series_with_ids()
|
||||
|
||||
tags_model = self.tags_view.model()
|
||||
result = tags_model.get_category_editor_data(category)
|
||||
if result is None:
|
||||
return
|
||||
|
||||
if category == 'series':
|
||||
key = lambda x:sort_key(title_sort(x))
|
||||
elif category == 'publisher':
|
||||
result = db.get_publishers_with_ids()
|
||||
key = sort_key
|
||||
else: # should be a custom field
|
||||
cc_label = None
|
||||
if category in db.field_metadata:
|
||||
cc_label = db.field_metadata[category]['label']
|
||||
result = db.get_custom_items_with_ids(label=cc_label)
|
||||
else:
|
||||
result = []
|
||||
else:
|
||||
key = sort_key
|
||||
|
||||
d = TagListEditor(self, tag_to_match=tag, data=result, key=key)
|
||||
db=self.library_view.model().db
|
||||
d = TagListEditor(self, cat_name=db.field_metadata[category]['name'],
|
||||
tag_to_match=tag, data=result, sorter=key)
|
||||
d.exec_()
|
||||
if d.result() == d.Accepted:
|
||||
to_rename = d.to_rename # dict of old id to new name
|
||||
@ -232,7 +226,8 @@ class TagBrowserMixin(object): # {{{
|
||||
elif category == 'publisher':
|
||||
rename_func = db.rename_publisher
|
||||
delete_func = db.delete_publisher_using_id
|
||||
else:
|
||||
else: # must be custom
|
||||
cc_label = db.field_metadata[category]['label']
|
||||
rename_func = partial(db.rename_custom_item, label=cc_label)
|
||||
delete_func = partial(db.delete_custom_item_using_id, label=cc_label)
|
||||
m = self.tags_view.model()
|
||||
|
@ -1810,6 +1810,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
for t in categories[sc]:
|
||||
user_categories[c].append([t.name, sc, 0])
|
||||
|
||||
gst_icon = icon_map['gst'] if icon_map else None
|
||||
for user_cat in sorted(user_categories.keys(), key=sort_key):
|
||||
items = []
|
||||
names_seen = {}
|
||||
@ -1825,7 +1826,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
t.tooltip = t.tooltip.replace(')', ', ' + label + ')')
|
||||
else:
|
||||
t = copy.copy(taglist[label][n])
|
||||
t.icon = icon_map['gst']
|
||||
t.icon = gst_icon
|
||||
names_seen[t.name] = t
|
||||
items.append(t)
|
||||
else:
|
||||
|
Loading…
x
Reference in New Issue
Block a user