mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Pull from driver-dev
This commit is contained in:
commit
8b0fc486b5
@ -83,8 +83,6 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
'''
|
'''
|
||||||
FDI_LUNS = {'lun0':0, 'lun1':1, 'lun2':2}
|
FDI_LUNS = {'lun0':0, 'lun1':1, 'lun2':2}
|
||||||
FDI_BCD_TEMPLATE = '<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.device_revision_bcd" int="%(bcd)s">'
|
FDI_BCD_TEMPLATE = '<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.device_revision_bcd" int="%(bcd)s">'
|
||||||
FDI_LUNS = {'lun0':0, 'lun1':1, 'lun2':2}
|
|
||||||
|
|
||||||
|
|
||||||
def reset(self, key='-1', log_packets=False, report_progress=None) :
|
def reset(self, key='-1', log_packets=False, report_progress=None) :
|
||||||
self._main_prefix = self._card_a_prefix = self._card_b_prefix = None
|
self._main_prefix = self._card_a_prefix = self._card_b_prefix = None
|
||||||
|
@ -211,7 +211,6 @@ def main(args=sys.argv):
|
|||||||
OptionRecommendation.HIGH) \
|
OptionRecommendation.HIGH) \
|
||||||
for n in parser.options_iter()
|
for n in parser.options_iter()
|
||||||
if n.dest]
|
if n.dest]
|
||||||
print recommendations
|
|
||||||
plumber.merge_ui_recommendations(recommendations)
|
plumber.merge_ui_recommendations(recommendations)
|
||||||
|
|
||||||
plumber.run()
|
plumber.run()
|
||||||
|
@ -6,8 +6,9 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from calibre.customize.conversion import OutputFormatPlugin
|
from calibre.customize.conversion import OutputFormatPlugin, \
|
||||||
from calibre.ebooks.pdb import PDBError, get_writer
|
OptionRecommendation
|
||||||
|
from calibre.ebooks.pdb import PDBError, get_writer, FORMAT_WRITERS
|
||||||
|
|
||||||
class PDBOutput(OutputFormatPlugin):
|
class PDBOutput(OutputFormatPlugin):
|
||||||
|
|
||||||
@ -15,20 +16,25 @@ class PDBOutput(OutputFormatPlugin):
|
|||||||
author = 'John Schember'
|
author = 'John Schember'
|
||||||
file_type = 'pdb'
|
file_type = 'pdb'
|
||||||
|
|
||||||
|
options = set([
|
||||||
|
OptionRecommendation(name='format', recommended_value='doc',
|
||||||
|
level=OptionRecommendation.LOW,
|
||||||
|
short_switch='f', choices=FORMAT_WRITERS.keys(),
|
||||||
|
help=_('Format to use inside the pdb container. Choices are: '
|
||||||
|
'%s' % FORMAT_WRITERS.keys())),
|
||||||
|
])
|
||||||
|
|
||||||
def convert(self, oeb_book, output_path, input_plugin, opts, log):
|
def convert(self, oeb_book, output_path, input_plugin, opts, log):
|
||||||
close = False
|
close = False
|
||||||
if not hasattr(output_path, 'write'):
|
if not hasattr(output_path, 'write'):
|
||||||
# Determine the format to write based upon the sub extension
|
|
||||||
format = os.path.splitext(os.path.splitext(output_path)[0])[1][1:]
|
|
||||||
close = True
|
close = True
|
||||||
if not os.path.exists(os.path.dirname(output_path)) and os.path.dirname(output_path) != '':
|
if not os.path.exists(os.path.dirname(output_path)) and os.path.dirname(output_path) != '':
|
||||||
os.makedirs(os.path.dirname(output_path))
|
os.makedirs(os.path.dirname(output_path))
|
||||||
out_stream = open(output_path, 'wb')
|
out_stream = open(output_path, 'wb')
|
||||||
else:
|
else:
|
||||||
format = os.path.splitext(os.path.splitext(output_path.name)[0])[1][1:]
|
|
||||||
out_stream = output_path
|
out_stream = output_path
|
||||||
|
|
||||||
Writer = get_writer(format)
|
Writer = get_writer(opts.format)
|
||||||
|
|
||||||
if Writer is None:
|
if Writer is None:
|
||||||
raise PDBError('No writer avaliable for format %s.' % format)
|
raise PDBError('No writer avaliable for format %s.' % format)
|
||||||
|
@ -7,7 +7,7 @@ from PyQt4.Qt import QThread, SIGNAL, QMutex, QWaitCondition, Qt
|
|||||||
|
|
||||||
from calibre.gui2.dialogs.progress import ProgressDialog
|
from calibre.gui2.dialogs.progress import ProgressDialog
|
||||||
from calibre.constants import preferred_encoding
|
from calibre.constants import preferred_encoding
|
||||||
from calibre.gui2.widgets import WarningDialog
|
from calibre.gui2 import warning_dialog
|
||||||
|
|
||||||
class Add(QThread):
|
class Add(QThread):
|
||||||
|
|
||||||
@ -113,13 +113,13 @@ class AddFiles(Add):
|
|||||||
|
|
||||||
def process_duplicates(self):
|
def process_duplicates(self):
|
||||||
if self.duplicates:
|
if self.duplicates:
|
||||||
files = _('<p>Books with the same title as the following already '
|
files = ''
|
||||||
'exist in the database. Add them anyway?<ul>')
|
|
||||||
for mi in self.duplicates[2]:
|
for mi in self.duplicates[2]:
|
||||||
files += '<li>'+mi.title+'</li>\n'
|
files += mi.title+'\n'
|
||||||
d = WarningDialog (_('Duplicates found!'),
|
d = warning_dialog(_('Duplicates found!'),
|
||||||
_('Duplicates found!'),
|
_('Books with the same title as the following already '
|
||||||
files+'</ul></p>', parent=self._parent)
|
'exist in the database. Add them anyway?'),
|
||||||
|
files, parent=self._parent)
|
||||||
if d.exec_() == d.Accepted:
|
if d.exec_() == d.Accepted:
|
||||||
num = self.db.add_books(*self.duplicates,
|
num = self.db.add_books(*self.duplicates,
|
||||||
**dict(add_duplicates=True))[1]
|
**dict(add_duplicates=True))[1]
|
||||||
@ -221,19 +221,19 @@ class AddRecursive(Add):
|
|||||||
|
|
||||||
def process_duplicates(self):
|
def process_duplicates(self):
|
||||||
if self.duplicates:
|
if self.duplicates:
|
||||||
files = _('<p>Books with the same title as the following already '
|
files = ''
|
||||||
'exist in the database. Add them anyway?<ul>')
|
|
||||||
for mi in self.duplicates:
|
for mi in self.duplicates:
|
||||||
title = mi[0].title
|
title = mi[0].title
|
||||||
if not isinstance(title, unicode):
|
if not isinstance(title, unicode):
|
||||||
title = title.decode(preferred_encoding, 'replace')
|
title = title.decode(preferred_encoding, 'replace')
|
||||||
files += '<li>'+title+'</li>\n'
|
files += title+'\n'
|
||||||
d = WarningDialog (_('Duplicates found!'),
|
d = warning_dialog(_('Duplicates found!'),
|
||||||
_('Duplicates found!'),
|
_('Books with the same title as the following already '
|
||||||
files+'</ul></p>', parent=self._parent)
|
'exist in the database. Add them anyway?'),
|
||||||
|
files, parent=self._parent)
|
||||||
if d.exec_() == d.Accepted:
|
if d.exec_() == d.Accepted:
|
||||||
for mi, formats in self.duplicates:
|
for mi, formats in self.duplicates:
|
||||||
self.db.import_book(mi, formats, notify=False)
|
self.db.import_book(mi, formats, notify=False)
|
||||||
self.number_of_books_added += 1
|
self.number_of_books_added += 1
|
||||||
|
|
||||||
|
|
||||||
|
116
src/calibre/gui2/convert/bulk.py
Normal file
116
src/calibre/gui2/convert/bulk.py
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
__license__ = 'GPL 3'
|
||||||
|
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from PyQt4.Qt import QString, SIGNAL
|
||||||
|
|
||||||
|
from calibre.gui2.convert.single import Config, sort_formats_by_preference, \
|
||||||
|
GroupModel
|
||||||
|
from calibre.customize.ui import available_output_formats
|
||||||
|
from calibre.gui2 import ResizableDialog
|
||||||
|
from calibre.gui2.convert.look_and_feel import LookAndFeelWidget
|
||||||
|
from calibre.gui2.convert.page_setup import PageSetupWidget
|
||||||
|
from calibre.gui2.convert import GuiRecommendations
|
||||||
|
from calibre.ebooks.conversion.plumber import Plumber, OUTPUT_FORMAT_PREFERENCES
|
||||||
|
from calibre.utils.logging import Log
|
||||||
|
|
||||||
|
class BulkConfig(Config):
|
||||||
|
|
||||||
|
def __init__(self, parent, db, preferred_output_format=None):
|
||||||
|
ResizableDialog.__init__(self, parent)
|
||||||
|
|
||||||
|
self.setup_output_formats(db, preferred_output_format)
|
||||||
|
self.db = db
|
||||||
|
|
||||||
|
self.setup_pipeline()
|
||||||
|
|
||||||
|
self.input_formats.hide()
|
||||||
|
|
||||||
|
self.connect(self.output_formats, SIGNAL('currentIndexChanged(QString)'),
|
||||||
|
self.setup_pipeline)
|
||||||
|
self.connect(self.groups, SIGNAL('activated(QModelIndex)'),
|
||||||
|
self.show_pane)
|
||||||
|
self.connect(self.groups, SIGNAL('clicked(QModelIndex)'),
|
||||||
|
self.show_pane)
|
||||||
|
self.connect(self.groups, SIGNAL('entered(QModelIndex)'),
|
||||||
|
self.show_group_help)
|
||||||
|
self.groups.setMouseTracking(True)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_pipeline(self, *args):
|
||||||
|
oidx = self.groups.currentIndex().row()
|
||||||
|
output_format = self.output_format
|
||||||
|
|
||||||
|
input_path = 'dummy.epub'
|
||||||
|
output_path = 'dummy.'+output_format
|
||||||
|
log = Log()
|
||||||
|
log.outputs = []
|
||||||
|
self.plumber = Plumber(input_path, output_path, log)
|
||||||
|
|
||||||
|
def widget_factory(cls):
|
||||||
|
return cls(self.stack, self.plumber.get_option_by_name,
|
||||||
|
self.plumber.get_option_help, self.db)
|
||||||
|
|
||||||
|
self.setWindowTitle(_('Bulk Convert'))
|
||||||
|
lf = widget_factory(LookAndFeelWidget)
|
||||||
|
ps = widget_factory(PageSetupWidget)
|
||||||
|
|
||||||
|
output_widget = None
|
||||||
|
name = 'calibre.gui2.convert.%s' % self.plumber.output_plugin.name.lower().replace(' ', '_')
|
||||||
|
try:
|
||||||
|
__import__(name)
|
||||||
|
output_widget = sys.modules[name]
|
||||||
|
pw = output_widget.PluginWidget
|
||||||
|
pw.ICON = ':/images/back.svg'
|
||||||
|
pw.HELP = _('Options specific to the output format.')
|
||||||
|
output_widget = widget_factory(pw)
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
while True:
|
||||||
|
c = self.stack.currentWidget()
|
||||||
|
if not c: break
|
||||||
|
self.stack.removeWidget(c)
|
||||||
|
|
||||||
|
widgets = [lf, ps]
|
||||||
|
if output_widget is not None:
|
||||||
|
widgets.append(output_widget)
|
||||||
|
for w in widgets:
|
||||||
|
self.stack.addWidget(w)
|
||||||
|
self.connect(w, SIGNAL('set_help(PyQt_PyObject)'),
|
||||||
|
self.help.setPlainText)
|
||||||
|
|
||||||
|
self._groups_model = GroupModel(widgets)
|
||||||
|
self.groups.setModel(self._groups_model)
|
||||||
|
|
||||||
|
idx = oidx if -1 < oidx < self._groups_model.rowCount() else 0
|
||||||
|
self.groups.setCurrentIndex(self._groups_model.index(idx))
|
||||||
|
|
||||||
|
|
||||||
|
def setup_output_formats(self, db, preferred_output_format):
|
||||||
|
available_formats = ''
|
||||||
|
available_formats = set([x.lower() for x in
|
||||||
|
available_formats.split(',')])
|
||||||
|
output_formats = sorted(available_output_formats())
|
||||||
|
output_formats.remove('oeb')
|
||||||
|
preferred_output_format = preferred_output_format if \
|
||||||
|
preferred_output_format in output_formats else \
|
||||||
|
sort_formats_by_preference(output_formats,
|
||||||
|
OUTPUT_FORMAT_PREFERENCES)[0]
|
||||||
|
self.output_formats.addItems(list(map(QString, [x.upper() for x in
|
||||||
|
output_formats])))
|
||||||
|
self.output_formats.setCurrentIndex(output_formats.index(preferred_output_format))
|
||||||
|
|
||||||
|
def accept(self):
|
||||||
|
recs = GuiRecommendations()
|
||||||
|
for w in self._groups_model.widgets:
|
||||||
|
x = w.commit(save_defaults=False)
|
||||||
|
recs.update(x)
|
||||||
|
self._recommendations = recs
|
||||||
|
ResizableDialog.accept(self)
|
||||||
|
|
||||||
|
|
@ -4,8 +4,6 @@ __license__ = 'GPL 3'
|
|||||||
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
|
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from calibre.ebooks.conversion.plumber import Plumber
|
from calibre.ebooks.conversion.plumber import Plumber
|
||||||
from calibre.utils.logging import Log
|
from calibre.utils.logging import Log
|
||||||
|
|
||||||
|
28
src/calibre/gui2/convert/pdb_output.py
Normal file
28
src/calibre/gui2/convert/pdb_output.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
__license__ = 'GPL 3'
|
||||||
|
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
from calibre.gui2.convert.pdb_output_ui import Ui_Form
|
||||||
|
from calibre.gui2.convert import Widget
|
||||||
|
from calibre.ebooks.pdb import FORMAT_WRITERS
|
||||||
|
from calibre.gui2.widgets import BasicComboModel
|
||||||
|
|
||||||
|
format_model = None
|
||||||
|
|
||||||
|
class PluginWidget(Widget, Ui_Form):
|
||||||
|
|
||||||
|
TITLE = _('PDB Output')
|
||||||
|
|
||||||
|
def __init__(self, parent, get_option, get_help, db=None, book_id=None):
|
||||||
|
Widget.__init__(self, parent, 'pdb_output', ['format'])
|
||||||
|
self.db, self.book_id = db, book_id
|
||||||
|
self.initialize_options(get_option, get_help, db, book_id)
|
||||||
|
|
||||||
|
global format_model
|
||||||
|
if format_model is None:
|
||||||
|
format_model = BasicComboModel(FORMAT_WRITERS.keys())
|
||||||
|
self.format_model = format_model
|
||||||
|
self.opt_format.setModel(self.format_model)
|
||||||
|
|
44
src/calibre/gui2/convert/pdb_output.ui
Normal file
44
src/calibre/gui2/convert/pdb_output.ui
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?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>400</width>
|
||||||
|
<height>300</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">
|
||||||
|
<property name="text">
|
||||||
|
<string>Format:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QComboBox" name="opt_format"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>148</width>
|
||||||
|
<height>246</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
@ -21,18 +21,12 @@ from calibre.gui2 import config, error_dialog, Dispatcher, dynamic, \
|
|||||||
pixmap_to_data, warning_dialog, \
|
pixmap_to_data, warning_dialog, \
|
||||||
info_dialog
|
info_dialog
|
||||||
from calibre.ebooks.metadata import authors_to_string
|
from calibre.ebooks.metadata import authors_to_string
|
||||||
from calibre.gui2.dialogs.conversion_error import ConversionErrorDialog
|
|
||||||
from calibre import sanitize_file_name, preferred_encoding
|
from calibre import sanitize_file_name, preferred_encoding
|
||||||
from calibre.utils.filenames import ascii_filename
|
from calibre.utils.filenames import ascii_filename
|
||||||
from calibre.devices.errors import FreeSpaceError
|
from calibre.devices.errors import FreeSpaceError
|
||||||
from calibre.utils.smtp import compose_mail, sendmail, extract_email_address, \
|
from calibre.utils.smtp import compose_mail, sendmail, extract_email_address, \
|
||||||
config as email_config
|
config as email_config
|
||||||
|
|
||||||
def warning(title, msg, details, parent):
|
|
||||||
from calibre.gui2.widgets import WarningDialog
|
|
||||||
WarningDialog(title, msg, details, parent).exec_()
|
|
||||||
|
|
||||||
|
|
||||||
class DeviceJob(Job):
|
class DeviceJob(Job):
|
||||||
|
|
||||||
def __init__(self, func, *args, **kwargs):
|
def __init__(self, func, *args, **kwargs):
|
||||||
@ -530,13 +524,13 @@ class DeviceGUI(object):
|
|||||||
good.append(title)
|
good.append(title)
|
||||||
if errors:
|
if errors:
|
||||||
errors = '\n'.join([
|
errors = '\n'.join([
|
||||||
'<li><b>%s</b><br>%s<br>%s<br></li>' %
|
'%s\n\n%s\n%s\n' %
|
||||||
(title, e, tb.replace('\n', '<br>')) for \
|
(title, e, tb) for \
|
||||||
title, e, tb in errors
|
title, e, tb in errors
|
||||||
])
|
])
|
||||||
ConversionErrorDialog(self, _('Failed to email books'),
|
error_dialog(self, _('Failed to email books'),
|
||||||
'<p>'+_('Failed to email the following books:')+\
|
_('Failed to email the following books:'),
|
||||||
'<ul>%s</ul>'%errors,
|
'%s'%errors,
|
||||||
show=True)
|
show=True)
|
||||||
else:
|
else:
|
||||||
self.status_bar.showMessage(_('Sent by email:') + ', '.join(good),
|
self.status_bar.showMessage(_('Sent by email:') + ', '.join(good),
|
||||||
|
@ -1,113 +0,0 @@
|
|||||||
<ui version="4.0" >
|
|
||||||
<class>Dialog</class>
|
|
||||||
<widget class="QDialog" name="Dialog" >
|
|
||||||
<property name="geometry" >
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>727</width>
|
|
||||||
<height>432</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle" >
|
|
||||||
<string>Dialog</string>
|
|
||||||
</property>
|
|
||||||
<property name="windowIcon" >
|
|
||||||
<iconset resource="../images.qrc" >
|
|
||||||
<normaloff>:/images/dialog_warning.svg</normaloff>:/images/dialog_warning.svg</iconset>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout" >
|
|
||||||
<item row="0" column="0" >
|
|
||||||
<widget class="QLabel" name="msg" >
|
|
||||||
<property name="text" >
|
|
||||||
<string>TextLabel</string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap" >
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0" >
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout" >
|
|
||||||
<item>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout" >
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label" >
|
|
||||||
<property name="text" >
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="pixmap" >
|
|
||||||
<pixmap resource="../images.qrc" >:/images/dialog_warning.svg</pixmap>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="verticalSpacer" >
|
|
||||||
<property name="orientation" >
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0" >
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>40</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QTextEdit" name="details" />
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0" >
|
|
||||||
<widget class="QDialogButtonBox" name="buttonBox" >
|
|
||||||
<property name="orientation" >
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="standardButtons" >
|
|
||||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<resources>
|
|
||||||
<include location="../images.qrc" />
|
|
||||||
</resources>
|
|
||||||
<connections>
|
|
||||||
<connection>
|
|
||||||
<sender>buttonBox</sender>
|
|
||||||
<signal>accepted()</signal>
|
|
||||||
<receiver>Dialog</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>Dialog</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>
|
|
@ -24,7 +24,7 @@ from calibre.gui2 import APP_UID, warning_dialog, choose_files, error_dialog, \
|
|||||||
max_available_height, config, info_dialog, \
|
max_available_height, config, info_dialog, \
|
||||||
available_width, GetMetadata
|
available_width, GetMetadata
|
||||||
from calibre.gui2.cover_flow import CoverFlow, DatabaseImages, pictureflowerror
|
from calibre.gui2.cover_flow import CoverFlow, DatabaseImages, pictureflowerror
|
||||||
from calibre.gui2.widgets import ProgressIndicator, WarningDialog
|
from calibre.gui2.widgets import ProgressIndicator
|
||||||
from calibre.gui2.dialogs.scheduler import Scheduler
|
from calibre.gui2.dialogs.scheduler import Scheduler
|
||||||
from calibre.gui2.update import CheckForUpdates
|
from calibre.gui2.update import CheckForUpdates
|
||||||
from calibre.gui2.dialogs.progress import ProgressDialog
|
from calibre.gui2.dialogs.progress import ProgressDialog
|
||||||
@ -36,8 +36,8 @@ from calibre.gui2.jobs2 import JobManager
|
|||||||
from calibre.gui2.dialogs.metadata_single import MetadataSingleDialog
|
from calibre.gui2.dialogs.metadata_single import MetadataSingleDialog
|
||||||
from calibre.gui2.dialogs.metadata_bulk import MetadataBulkDialog
|
from calibre.gui2.dialogs.metadata_bulk import MetadataBulkDialog
|
||||||
from calibre.gui2.dialogs.jobs import JobsDialog
|
from calibre.gui2.dialogs.jobs import JobsDialog
|
||||||
from calibre.gui2.dialogs.conversion_error import ConversionErrorDialog
|
from calibre.gui2.tools import convert_single_ebook, convert_bulk_ebook, \
|
||||||
from calibre.gui2.tools import convert_single_ebook, fetch_scheduled_recipe
|
fetch_scheduled_recipe
|
||||||
from calibre.gui2.dialogs.config import ConfigDialog
|
from calibre.gui2.dialogs.config import ConfigDialog
|
||||||
from calibre.gui2.dialogs.search import SearchDialog
|
from calibre.gui2.dialogs.search import SearchDialog
|
||||||
from calibre.gui2.dialogs.choose_format import ChooseFormatDialog
|
from calibre.gui2.dialogs.choose_format import ChooseFormatDialog
|
||||||
@ -89,7 +89,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
self.persistent_files = []
|
self.persistent_files = []
|
||||||
self.metadata_dialogs = []
|
self.metadata_dialogs = []
|
||||||
self.default_thumbnail = None
|
self.default_thumbnail = None
|
||||||
self.device_error_dialog = ConversionErrorDialog(self,
|
self.device_error_dialog = error_dialog(self, _('Error'),
|
||||||
_('Error communicating with device'), ' ')
|
_('Error communicating with device'), ' ')
|
||||||
self.device_error_dialog.setModal(Qt.NonModal)
|
self.device_error_dialog.setModal(Qt.NonModal)
|
||||||
self.tb_wrapper = textwrap.TextWrapper(width=40)
|
self.tb_wrapper = textwrap.TextWrapper(width=40)
|
||||||
@ -865,16 +865,16 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
db = self.library_view.model().refresh_ids(
|
db = self.library_view.model().refresh_ids(
|
||||||
x.updated, cr)
|
x.updated, cr)
|
||||||
if x.failures:
|
if x.failures:
|
||||||
details = ['<li><b>%s:</b> %s</li>'%(title, reason) for title,
|
details = ['%s: %s'%(title, reason) for title,
|
||||||
reason in x.failures.values()]
|
reason in x.failures.values()]
|
||||||
details = '<p><ul>%s</ul></p>'%(''.join(details))
|
details = '%s\n'%('\n'.join(details))
|
||||||
WarningDialog(_('Failed to download some metadata'),
|
warning_dialog(_('Failed to download some metadata'),
|
||||||
_('Failed to download metadata for the following:'),
|
_('Failed to download metadata for the following:'),
|
||||||
details, self).exec_()
|
details, self).exec_()
|
||||||
else:
|
else:
|
||||||
err = _('<b>Failed to download metadata:')+\
|
err = _('<b>Failed to download metadata:')+\
|
||||||
'</b><br><pre>'+x.tb+'</pre>'
|
'</b><br><pre>'+x.tb+'</pre>'
|
||||||
ConversionErrorDialog(self, _('Error'), err,
|
error_dialog(self, _('Error'), err,
|
||||||
show=True)
|
show=True)
|
||||||
|
|
||||||
|
|
||||||
@ -1047,28 +1047,27 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
d = error_dialog(self, _('Cannot convert'),
|
d = error_dialog(self, _('Cannot convert'),
|
||||||
_('No books selected'))
|
_('No books selected'))
|
||||||
d.exec_()
|
d.exec_()
|
||||||
return [], []
|
return None
|
||||||
return [self.library_view.model().db.id(r) for r in rows]
|
return [self.library_view.model().db.id(r) for r in rows]
|
||||||
|
|
||||||
def convert_bulk(self, checked):
|
def convert_bulk(self, checked):
|
||||||
r = self.get_books_for_conversion()
|
row_ids = self.get_books_for_conversion()
|
||||||
if r is None:
|
if row_ids is None: return
|
||||||
return
|
previous = self.library_view.currentIndex()
|
||||||
comics, others = r
|
rows = [x.row() for x in \
|
||||||
|
self.library_view.selectionModel().selectedRows()]
|
||||||
res = convert_bulk_ebooks(self,
|
jobs, changed, bad = convert_bulk_ebook(self,
|
||||||
self.library_view.model().db, comics, others)
|
self.library_view.model().db, row_ids)
|
||||||
if res is None:
|
|
||||||
return
|
|
||||||
jobs, changed = res
|
|
||||||
for func, args, desc, fmt, id, temp_files in jobs:
|
for func, args, desc, fmt, id, temp_files in jobs:
|
||||||
job = self.job_manager.run_job(Dispatcher(self.book_converted),
|
if id not in bad:
|
||||||
|
job = self.job_manager.run_job(Dispatcher(self.book_converted),
|
||||||
func, args=args, description=desc)
|
func, args=args, description=desc)
|
||||||
self.conversion_jobs[job] = (temp_files, fmt, id)
|
self.conversion_jobs[job] = (temp_files, fmt, id)
|
||||||
|
|
||||||
if changed:
|
if changed:
|
||||||
self.library_view.model().resort(reset=False)
|
self.library_view.model().refresh_rows(rows)
|
||||||
self.library_view.model().research()
|
current = self.library_view.currentIndex()
|
||||||
|
self.library_view.model().current_changed(current, previous)
|
||||||
|
|
||||||
def convert_single(self, checked):
|
def convert_single(self, checked):
|
||||||
row_ids = self.get_books_for_conversion()
|
row_ids = self.get_books_for_conversion()
|
||||||
@ -1431,7 +1430,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
return
|
return
|
||||||
if isinstance(job.exception, JobKilled):
|
if isinstance(job.exception, JobKilled):
|
||||||
return
|
return
|
||||||
ConversionErrorDialog(self, _('Conversion Error'), job.gui_text(),
|
error_dialog(self, _('Conversion Error'), job.gui_text(),
|
||||||
show=True)
|
show=True)
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ from calibre.gui2 import warning_dialog
|
|||||||
from calibre.gui2.convert import load_specifics
|
from calibre.gui2.convert import load_specifics
|
||||||
from calibre.gui2.convert.single import NoSupportedInputFormats
|
from calibre.gui2.convert.single import NoSupportedInputFormats
|
||||||
from calibre.gui2.convert.single import Config as SingleConfig
|
from calibre.gui2.convert.single import Config as SingleConfig
|
||||||
|
from calibre.gui2.convert.bulk import BulkConfig
|
||||||
|
|
||||||
def convert_single_ebook(parent, db, book_ids, auto_conversion=False, out_format=None):
|
def convert_single_ebook(parent, db, book_ids, auto_conversion=False, out_format=None):
|
||||||
changed = False
|
changed = False
|
||||||
@ -71,109 +72,59 @@ def convert_single_ebook(parent, db, book_ids, auto_conversion=False, out_format
|
|||||||
|
|
||||||
return jobs, changed, bad
|
return jobs, changed, bad
|
||||||
|
|
||||||
def convert_bulk_ebooks(*args):
|
def convert_bulk_ebook(parent, db, book_ids):
|
||||||
pass
|
changed = False
|
||||||
#(fmt, parent, db, comics, others):
|
|
||||||
if others:
|
|
||||||
d = get_dialog(fmt)(parent, db)
|
|
||||||
if d.exec_() != QDialog.Accepted:
|
|
||||||
others, user_mi = [], None
|
|
||||||
else:
|
|
||||||
opts = d.opts
|
|
||||||
opts.verbose = 2
|
|
||||||
user_mi = d.user_mi
|
|
||||||
if comics:
|
|
||||||
comic_opts = ComicConf.get_bulk_conversion_options(parent)
|
|
||||||
if not comic_opts:
|
|
||||||
comics = []
|
|
||||||
bad_rows = []
|
|
||||||
jobs = []
|
jobs = []
|
||||||
total = sum(map(len, (others, comics)))
|
bad = []
|
||||||
|
|
||||||
|
total = len(book_ids)
|
||||||
if total == 0:
|
if total == 0:
|
||||||
return
|
return None, None, None
|
||||||
parent.status_bar.showMessage(_('Starting Bulk conversion of %d books')%total, 2000)
|
parent.status_bar.showMessage(_('Starting conversion of %d books') % total, 2000)
|
||||||
|
|
||||||
for i, row in enumerate(others+comics):
|
d = BulkConfig(parent, db)
|
||||||
row_id = db.id(row)
|
if d.exec_() != QDialog.Accepted:
|
||||||
if row in others:
|
return jobs, changed, bad
|
||||||
data = None
|
|
||||||
for _fmt in EPUB_PREFERRED_SOURCE_FORMATS:
|
|
||||||
try:
|
|
||||||
data = db.format(row, _fmt.upper())
|
|
||||||
if data is not None:
|
|
||||||
break
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
if data is None:
|
|
||||||
bad_rows.append(row)
|
|
||||||
continue
|
|
||||||
options = opts.copy()
|
|
||||||
mi = db.get_metadata(row)
|
|
||||||
if user_mi is not None:
|
|
||||||
if user_mi.series_index == 1:
|
|
||||||
user_mi.series_index = None
|
|
||||||
mi.smart_update(user_mi)
|
|
||||||
db.set_metadata(db.id(row), mi)
|
|
||||||
opf = OPFCreator(os.getcwdu(), mi)
|
|
||||||
opf_file = PersistentTemporaryFile('.opf')
|
|
||||||
opf.render(opf_file)
|
|
||||||
opf_file.close()
|
|
||||||
pt = PersistentTemporaryFile('.'+_fmt.lower())
|
|
||||||
pt.write(data)
|
|
||||||
pt.close()
|
|
||||||
of = PersistentTemporaryFile('.'+fmt)
|
|
||||||
of.close()
|
|
||||||
cover = db.cover(row)
|
|
||||||
cf = None
|
|
||||||
if cover:
|
|
||||||
cf = PersistentTemporaryFile('.jpeg')
|
|
||||||
cf.write(cover)
|
|
||||||
cf.close()
|
|
||||||
options.cover = cf.name
|
|
||||||
options.output = of.name
|
|
||||||
options.from_opf = opf_file.name
|
|
||||||
args = [options, pt.name]
|
|
||||||
desc = _('Convert book %d of %d (%s)')%(i+1, total, repr(mi.title))
|
|
||||||
temp_files = [cf] if cf is not None else []
|
|
||||||
temp_files.extend([opf_file, pt, of])
|
|
||||||
jobs.append(('any2'+fmt, args, desc, fmt.upper(), row_id, temp_files))
|
|
||||||
else:
|
|
||||||
options = comic_opts.copy()
|
|
||||||
mi = db.get_metadata(row)
|
|
||||||
if mi.title:
|
|
||||||
options.title = mi.title
|
|
||||||
if mi.authors:
|
|
||||||
options.author = ','.join(mi.authors)
|
|
||||||
data = None
|
|
||||||
for _fmt in ['cbz', 'cbr']:
|
|
||||||
try:
|
|
||||||
data = db.format(row, _fmt.upper())
|
|
||||||
if data is not None:
|
|
||||||
break
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
|
|
||||||
pt = PersistentTemporaryFile('.'+_fmt.lower())
|
output_format = d.output_format
|
||||||
pt.write(data)
|
recs = cPickle.loads(d.recommendations)
|
||||||
pt.close()
|
|
||||||
of = PersistentTemporaryFile('.'+fmt)
|
|
||||||
of.close()
|
|
||||||
setattr(options, 'output', of.name)
|
|
||||||
options.verbose = 1
|
|
||||||
args = [pt.name, options]
|
|
||||||
desc = _('Convert book %d of %d (%s)')%(i+1, total, repr(mi.title))
|
|
||||||
jobs.append(('comic2'+fmt, args, desc, fmt.upper(), row_id, [pt, of]))
|
|
||||||
|
|
||||||
if bad_rows:
|
for i, book_id in enumerate(book_ids):
|
||||||
|
temp_files = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
d = SingleConfig(parent, db, book_id, None, output_format)
|
||||||
|
d.accept()
|
||||||
|
|
||||||
|
mi = db.get_metadata(book_id, True)
|
||||||
|
in_file = db.format_abspath(book_id, d.input_format, True)
|
||||||
|
|
||||||
|
out_file = PersistentTemporaryFile('.' + output_format)
|
||||||
|
out_file.write(output_format)
|
||||||
|
out_file.close()
|
||||||
|
|
||||||
|
desc = _('Convert book %d of %d (%s)') % (i + 1, total, repr(mi.title))
|
||||||
|
|
||||||
|
args = [in_file, out_file.name, recs]
|
||||||
|
temp_files = [out_file]
|
||||||
|
jobs.append(('gui_convert', args, desc, d.output_format.upper(), book_id, temp_files))
|
||||||
|
|
||||||
|
changed = True
|
||||||
|
except NoSupportedInputFormats:
|
||||||
|
bad.append(book_id)
|
||||||
|
|
||||||
|
if bad != []:
|
||||||
res = []
|
res = []
|
||||||
for row in bad_rows:
|
for id in bad:
|
||||||
title = db.title(row)
|
title = db.title(id, True)
|
||||||
res.append('<li>%s</li>'%title)
|
res.append('%s'%title)
|
||||||
|
|
||||||
msg = _('<p>Could not convert %d of %d books, because no suitable source format was found.<ul>%s</ul>')%(len(res), total, '\n'.join(res))
|
msg = '%s' % '\n'.join(res)
|
||||||
warning_dialog(parent, _('Could not convert some books'), msg).exec_()
|
warning_dialog(parent, _('Could not convert some books'),
|
||||||
|
_('Could not convert %d of %d books, because no suitable source format was found.' % (len(res), total)),
|
||||||
|
msg).exec_()
|
||||||
|
|
||||||
return jobs, False
|
return jobs, changed, bad
|
||||||
|
|
||||||
def _fetch_news(data, fmt):
|
def _fetch_news(data, fmt):
|
||||||
pt = PersistentTemporaryFile(suffix='_feeds2%s.%s'%(fmt.lower(), fmt.lower()))
|
pt = PersistentTemporaryFile(suffix='_feeds2%s.%s'%(fmt.lower(), fmt.lower()))
|
||||||
|
@ -19,7 +19,6 @@ from calibre import fit_image
|
|||||||
from calibre.utils.fontconfig import find_font_families
|
from calibre.utils.fontconfig import find_font_families
|
||||||
from calibre.ebooks.metadata.meta import metadata_from_filename
|
from calibre.ebooks.metadata.meta import metadata_from_filename
|
||||||
from calibre.utils.config import prefs
|
from calibre.utils.config import prefs
|
||||||
from calibre.gui2.dialogs.warning_ui import Ui_Dialog as Ui_WarningDialog
|
|
||||||
|
|
||||||
class ProgressIndicator(QWidget):
|
class ProgressIndicator(QWidget):
|
||||||
|
|
||||||
@ -56,16 +55,6 @@ class ProgressIndicator(QWidget):
|
|||||||
self.movie.setPaused(True)
|
self.movie.setPaused(True)
|
||||||
self.setVisible(False)
|
self.setVisible(False)
|
||||||
|
|
||||||
|
|
||||||
class WarningDialog(QDialog, Ui_WarningDialog):
|
|
||||||
|
|
||||||
def __init__(self, title, msg, details, parent=None):
|
|
||||||
QDialog.__init__(self, parent)
|
|
||||||
self.setupUi(self)
|
|
||||||
self.setWindowTitle(title)
|
|
||||||
self.msg.setText(msg)
|
|
||||||
self.details.setText(details)
|
|
||||||
|
|
||||||
class FilenamePattern(QWidget, Ui_Form):
|
class FilenamePattern(QWidget, Ui_Form):
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
@ -305,6 +294,31 @@ class FontFamilyModel(QAbstractListModel):
|
|||||||
def index_of(self, family):
|
def index_of(self, family):
|
||||||
return self.families.index(family.strip())
|
return self.families.index(family.strip())
|
||||||
|
|
||||||
|
class BasicComboModel(QAbstractListModel):
|
||||||
|
|
||||||
|
def __init__(self, items, *args):
|
||||||
|
QAbstractListModel.__init__(self, *args)
|
||||||
|
self.items = [i for i in items]
|
||||||
|
self.items.sort()
|
||||||
|
|
||||||
|
def rowCount(self, *args):
|
||||||
|
return len(self.items)
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
try:
|
||||||
|
item = self.items[index.row()]
|
||||||
|
except:
|
||||||
|
traceback.print_exc()
|
||||||
|
return NONE
|
||||||
|
if role == Qt.DisplayRole:
|
||||||
|
return QVariant(item)
|
||||||
|
if role == Qt.FontRole:
|
||||||
|
return QVariant(QFont(item))
|
||||||
|
return NONE
|
||||||
|
|
||||||
|
def index_of(self, item):
|
||||||
|
return self.items.index(item.strip())
|
||||||
|
|
||||||
|
|
||||||
class BasicListItem(QListWidgetItem):
|
class BasicListItem(QListWidgetItem):
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user