Catalogs: CSV Output: Allow changing the order of fields in the generated CSV catalog by using drag and drop to re-arrange the fields in the create catalog dialog. Fixes #1379048 [[Enhancement] Specify column order in csv calalogue](https://bugs.launchpad.net/calibre/+bug/1379048)

This commit is contained in:
Kovid Goyal 2014-10-09 09:37:32 +05:30
parent 713153a965
commit 4404b6ff95
3 changed files with 55 additions and 81 deletions

View File

@ -474,7 +474,7 @@ class CatalogPlugin(Plugin): # {{{
return db.get_data_as_dict(ids=opts.ids)
def get_output_fields(self, db, opts):
# Return a list of requested fields, with opts.sort_by first
# Return a list of requested fields
all_std_fields = set(
['author_sort','authors','comments','cover','formats',
'id','isbn','library_name','ondevice','pubdate','publisher',
@ -489,7 +489,8 @@ class CatalogPlugin(Plugin): # {{{
if opts.fields != 'all':
# Make a list from opts.fields
requested_fields = set(opts.fields.split(','))
of = [x.strip() for x in opts.fields.split(',')]
requested_fields = set(of)
# Validate requested_fields
if requested_fields - all_fields:
@ -500,16 +501,13 @@ class CatalogPlugin(Plugin): # {{{
(current_library_name(), ', '.join(sorted(list(all_fields)))))
raise ValueError("unable to generate catalog with specified fields")
fields = list(all_fields & requested_fields)
fields = [x for x in of if x in all_fields]
else:
fields = list(all_fields)
fields = sorted(all_fields, key=self._field_sorter)
if not opts.connected_device['is_device_connected'] and 'ondevice' in fields:
fields.pop(int(fields.index('ondevice')))
fields = sorted(fields, key=self._field_sorter)
if opts.sort_by and opts.sort_by in fields:
fields.insert(0,fields.pop(int(fields.index(opts.sort_by))))
return fields
def initialize(self):

View File

@ -7,11 +7,10 @@ __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from calibre.gui2 import gprefs
from calibre.gui2.catalog.catalog_csv_xml_ui import Ui_Form
from calibre.library import db as db_
from PyQt5.Qt import QWidget, QListWidgetItem
from calibre.gui2.ui import get_gui
from PyQt5.Qt import QWidget, QListWidgetItem, Qt, QVBoxLayout, QLabel, QListWidget
class PluginWidget(QWidget, Ui_Form):
class PluginWidget(QWidget):
TITLE = _('CSV/XML Options')
HELP = _('Options specific to')+' CSV/XML '+_('output')
@ -20,42 +19,66 @@ class PluginWidget(QWidget, Ui_Form):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setupUi(self)
self.l = l = QVBoxLayout(self)
self.la = la = QLabel(_('Fields to include in output:'))
la.setWordWrap(True)
l.addWidget(la)
self.db_fields = QListWidget(self)
l.addWidget(self.db_fields)
self.la2 = la = QLabel(_('Drag and drop to re-arrange fields'))
l.addWidget(la)
self.db_fields.setDragEnabled(True)
self.db_fields.setDragDropMode(QListWidget.InternalMove)
self.db_fields.setDefaultDropAction(Qt.MoveAction)
self.db_fields.setAlternatingRowColors(True)
self.db_fields.setObjectName("db_fields")
def initialize(self, catalog_name, db):
self.name = catalog_name
from calibre.library.catalogs import FIELDS
self.all_fields = []
for x in FIELDS:
if x != 'all':
self.all_fields.append(x)
QListWidgetItem(x, self.db_fields)
db = get_gui().current_db
self.all_fields = {x for x in FIELDS if x != 'all'} | set(db.custom_field_keys())
sort_order = gprefs.get(self.name + '_db_fields_sort_order', {})
fm = db.field_metadata
db = db_()
for x in sorted(db.custom_field_keys()):
self.all_fields.append(x)
QListWidgetItem(x, self.db_fields)
def name(x):
if x == 'isbn':
return 'ISBN'
if x == 'library_name':
return _('Library Name')
if x.endswith('_index'):
return name(x[:-len('_index')]) + ' ' + _('Number')
return fm[x].get('name') or x
fm = db.field_metadata[x]
if fm['datatype'] == 'series':
QListWidgetItem(x+'_index', self.db_fields)
def key(x):
return (sort_order.get(x, 10000), name(x))
self.db_fields.clear()
for x in sorted(self.all_fields, key=key):
QListWidgetItem(name(x) + ' (%s)' % x, self.db_fields).setData(Qt.UserRole, x)
if x.startswith('#') and fm[x]['datatype'] == 'series':
x += '_index'
QListWidgetItem(name(x) + ' (%s)' % x, self.db_fields).setData(Qt.UserRole, x)
def initialize(self, name, db):
self.name = name
fields = gprefs.get(name+'_db_fields', self.all_fields)
# Restore the activated fields from last use
fields = frozenset(gprefs.get(self.name+'_db_fields', self.all_fields))
for x in range(self.db_fields.count()):
item = self.db_fields.item(x)
item.setSelected(unicode(item.text()) in fields)
item.setCheckState(Qt.Checked if unicode(item.data(Qt.UserRole)) in fields else Qt.Unchecked)
def options(self):
# Save the currently activated fields
fields = []
for x in range(self.db_fields.count()):
fields, all_fields = [], []
for x in xrange(self.db_fields.count()):
item = self.db_fields.item(x)
if item.isSelected():
fields.append(unicode(item.text()))
all_fields.append(unicode(item.data(Qt.UserRole)))
if item.checkState() == Qt.Checked:
fields.append(unicode(item.data(Qt.UserRole)))
gprefs.set(self.name+'_db_fields', fields)
gprefs.set(self.name + '_db_fields_sort_order', {x:i for i, x in enumerate(all_fields)})
# Return a dictionary with current options for this widget
if len(self.db_fields.selectedItems()):
return {'fields':[unicode(i.text()) for i in self.db_fields.selectedItems()]}
if len(fields):
return {'fields':fields}
else:
return {'fields':['all']}

View File

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>579</width>
<height>411</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Fields to include in output:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QListWidget" name="db_fields">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string extracomment="Select all fields to be exported"/>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>