mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
pluginize installs again
This commit is contained in:
parent
dc0cf57755
commit
6fe1590813
@ -34,7 +34,7 @@ class PdbHeaderReader(object):
|
|||||||
def full_section_info(self, number):
|
def full_section_info(self, number):
|
||||||
if number not in range(0, self.num_sections):
|
if number not in range(0, self.num_sections):
|
||||||
raise ValueError('Not a valid section number %i' % number)
|
raise ValueError('Not a valid section number %i' % number)
|
||||||
|
|
||||||
self.stream.seek(78+number*8)
|
self.stream.seek(78+number*8)
|
||||||
offset, a1, a2, a3, a4 = struct.unpack('>LBBBB', self.stream.read(8))[0]
|
offset, a1, a2, a3, a4 = struct.unpack('>LBBBB', self.stream.read(8))[0]
|
||||||
flags, val = a1, a2<<16 | a3<<8 | a4
|
flags, val = a1, a2<<16 | a3<<8 | a4
|
||||||
@ -43,14 +43,14 @@ class PdbHeaderReader(object):
|
|||||||
def section_offset(self, number):
|
def section_offset(self, number):
|
||||||
if number not in range(0, self.num_sections):
|
if number not in range(0, self.num_sections):
|
||||||
raise ValueError('Not a valid section number %i' % number)
|
raise ValueError('Not a valid section number %i' % number)
|
||||||
|
|
||||||
self.stream.seek(78+number*8)
|
self.stream.seek(78+number*8)
|
||||||
return struct.unpack('>LBBBB', self.stream.read(8))[0]
|
return struct.unpack('>LBBBB', self.stream.read(8))[0]
|
||||||
|
|
||||||
def section_data(self, number):
|
def section_data(self, number):
|
||||||
if number not in range(0, self.num_sections):
|
if number not in range(0, self.num_sections):
|
||||||
raise ValueError('Not a valid section number %i' % number)
|
raise ValueError('Not a valid section number %i' % number)
|
||||||
|
|
||||||
start = self.section_offset(number)
|
start = self.section_offset(number)
|
||||||
if number == self.num_sections -1:
|
if number == self.num_sections -1:
|
||||||
end = os.stat(self.stream.name).st_size
|
end = os.stat(self.stream.name).st_size
|
||||||
@ -65,13 +65,13 @@ class PdbHeaderWriter(object):
|
|||||||
def __init__(self, identity, title):
|
def __init__(self, identity, title):
|
||||||
self.identity = identity[:8]
|
self.identity = identity[:8]
|
||||||
self.title = title.ljust(32, '\x00')[:32]
|
self.title = title.ljust(32, '\x00')[:32]
|
||||||
|
|
||||||
def build_header(self, sections)
|
def build_header(self, sections):
|
||||||
'''
|
'''
|
||||||
Sections is a list of section offsets
|
Sections is a list of section offsets
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return header
|
return header
|
||||||
|
@ -8,7 +8,6 @@ __docformat__ = 'restructuredtext en'
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from calibre.customize.conversion import InputFormatPlugin
|
from calibre.customize.conversion import InputFormatPlugin
|
||||||
from calibre.ebooks.pdb.header import PdbHeader
|
|
||||||
from calibre.ebooks.pdb import PDBError, IDENTITY_TO_NAME, get_reader
|
from calibre.ebooks.pdb import PDBError, IDENTITY_TO_NAME, get_reader
|
||||||
|
|
||||||
class PDBInput(InputFormatPlugin):
|
class PDBInput(InputFormatPlugin):
|
||||||
@ -17,18 +16,18 @@ class PDBInput(InputFormatPlugin):
|
|||||||
author = 'John Schember'
|
author = 'John Schember'
|
||||||
description = 'Convert PDB to HTML'
|
description = 'Convert PDB to HTML'
|
||||||
file_types = set(['pdb'])
|
file_types = set(['pdb'])
|
||||||
|
|
||||||
def convert(self, stream, options, file_ext, log,
|
def convert(self, stream, options, file_ext, log,
|
||||||
accelerators):
|
accelerators):
|
||||||
header = PdbHeaderReader(stream)
|
header = PdbHeaderReader(stream)
|
||||||
Reader = get_reader(header.ident)
|
Reader = get_reader(header.ident)
|
||||||
|
|
||||||
if Reader is None:
|
if Reader is None:
|
||||||
raise PDBError('Unknown format in pdb file. Identity is %s' % header.identity)
|
raise PDBError('Unknown format in pdb file. Identity is %s' % header.identity)
|
||||||
|
|
||||||
log.debug('Detected ebook format as: %s with identity: %s' % (IDENTITY_TO_NAME[header.ident], header.ident))
|
log.debug('Detected ebook format as: %s with identity: %s' % (IDENTITY_TO_NAME[header.ident], header.ident))
|
||||||
|
|
||||||
reader = Reader(header, stream, log, options.input_encoding)
|
reader = Reader(header, stream, log, options.input_encoding)
|
||||||
opf = reader.extract_content(os.getcwd())
|
opf = reader.extract_content(os.getcwd())
|
||||||
|
|
||||||
return opf
|
return opf
|
||||||
|
@ -1,292 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
'''
|
|
||||||
The GUI for conversion to EPUB.
|
|
||||||
'''
|
|
||||||
import os, uuid
|
|
||||||
|
|
||||||
from PyQt4.Qt import QDialog, QSpinBox, QDoubleSpinBox, QComboBox, QLineEdit, \
|
|
||||||
QTextEdit, QCheckBox, Qt, QPixmap, QIcon, QListWidgetItem, SIGNAL
|
|
||||||
from lxml.etree import XPath
|
|
||||||
|
|
||||||
from calibre.gui2.dialogs.choose_format import ChooseFormatDialog
|
|
||||||
from calibre.gui2.dialogs.epub_ui import Ui_Dialog
|
|
||||||
from calibre.gui2 import error_dialog, choose_images, pixmap_to_data, ResizableDialog
|
|
||||||
from calibre.ebooks.epub.from_any import SOURCE_FORMATS, config as epubconfig
|
|
||||||
from calibre.ebooks.metadata import MetaInformation
|
|
||||||
from calibre.ptempfile import PersistentTemporaryFile
|
|
||||||
from calibre.ebooks.metadata.opf2 import OPFCreator
|
|
||||||
from calibre.ebooks.metadata import authors_to_string, string_to_authors
|
|
||||||
|
|
||||||
|
|
||||||
class Config(ResizableDialog, Ui_Dialog):
|
|
||||||
|
|
||||||
OUTPUT = 'EPUB'
|
|
||||||
|
|
||||||
def __init__(self, parent, db, row=None, config=epubconfig):
|
|
||||||
ResizableDialog.__init__(self, parent)
|
|
||||||
self.hide_controls()
|
|
||||||
self.connect(self.category_list, SIGNAL('itemEntered(QListWidgetItem *)'),
|
|
||||||
self.show_category_help)
|
|
||||||
self.connect(self.cover_button, SIGNAL("clicked()"), self.select_cover)
|
|
||||||
|
|
||||||
self.cover_changed = False
|
|
||||||
self.db = db
|
|
||||||
self.id = None
|
|
||||||
self.row = row
|
|
||||||
if row is not None:
|
|
||||||
self.id = db.id(row)
|
|
||||||
base = config().as_string() + '\n\n'
|
|
||||||
defaults = self.db.conversion_options(self.id, self.OUTPUT.lower())
|
|
||||||
defaults = base + (defaults if defaults else '')
|
|
||||||
self.config = config(defaults=defaults)
|
|
||||||
else:
|
|
||||||
self.config = config()
|
|
||||||
self.initialize()
|
|
||||||
self.get_source_format()
|
|
||||||
self.category_list.setCurrentRow(0)
|
|
||||||
if self.row is None:
|
|
||||||
self.setWindowTitle(_('Bulk convert to ')+self.OUTPUT)
|
|
||||||
else:
|
|
||||||
self.setWindowTitle((_(u'Convert %s to ')%unicode(self.title.text()))+self.OUTPUT)
|
|
||||||
|
|
||||||
def hide_controls(self):
|
|
||||||
self.source_profile_label.setVisible(False)
|
|
||||||
self.opt_source_profile.setVisible(False)
|
|
||||||
self.dest_profile_label.setVisible(False)
|
|
||||||
self.opt_dest_profile.setVisible(False)
|
|
||||||
self.opt_toc_title.setVisible(False)
|
|
||||||
self.toc_title_label.setVisible(False)
|
|
||||||
self.opt_rescale_images.setVisible(False)
|
|
||||||
self.opt_ignore_tables.setVisible(False)
|
|
||||||
self.opt_prefer_author_sort.setVisible(False)
|
|
||||||
|
|
||||||
def initialize(self):
|
|
||||||
self.__w = []
|
|
||||||
self.__w.append(QIcon(':/images/dialog_information.svg'))
|
|
||||||
self.item1 = QListWidgetItem(self.__w[-1], _('Metadata'), self.category_list)
|
|
||||||
self.__w.append(QIcon(':/images/lookfeel.svg'))
|
|
||||||
self.item2 = QListWidgetItem(self.__w[-1], _('Look & Feel').replace(' ','\n'), self.category_list)
|
|
||||||
self.__w.append(QIcon(':/images/page.svg'))
|
|
||||||
self.item3 = QListWidgetItem(self.__w[-1], _('Page Setup').replace(' ','\n'), self.category_list)
|
|
||||||
self.__w.append(QIcon(':/images/chapters.svg'))
|
|
||||||
self.item4 = QListWidgetItem(self.__w[-1], _('Chapter Detection').replace(' ','\n'), self.category_list)
|
|
||||||
self.setup_tooltips()
|
|
||||||
self.initialize_options()
|
|
||||||
|
|
||||||
def set_help(self, msg):
|
|
||||||
if msg and getattr(msg, 'strip', lambda:True)():
|
|
||||||
self.help_view.setPlainText(msg)
|
|
||||||
|
|
||||||
def setup_tooltips(self):
|
|
||||||
for opt in self.config.option_set.preferences:
|
|
||||||
g = getattr(self, 'opt_'+opt.name, False)
|
|
||||||
if opt.help and g:
|
|
||||||
help = opt.help.replace('%default', str(opt.default))
|
|
||||||
g._help = help
|
|
||||||
g.setToolTip(help.replace('<', '<').replace('>', '>'))
|
|
||||||
g.setWhatsThis(help.replace('<', '<').replace('>', '>'))
|
|
||||||
g.__class__.enterEvent = lambda obj, event: self.set_help(getattr(obj, '_help', obj.toolTip()))
|
|
||||||
|
|
||||||
def show_category_help(self, item):
|
|
||||||
text = unicode(item.text())
|
|
||||||
help = {
|
|
||||||
_('Metadata') : _('Specify metadata such as title and author for the book.\n\nMetadata will be updated in the database as well as the generated %s file.')%self.OUTPUT,
|
|
||||||
_('Look & Feel') : _('Adjust the look of the generated ebook by specifying things like font sizes.'),
|
|
||||||
_('Page Setup') : _('Specify the page layout settings like margins.'),
|
|
||||||
_('Chapter Detection') : _('Fine tune the detection of chapter and section headings.'),
|
|
||||||
}
|
|
||||||
self.set_help(help[text.replace('\n', ' ')])
|
|
||||||
|
|
||||||
def select_cover(self):
|
|
||||||
files = choose_images(self, 'change cover dialog',
|
|
||||||
_('Choose cover for ') + unicode(self.title.text()))
|
|
||||||
if not files:
|
|
||||||
return
|
|
||||||
_file = files[0]
|
|
||||||
if _file:
|
|
||||||
_file = os.path.abspath(_file)
|
|
||||||
if not os.access(_file, os.R_OK):
|
|
||||||
d = error_dialog(self.window, _('Cannot read'),
|
|
||||||
_('You do not have permission to read the file: ') + _file)
|
|
||||||
d.exec_()
|
|
||||||
return
|
|
||||||
cf, cover = None, None
|
|
||||||
try:
|
|
||||||
cf = open(_file, "rb")
|
|
||||||
cover = cf.read()
|
|
||||||
except IOError, e:
|
|
||||||
d = error_dialog(self.window, _('Error reading file'),
|
|
||||||
_("<p>There was an error reading from file: <br /><b>") + _file + "</b></p><br />"+str(e))
|
|
||||||
d.exec_()
|
|
||||||
if cover:
|
|
||||||
pix = QPixmap()
|
|
||||||
pix.loadFromData(cover)
|
|
||||||
if pix.isNull():
|
|
||||||
d = error_dialog(self.window, _('Error reading file'),
|
|
||||||
_file + _(" is not a valid picture"))
|
|
||||||
d.exec_()
|
|
||||||
else:
|
|
||||||
self.cover_path.setText(_file)
|
|
||||||
self.cover.setPixmap(pix)
|
|
||||||
self.cover_changed = True
|
|
||||||
self.cpixmap = pix
|
|
||||||
|
|
||||||
def initialize_metadata_options(self):
|
|
||||||
all_series = self.db.all_series()
|
|
||||||
all_series.sort(cmp=lambda x, y : cmp(x[1], y[1]))
|
|
||||||
for series in all_series:
|
|
||||||
self.series.addItem(series[1])
|
|
||||||
self.series.setCurrentIndex(-1)
|
|
||||||
|
|
||||||
if self.row is not None:
|
|
||||||
mi = self.db.get_metadata(self.id, index_is_id=True)
|
|
||||||
self.title.setText(mi.title)
|
|
||||||
if mi.authors:
|
|
||||||
self.author.setText(authors_to_string(mi.authors))
|
|
||||||
else:
|
|
||||||
self.author.setText('')
|
|
||||||
self.publisher.setText(mi.publisher if mi.publisher else '')
|
|
||||||
self.author_sort.setText(mi.author_sort if mi.author_sort else '')
|
|
||||||
self.tags.setText(', '.join(mi.tags if mi.tags else []))
|
|
||||||
self.comment.setText(mi.comments if mi.comments else '')
|
|
||||||
if mi.series:
|
|
||||||
self.series.setCurrentIndex(self.series.findText(mi.series))
|
|
||||||
if mi.series_index is not None:
|
|
||||||
self.series_index.setValue(mi.series_index)
|
|
||||||
|
|
||||||
cover = self.db.cover(self.id, index_is_id=True)
|
|
||||||
if cover:
|
|
||||||
pm = QPixmap()
|
|
||||||
pm.loadFromData(cover)
|
|
||||||
if not pm.isNull():
|
|
||||||
self.cover.setPixmap(pm)
|
|
||||||
|
|
||||||
def get_title_and_authors(self):
|
|
||||||
title = unicode(self.title.text()).strip()
|
|
||||||
if not title:
|
|
||||||
title = _('Unknown')
|
|
||||||
authors = unicode(self.author.text()).strip()
|
|
||||||
authors = string_to_authors(authors) if authors else [_('Unknown')]
|
|
||||||
return title, authors
|
|
||||||
|
|
||||||
def get_metadata(self):
|
|
||||||
title, authors = self.get_title_and_authors()
|
|
||||||
mi = MetaInformation(title, authors)
|
|
||||||
publisher = unicode(self.publisher.text()).strip()
|
|
||||||
if publisher:
|
|
||||||
mi.publisher = publisher
|
|
||||||
author_sort = unicode(self.author_sort.text()).strip()
|
|
||||||
if author_sort:
|
|
||||||
mi.author_sort = author_sort
|
|
||||||
comments = unicode(self.comment.toPlainText()).strip()
|
|
||||||
if comments:
|
|
||||||
mi.comments = comments
|
|
||||||
mi.series_index = int(self.series_index.value())
|
|
||||||
if self.series.currentIndex() > -1:
|
|
||||||
mi.series = unicode(self.series.currentText()).strip()
|
|
||||||
tags = [t.strip() for t in unicode(self.tags.text()).strip().split(',')]
|
|
||||||
if tags:
|
|
||||||
mi.tags = tags
|
|
||||||
|
|
||||||
return mi
|
|
||||||
|
|
||||||
def read_settings(self):
|
|
||||||
for pref in self.config.option_set.preferences:
|
|
||||||
g = getattr(self, 'opt_'+pref.name, False)
|
|
||||||
if g:
|
|
||||||
if isinstance(g, (QSpinBox, QDoubleSpinBox)):
|
|
||||||
self.config.set(pref.name, g.value())
|
|
||||||
elif isinstance(g, (QLineEdit, QTextEdit)):
|
|
||||||
func = getattr(g, 'toPlainText', getattr(g, 'text', None))()
|
|
||||||
val = unicode(func)
|
|
||||||
self.config.set(pref.name, val if val else None)
|
|
||||||
elif isinstance(g, QComboBox):
|
|
||||||
self.config.set(pref.name, unicode(g.currentText()))
|
|
||||||
elif isinstance(g, QCheckBox):
|
|
||||||
self.config.set(pref.name, bool(g.isChecked()))
|
|
||||||
if self.row is not None:
|
|
||||||
self.db.set_conversion_options(self.id, self.OUTPUT.lower(), self.config.src)
|
|
||||||
|
|
||||||
|
|
||||||
def initialize_options(self):
|
|
||||||
self.initialize_metadata_options()
|
|
||||||
values = self.config.parse()
|
|
||||||
for pref in self.config.option_set.preferences:
|
|
||||||
g = getattr(self, 'opt_'+pref.name, False)
|
|
||||||
if g:
|
|
||||||
val = getattr(values, pref.name)
|
|
||||||
if val is None:
|
|
||||||
continue
|
|
||||||
if isinstance(g, (QSpinBox, QDoubleSpinBox)):
|
|
||||||
g.setValue(val)
|
|
||||||
elif isinstance(g, (QLineEdit, QTextEdit)):
|
|
||||||
getattr(g, 'setPlainText', g.setText)(val)
|
|
||||||
getattr(g, 'setCursorPosition', lambda x: x)(0)
|
|
||||||
elif isinstance(g, QComboBox):
|
|
||||||
for value in pref.choices:
|
|
||||||
g.addItem(value)
|
|
||||||
g.setCurrentIndex(g.findText(val))
|
|
||||||
elif isinstance(g, QCheckBox):
|
|
||||||
g.setCheckState(Qt.Checked if bool(val) else Qt.Unchecked)
|
|
||||||
|
|
||||||
|
|
||||||
def get_source_format(self):
|
|
||||||
self.source_format = None
|
|
||||||
if self.row is not None:
|
|
||||||
temp = self.db.formats(self.id, index_is_id=True)
|
|
||||||
if not temp:
|
|
||||||
error_dialog(self.parent(), _('Cannot convert'),
|
|
||||||
_('This book has no available formats')).exec_()
|
|
||||||
|
|
||||||
available_formats = [f.upper().strip() for f in temp.split(',')]
|
|
||||||
choices = [fmt.upper() for fmt in SOURCE_FORMATS if fmt.upper() in available_formats]
|
|
||||||
if not choices:
|
|
||||||
error_dialog(self.parent(), _('No available formats'),
|
|
||||||
_('Cannot convert %s as this book has no supported formats')%(self.title.text())).exec_()
|
|
||||||
elif len(choices) == 1:
|
|
||||||
self.source_format = choices[0]
|
|
||||||
else:
|
|
||||||
d = ChooseFormatDialog(self.parent(), _('Choose the format to convert to ')+self.OUTPUT, choices)
|
|
||||||
if d.exec_() == QDialog.Accepted:
|
|
||||||
self.source_format = d.format()
|
|
||||||
|
|
||||||
def accept(self):
|
|
||||||
for opt in ('chapter', 'level1_toc', 'level2_toc', 'level3_toc', 'page',
|
|
||||||
'page_names'):
|
|
||||||
text = unicode(getattr(self, 'opt_'+opt).text())
|
|
||||||
if text:
|
|
||||||
try:
|
|
||||||
XPath(text,namespaces={'re':'http://exslt.org/regular-expressions'})
|
|
||||||
except Exception, err:
|
|
||||||
error_dialog(self, _('Invalid XPath expression'),
|
|
||||||
_('The expression %s is invalid. Error: %s')%(text, err)
|
|
||||||
).exec_()
|
|
||||||
return
|
|
||||||
mi = self.get_metadata()
|
|
||||||
self.user_mi = mi
|
|
||||||
self.read_settings()
|
|
||||||
self.cover_file = None
|
|
||||||
if self.row is not None:
|
|
||||||
self.db.set_metadata(self.id, mi)
|
|
||||||
self.mi = self.db.get_metadata(self.id, index_is_id=True)
|
|
||||||
self.mi.application_id = uuid.uuid4()
|
|
||||||
opf = OPFCreator(os.getcwdu(), self.mi)
|
|
||||||
self.opf_file = PersistentTemporaryFile('.opf')
|
|
||||||
opf.render(self.opf_file)
|
|
||||||
self.opf_file.close()
|
|
||||||
if self.cover_changed:
|
|
||||||
self.db.set_cover(self.id, pixmap_to_data(self.cover.pixmap()))
|
|
||||||
cover = self.db.cover(self.id, index_is_id=True)
|
|
||||||
if cover:
|
|
||||||
cf = PersistentTemporaryFile('.jpeg')
|
|
||||||
cf.write(cover)
|
|
||||||
cf.close()
|
|
||||||
self.cover_file = cf
|
|
||||||
self.opts = self.config.parse()
|
|
||||||
QDialog.accept(self)
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -1,425 +0,0 @@
|
|||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
|
||||||
import os, codecs
|
|
||||||
|
|
||||||
from PyQt4.QtCore import QObject, SIGNAL, Qt
|
|
||||||
from PyQt4.QtGui import QAbstractSpinBox, QLineEdit, QCheckBox, QDialog, \
|
|
||||||
QPixmap, QTextEdit, QListWidgetItem, QIcon
|
|
||||||
|
|
||||||
from calibre.gui2.dialogs.lrf_single_ui import Ui_LRFSingleDialog
|
|
||||||
from calibre.gui2.dialogs.choose_format import ChooseFormatDialog
|
|
||||||
from calibre.gui2 import qstring_to_unicode, error_dialog, \
|
|
||||||
pixmap_to_data, choose_images, config
|
|
||||||
from calibre.gui2.widgets import FontFamilyModel
|
|
||||||
from calibre.ebooks.lrf import option_parser
|
|
||||||
from calibre.ptempfile import PersistentTemporaryFile
|
|
||||||
from calibre.constants import __appname__
|
|
||||||
from calibre.ebooks.metadata import authors_to_string, string_to_authors, authors_to_sort_string
|
|
||||||
|
|
||||||
font_family_model = None
|
|
||||||
|
|
||||||
class LRFSingleDialog(QDialog, Ui_LRFSingleDialog):
|
|
||||||
|
|
||||||
PARSER = option_parser('')
|
|
||||||
PREPROCESS_OPTIONS = [ o for o in PARSER.option_groups if o.title == 'PREPROCESSING OPTIONS'][0].option_list
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def options(cls):
|
|
||||||
options = cls.PARSER.option_list
|
|
||||||
for g in cls.PARSER.option_groups:
|
|
||||||
options.extend(g.option_list)
|
|
||||||
for opt in options:
|
|
||||||
yield opt
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def option_to_name(cls, opt):
|
|
||||||
src = opt.get_opt_string()
|
|
||||||
return 'gui_' + src[2:].replace('-', '_')
|
|
||||||
|
|
||||||
def initialize_common(self):
|
|
||||||
self.output_format = 'LRF'
|
|
||||||
self.setup_tooltips()
|
|
||||||
self.initialize_options()
|
|
||||||
global font_family_model
|
|
||||||
if font_family_model is None:
|
|
||||||
font_family_model = FontFamilyModel()
|
|
||||||
self.font_family_model = font_family_model
|
|
||||||
self.gui_serif_family.setModel(self.font_family_model)
|
|
||||||
self.gui_sans_family.setModel(self.font_family_model)
|
|
||||||
self.gui_mono_family.setModel(self.font_family_model)
|
|
||||||
self.load_saved_global_defaults()
|
|
||||||
|
|
||||||
def populate_list(self):
|
|
||||||
self.__w = []
|
|
||||||
self.__w.append(QIcon(':/images/dialog_information.svg'))
|
|
||||||
self.item1 = QListWidgetItem(self.__w[-1], _("Metadata"), self.categoryList)
|
|
||||||
self.__w.append(QIcon(':/images/lookfeel.svg'))
|
|
||||||
self.item2 = QListWidgetItem(self.__w[-1], _('Look & Feel'), self.categoryList)
|
|
||||||
self.__w.append(QIcon(':/images/page.svg'))
|
|
||||||
self.item3 = QListWidgetItem(self.__w[-1], _('Page Setup'), self.categoryList)
|
|
||||||
self.__w.append(QIcon(':/images/chapters.svg'))
|
|
||||||
self.item4 = QListWidgetItem(self.__w[-1], _('Chapter Detection'), self.categoryList)
|
|
||||||
|
|
||||||
def __init__(self, window, db, row):
|
|
||||||
QDialog.__init__(self, window)
|
|
||||||
Ui_LRFSingleDialog.__init__(self)
|
|
||||||
self.setupUi(self)
|
|
||||||
self.populate_list()
|
|
||||||
self.categoryList.setCurrentRow(0)
|
|
||||||
QObject.connect(self.categoryList, SIGNAL('itemEntered(QListWidgetItem *)'),
|
|
||||||
self.show_category_help)
|
|
||||||
QObject.connect(self.cover_button, SIGNAL("clicked(bool)"), self.select_cover)
|
|
||||||
#self.categoryList.leaveEvent = self.reset_help
|
|
||||||
self.reset_help()
|
|
||||||
self.selected_format = None
|
|
||||||
self.initialize_common()
|
|
||||||
self.db = db
|
|
||||||
self.row = row
|
|
||||||
self.cover_changed = False
|
|
||||||
self.cpixmap = None
|
|
||||||
self.changed = False
|
|
||||||
|
|
||||||
if db:
|
|
||||||
self.id = self.db.id(self.row)
|
|
||||||
self.read_saved_options()
|
|
||||||
self.initialize_metadata()
|
|
||||||
formats = self.db.formats(self.row)
|
|
||||||
formats = [i.upper() for i in formats.split(',')] if formats else []
|
|
||||||
try:
|
|
||||||
formats.remove(self.output_format)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
if not formats:
|
|
||||||
d = error_dialog(window, _('No available formats'),
|
|
||||||
_('Cannot convert %s as this book has no supported formats')%(self.gui_title.text()))
|
|
||||||
d.exec_()
|
|
||||||
|
|
||||||
if len(formats) > 1:
|
|
||||||
d = ChooseFormatDialog(window, _('Choose the format to convert into LRF'), formats)
|
|
||||||
d.exec_()
|
|
||||||
if d.result() == QDialog.Accepted:
|
|
||||||
self.selected_format = d.format()
|
|
||||||
elif len(formats) > 0:
|
|
||||||
self.selected_format = formats[0]
|
|
||||||
|
|
||||||
if self.selected_format:
|
|
||||||
self.setWindowTitle(_('Convert %s to LRF')%(self.selected_format,))
|
|
||||||
|
|
||||||
else:
|
|
||||||
self.setWindowTitle(_('Set conversion defaults'))
|
|
||||||
|
|
||||||
|
|
||||||
def load_saved_global_defaults(self):
|
|
||||||
cmdline = config['LRF_conversion_defaults']
|
|
||||||
if cmdline:
|
|
||||||
self.set_options_from_cmdline(cmdline)
|
|
||||||
|
|
||||||
def set_options_from_cmdline(self, cmdline):
|
|
||||||
for opt in self.options():
|
|
||||||
guiname = self.option_to_name(opt)
|
|
||||||
try:
|
|
||||||
obj = getattr(self, guiname)
|
|
||||||
except AttributeError:
|
|
||||||
continue
|
|
||||||
if isinstance(obj, QCheckBox):
|
|
||||||
if opt.get_opt_string() in cmdline:
|
|
||||||
obj.setCheckState(Qt.Checked)
|
|
||||||
else:
|
|
||||||
obj.setCheckState(Qt.Unchecked)
|
|
||||||
try:
|
|
||||||
i = cmdline.index(opt.get_opt_string())
|
|
||||||
except ValueError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if isinstance(obj, QAbstractSpinBox):
|
|
||||||
obj.setValue(cmdline[i+1])
|
|
||||||
elif isinstance(obj, QLineEdit):
|
|
||||||
obj.setText(cmdline[i+1])
|
|
||||||
elif isinstance(obj, QTextEdit):
|
|
||||||
obj.setPlainText(cmdline[i+1])
|
|
||||||
profile = cmdline[cmdline.index('--profile')+1]
|
|
||||||
pindex = self.gui_profile.findText(profile)
|
|
||||||
if pindex >= 0:
|
|
||||||
self.gui_profile.setCurrentIndex(pindex)
|
|
||||||
for prepro in self.PREPROCESS_OPTIONS:
|
|
||||||
ops = prepro.get_opt_string()
|
|
||||||
if ops in cmdline:
|
|
||||||
self.preprocess.setCurrentIndex(self.preprocess.findText(ops[2:]))
|
|
||||||
break
|
|
||||||
|
|
||||||
for opt in ('--serif-family', '--sans-family', '--mono-family'):
|
|
||||||
if opt in cmdline:
|
|
||||||
print 'in'
|
|
||||||
family = cmdline[cmdline.index(opt)+1].split(',')[-1].strip()
|
|
||||||
obj = getattr(self, 'gui_'+opt[2:].replace('-', '_'))
|
|
||||||
try:
|
|
||||||
obj.setCurrentIndex(self.font_family_model.index_of(family))
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
|
|
||||||
def read_saved_options(self):
|
|
||||||
cmdline = self.db.conversion_options(self.id, self.output_format.lower())
|
|
||||||
if cmdline:
|
|
||||||
self.set_options_from_cmdline(cmdline)
|
|
||||||
|
|
||||||
def select_cover(self, checked):
|
|
||||||
files = choose_images(self, 'change cover dialog',
|
|
||||||
_('Choose cover for ') + qstring_to_unicode(self.gui_title.text()))
|
|
||||||
if not files:
|
|
||||||
return
|
|
||||||
_file = files[0]
|
|
||||||
if _file:
|
|
||||||
_file = os.path.abspath(_file)
|
|
||||||
if not os.access(_file, os.R_OK):
|
|
||||||
d = error_dialog(self.window, _('Cannot read'),
|
|
||||||
_('You do not have permission to read the file: ') + _file)
|
|
||||||
d.exec_()
|
|
||||||
return
|
|
||||||
cf, cover = None, None
|
|
||||||
try:
|
|
||||||
cf = open(_file, "rb")
|
|
||||||
cover = cf.read()
|
|
||||||
except IOError, e:
|
|
||||||
d = error_dialog(self.window, _('Error reading file'),
|
|
||||||
_("<p>There was an error reading from file: <br /><b>") + _file + "</b></p><br />"+str(e))
|
|
||||||
d.exec_()
|
|
||||||
if cover:
|
|
||||||
pix = QPixmap()
|
|
||||||
pix.loadFromData(cover)
|
|
||||||
if pix.isNull():
|
|
||||||
d = error_dialog(self.window, _file + _(" is not a valid picture"))
|
|
||||||
d.exec_()
|
|
||||||
else:
|
|
||||||
self.cover_path.setText(_file)
|
|
||||||
self.cover.setPixmap(pix)
|
|
||||||
self.cover_changed = True
|
|
||||||
self.cpixmap = pix
|
|
||||||
|
|
||||||
def initialize_metadata(self):
|
|
||||||
db, row = self.db, self.row
|
|
||||||
self.id = self.db.id(row)
|
|
||||||
self.gui_title.setText(db.title(row))
|
|
||||||
au = self.db.authors(row)
|
|
||||||
if au:
|
|
||||||
au = [a.strip().replace('|', ',') for a in au.split(',')]
|
|
||||||
self.gui_author.setText(authors_to_string(au))
|
|
||||||
else:
|
|
||||||
self.gui_author.setText('')
|
|
||||||
aus = self.db.author_sort(row)
|
|
||||||
self.gui_author_sort.setText(aus if aus else '')
|
|
||||||
pub = self.db.publisher(row)
|
|
||||||
self.gui_publisher.setText(pub if pub else '')
|
|
||||||
tags = self.db.tags(row)
|
|
||||||
self.tags.setText(tags if tags else '')
|
|
||||||
comments = self.db.comments(row)
|
|
||||||
self.gui_comment.setPlainText(comments if comments else '')
|
|
||||||
|
|
||||||
all_series = self.db.all_series()
|
|
||||||
all_series.sort(cmp=lambda x, y : cmp(x[1], y[1]))
|
|
||||||
series_id = self.db.series_id(row)
|
|
||||||
idx, c = None, 0
|
|
||||||
for i in all_series:
|
|
||||||
id, name = i
|
|
||||||
if id == series_id:
|
|
||||||
idx = c
|
|
||||||
self.series.addItem(name)
|
|
||||||
c += 1
|
|
||||||
|
|
||||||
self.series.lineEdit().setText('')
|
|
||||||
if idx is not None:
|
|
||||||
self.series.setCurrentIndex(idx)
|
|
||||||
|
|
||||||
self.series_index.setValue(self.db.series_index(row))
|
|
||||||
|
|
||||||
cover = self.db.cover(row)
|
|
||||||
if cover:
|
|
||||||
pm = QPixmap()
|
|
||||||
pm.loadFromData(cover)
|
|
||||||
if not pm.isNull():
|
|
||||||
self.cover.setPixmap(pm)
|
|
||||||
|
|
||||||
def initialize_options(self):
|
|
||||||
'''Initialize non metadata options from the defaults.'''
|
|
||||||
for name in self.option_map.keys():
|
|
||||||
default = self.option_map[name].default
|
|
||||||
obj = getattr(self, name)
|
|
||||||
if isinstance(obj, QAbstractSpinBox):
|
|
||||||
obj.setValue(default)
|
|
||||||
elif isinstance(obj, QLineEdit) and default:
|
|
||||||
obj.setText(default)
|
|
||||||
elif isinstance(obj, QTextEdit) and default:
|
|
||||||
obj.setPlainText(default)
|
|
||||||
elif isinstance(obj, QCheckBox):
|
|
||||||
state = Qt.Checked if default else Qt.Unchecked
|
|
||||||
obj.setCheckState(state)
|
|
||||||
self.gui_headerformat.setDisabled(True)
|
|
||||||
self.gui_header_separation.setDisabled(True)
|
|
||||||
self.gui_use_metadata_cover.setCheckState(Qt.Checked)
|
|
||||||
self.preprocess.addItem(_('No preprocessing'))
|
|
||||||
for opt in self.PREPROCESS_OPTIONS:
|
|
||||||
self.preprocess.addItem(opt.get_opt_string()[2:])
|
|
||||||
ph = _('Preprocess the file before converting to LRF. This is useful if you know that the file is from a specific source. Known sources:')
|
|
||||||
ph += _('<ol><li><b>baen</b> - Books from BAEN Publishers</li>')
|
|
||||||
ph += _('<li><b>pdftohtml</b> - HTML files that are the output of the program pdftohtml</li>')
|
|
||||||
ph += _('<li><b>book-designer</b> - HTML0 files from Book Designer</li>')
|
|
||||||
self.preprocess.setToolTip(ph)
|
|
||||||
self.preprocess.setWhatsThis(ph)
|
|
||||||
for profile in self.PARSER.get_option('--profile').choices:
|
|
||||||
if self.gui_profile.findText(profile) < 0:
|
|
||||||
self.gui_profile.addItem(profile)
|
|
||||||
|
|
||||||
def setup_tooltips(self):
|
|
||||||
def show_item_help(obj, event):
|
|
||||||
self.set_help(obj.toolTip())
|
|
||||||
|
|
||||||
self.option_map = {}
|
|
||||||
for opt in self.options():
|
|
||||||
try:
|
|
||||||
help = opt.help.replace('%default', str(opt.default))
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
help = opt.help
|
|
||||||
|
|
||||||
guiname = self.option_to_name(opt)
|
|
||||||
if hasattr(self, guiname):
|
|
||||||
obj = getattr(self, guiname)
|
|
||||||
obj.setToolTip(help)
|
|
||||||
obj.setWhatsThis(help)
|
|
||||||
self.option_map[guiname] = opt
|
|
||||||
obj.__class__.enterEvent = show_item_help
|
|
||||||
#obj.leaveEvent = self.reset_help
|
|
||||||
self.preprocess.__class__.enterEvent = show_item_help
|
|
||||||
#self.preprocess.leaveEvent = self.reset_help
|
|
||||||
|
|
||||||
|
|
||||||
def show_category_help(self, item):
|
|
||||||
text = qstring_to_unicode(item.text())
|
|
||||||
help = {
|
|
||||||
_('Metadata') : _('Specify metadata such as title and author for the book.<p>Metadata will be updated in the database as well as the generated LRF file.'),
|
|
||||||
_('Look & Feel') : _('Adjust the look of the generated LRF file by specifying things like font sizes and the spacing between words.'),
|
|
||||||
_('Page Setup') : _('Specify the page settings like margins and the screen size of the target device.'),
|
|
||||||
_('Chapter Detection') : _('Fine tune the detection of chapter and section headings.'),
|
|
||||||
}
|
|
||||||
self.set_help(help[text])
|
|
||||||
|
|
||||||
def set_help(self, msg):
|
|
||||||
if msg and getattr(msg, 'strip', lambda:True)():
|
|
||||||
self.help_view.setHtml('<html><body>%s</body></html>'%(msg,))
|
|
||||||
|
|
||||||
def reset_help(self, *args):
|
|
||||||
self.set_help(_('<font color="gray">No help available</font>'))
|
|
||||||
if args:
|
|
||||||
args[0].accept()
|
|
||||||
|
|
||||||
def build_commandline(self):
|
|
||||||
cmd = [__appname__]
|
|
||||||
for name in self.option_map.keys():
|
|
||||||
opt = self.option_map[name].get_opt_string()
|
|
||||||
obj = getattr(self, name)
|
|
||||||
if isinstance(obj, QAbstractSpinBox):
|
|
||||||
cmd.extend([opt, obj.value()])
|
|
||||||
elif isinstance(obj, QLineEdit):
|
|
||||||
val = qstring_to_unicode(obj.text())
|
|
||||||
if val:
|
|
||||||
if opt == '--encoding':
|
|
||||||
try:
|
|
||||||
codecs.getdecoder(val)
|
|
||||||
except:
|
|
||||||
d = error_dialog(self, 'Unknown encoding',
|
|
||||||
'<p>Unknown encoding: %s<br/>For a list of known encodings see http://docs.python.org/lib/standard-encodings.html'%val)
|
|
||||||
d.exec_()
|
|
||||||
return
|
|
||||||
cmd.extend([opt, val])
|
|
||||||
elif isinstance(obj, QTextEdit):
|
|
||||||
val = qstring_to_unicode(obj.toPlainText())
|
|
||||||
if val:
|
|
||||||
cmd.extend([opt, val])
|
|
||||||
elif isinstance(obj, QCheckBox):
|
|
||||||
if obj.checkState() == Qt.Checked:
|
|
||||||
cmd.append(opt)
|
|
||||||
|
|
||||||
text = qstring_to_unicode(self.preprocess.currentText())
|
|
||||||
if text != _('No preprocessing'):
|
|
||||||
cmd.append(u'--'+text)
|
|
||||||
cmd.extend([u'--profile', qstring_to_unicode(self.gui_profile.currentText())])
|
|
||||||
|
|
||||||
for opt in ('--serif-family', '--sans-family', '--mono-family'):
|
|
||||||
obj = getattr(self, 'gui_'+opt[2:].replace('-', '_'))
|
|
||||||
family = qstring_to_unicode(obj.itemText(obj.currentIndex())).strip()
|
|
||||||
if family != 'None':
|
|
||||||
cmd.extend([opt, family])
|
|
||||||
|
|
||||||
return cmd
|
|
||||||
|
|
||||||
def title(self):
|
|
||||||
return qstring_to_unicode(self.gui_title.text())
|
|
||||||
|
|
||||||
def write_metadata(self):
|
|
||||||
title = qstring_to_unicode(self.gui_title.text())
|
|
||||||
self.db.set_title(self.id, title)
|
|
||||||
au = unicode(self.gui_author.text())
|
|
||||||
if au:
|
|
||||||
self.db.set_authors(self.id, string_to_authors(au))
|
|
||||||
aus = qstring_to_unicode(self.gui_author_sort.text())
|
|
||||||
if not aus:
|
|
||||||
t = self.db.authors(self.id, index_is_id=True)
|
|
||||||
if not t:
|
|
||||||
t = _('Unknown')
|
|
||||||
aus = [a.strip().replace('|', ',') for a in t.split(',')]
|
|
||||||
aus = authors_to_sort_string(aus)
|
|
||||||
self.db.set_author_sort(self.id, aus)
|
|
||||||
self.db.set_publisher(self.id, qstring_to_unicode(self.gui_publisher.text()))
|
|
||||||
self.db.set_tags(self.id, qstring_to_unicode(self.tags.text()).split(','))
|
|
||||||
self.db.set_series(self.id, qstring_to_unicode(self.series.currentText()))
|
|
||||||
self.db.set_series_index(self.id, self.series_index.value())
|
|
||||||
if self.cover_changed:
|
|
||||||
self.db.set_cover(self.id, pixmap_to_data(self.cover.pixmap()))
|
|
||||||
|
|
||||||
|
|
||||||
def accept(self):
|
|
||||||
cmdline = self.build_commandline()
|
|
||||||
if cmdline is None:
|
|
||||||
return
|
|
||||||
if self.db:
|
|
||||||
self.cover_file = None
|
|
||||||
self.write_metadata()
|
|
||||||
cover = self.db.cover(self.row)
|
|
||||||
if cover:
|
|
||||||
self.cover_file = PersistentTemporaryFile(suffix='.jpeg')
|
|
||||||
self.cover_file.write(cover)
|
|
||||||
self.cover_file.close()
|
|
||||||
self.db.set_conversion_options(self.id, self.output_format.lower(), cmdline)
|
|
||||||
|
|
||||||
if self.cover_file:
|
|
||||||
cmdline.extend([u'--cover', self.cover_file.name])
|
|
||||||
self.cmdline = [unicode(i) for i in cmdline]
|
|
||||||
else:
|
|
||||||
config.set('LRF_conversion_defaults', cmdline)
|
|
||||||
QDialog.accept(self)
|
|
||||||
|
|
||||||
class LRFBulkDialog(LRFSingleDialog):
|
|
||||||
|
|
||||||
def __init__(self, window):
|
|
||||||
QDialog.__init__(self, window)
|
|
||||||
Ui_LRFSingleDialog.__init__(self)
|
|
||||||
self.setupUi(self)
|
|
||||||
self.populate_list()
|
|
||||||
|
|
||||||
self.categoryList.takeItem(0)
|
|
||||||
self.stack.removeWidget(self.stack.widget(0))
|
|
||||||
self.categoryList.setCurrentRow(0)
|
|
||||||
|
|
||||||
self.initialize_common()
|
|
||||||
self.setWindowTitle(_('Bulk convert ebooks to LRF'))
|
|
||||||
|
|
||||||
def accept(self):
|
|
||||||
self.cmdline = [unicode(i) for i in self.build_commandline()]
|
|
||||||
for meta in ('--title', '--author', '--publisher', '--comment'):
|
|
||||||
try:
|
|
||||||
index = self.cmdline.index(meta)
|
|
||||||
self.cmdline[index:index+2] = []
|
|
||||||
except ValueError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
self.cover_file = None
|
|
||||||
QDialog.accept(self)
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -1,22 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2009, Kovid Goyal kovid@kovidgoyal.net'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
from calibre.gui2.dialogs.epub import Config as _Config
|
|
||||||
from calibre.ebooks.mobi.from_any import config as mobiconfig
|
|
||||||
|
|
||||||
class Config(_Config):
|
|
||||||
|
|
||||||
OUTPUT = 'MOBI'
|
|
||||||
|
|
||||||
def __init__(self, parent, db, row=None):
|
|
||||||
_Config.__init__(self, parent, db, row=row, config=mobiconfig)
|
|
||||||
|
|
||||||
def hide_controls(self):
|
|
||||||
self.profile_label.setVisible(False)
|
|
||||||
self.opt_profile.setVisible(False)
|
|
||||||
self.opt_dont_split_on_page_breaks.setVisible(False)
|
|
||||||
self.opt_preserve_tag_structure.setVisible(False)
|
|
||||||
self.opt_linearize_tables.setVisible(False)
|
|
||||||
self.page_map_box.setVisible(False)
|
|
@ -11,17 +11,8 @@ from PyQt4.Qt import QDialog
|
|||||||
|
|
||||||
from calibre.customize.ui import available_input_formats
|
from calibre.customize.ui import available_input_formats
|
||||||
from calibre.utils.config import prefs
|
from calibre.utils.config import prefs
|
||||||
from calibre.gui2.dialogs.lrf_single import LRFSingleDialog, LRFBulkDialog
|
|
||||||
from calibre.gui2.dialogs.epub import Config as EPUBConvert
|
|
||||||
from calibre.gui2.dialogs.mobi import Config as MOBIConvert
|
|
||||||
import calibre.gui2.dialogs.comicconf as ComicConf
|
|
||||||
from calibre.gui2 import warning_dialog
|
from calibre.gui2 import warning_dialog
|
||||||
from calibre.ptempfile import PersistentTemporaryFile
|
from calibre.ptempfile import PersistentTemporaryFile
|
||||||
from calibre.ebooks.lrf import preferred_source_formats as LRF_PREFERRED_SOURCE_FORMATS
|
|
||||||
from calibre.ebooks.metadata.opf import OPFCreator
|
|
||||||
from calibre.ebooks.epub.from_any import SOURCE_FORMATS as EPUB_PREFERRED_SOURCE_FORMATS, config as epubconfig
|
|
||||||
from calibre.ebooks.mobi.from_any import config as mobiconfig
|
|
||||||
from calibre.ebooks.lrf.comic.convert_from import config as comicconfig
|
|
||||||
|
|
||||||
# Ordered list of source formats. Items closer to the beginning are
|
# Ordered list of source formats. Items closer to the beginning are
|
||||||
# preferred for conversion over those toward the end.
|
# preferred for conversion over those toward the end.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user