Start bulk convert. Replace error and warning dialogs with Qts.

This commit is contained in:
John Schember 2009-05-07 19:12:39 -04:00
parent f92cc8ac2d
commit 4b5392bf01
6 changed files with 87 additions and 267 deletions

View File

@ -7,7 +7,7 @@ from PyQt4.Qt import QThread, SIGNAL, QMutex, QWaitCondition, Qt
from calibre.gui2.dialogs.progress import ProgressDialog
from calibre.constants import preferred_encoding
from calibre.gui2.widgets import WarningDialog
from calibre.gui2 import warning_dialog
class Add(QThread):
@ -113,13 +113,13 @@ class AddFiles(Add):
def process_duplicates(self):
if self.duplicates:
files = _('<p>Books with the same title as the following already '
'exist in the database. Add them anyway?<ul>')
files = ''
for mi in self.duplicates[2]:
files += '<li>'+mi.title+'</li>\n'
d = WarningDialog (_('Duplicates found!'),
_('Duplicates found!'),
files+'</ul></p>', parent=self._parent)
files += mi.title+'\n'
d = warning_dialog(_('Duplicates found!'),
_('Books with the same title as the following already '
'exist in the database. Add them anyway?'),
files, parent=self._parent)
if d.exec_() == d.Accepted:
num = self.db.add_books(*self.duplicates,
**dict(add_duplicates=True))[1]
@ -221,19 +221,19 @@ class AddRecursive(Add):
def process_duplicates(self):
if self.duplicates:
files = _('<p>Books with the same title as the following already '
'exist in the database. Add them anyway?<ul>')
files = ''
for mi in self.duplicates:
title = mi[0].title
if not isinstance(title, unicode):
title = title.decode(preferred_encoding, 'replace')
files += '<li>'+title+'</li>\n'
d = WarningDialog (_('Duplicates found!'),
_('Duplicates found!'),
files+'</ul></p>', parent=self._parent)
files += title+'\n'
d = warning_dialog(_('Duplicates found!'),
_('Books with the same title as the following already '
'exist in the database. Add them anyway?'),
files, parent=self._parent)
if d.exec_() == d.Accepted:
for mi, formats in self.duplicates:
self.db.import_book(mi, formats, notify=False)
self.number_of_books_added += 1

View File

@ -21,18 +21,12 @@ from calibre.gui2 import config, error_dialog, Dispatcher, dynamic, \
pixmap_to_data, warning_dialog, \
info_dialog
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.utils.filenames import ascii_filename
from calibre.devices.errors import FreeSpaceError
from calibre.utils.smtp import compose_mail, sendmail, extract_email_address, \
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):
def __init__(self, func, *args, **kwargs):
@ -530,13 +524,13 @@ class DeviceGUI(object):
good.append(title)
if errors:
errors = '\n'.join([
'<li><b>%s</b><br>%s<br>%s<br></li>' %
(title, e, tb.replace('\n', '<br>')) for \
'%s\n\n%s\n%s\n' %
(title, e, tb) for \
title, e, tb in errors
])
ConversionErrorDialog(self, _('Failed to email books'),
'<p>'+_('Failed to email the following books:')+\
'<ul>%s</ul>'%errors,
error_dialog(self, _('Failed to email books'),
_('Failed to email the following books:'),
'%s'%errors,
show=True)
else:
self.status_bar.showMessage(_('Sent by email:') + ', '.join(good),

View File

@ -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>

View File

@ -24,7 +24,7 @@ from calibre.gui2 import APP_UID, warning_dialog, choose_files, error_dialog, \
max_available_height, config, info_dialog, \
available_width, GetMetadata
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.update import CheckForUpdates
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_bulk import MetadataBulkDialog
from calibre.gui2.dialogs.jobs import JobsDialog
from calibre.gui2.dialogs.conversion_error import ConversionErrorDialog
from calibre.gui2.tools import convert_single_ebook, fetch_scheduled_recipe
from calibre.gui2.tools import convert_single_ebook, convert_bulk_ebook, \
fetch_scheduled_recipe
from calibre.gui2.dialogs.config import ConfigDialog
from calibre.gui2.dialogs.search import SearchDialog
from calibre.gui2.dialogs.choose_format import ChooseFormatDialog
@ -89,7 +89,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.persistent_files = []
self.metadata_dialogs = []
self.default_thumbnail = None
self.device_error_dialog = ConversionErrorDialog(self,
self.device_error_dialog = error_dialog(self, _('Error'),
_('Error communicating with device'), ' ')
self.device_error_dialog.setModal(Qt.NonModal)
self.tb_wrapper = textwrap.TextWrapper(width=40)
@ -865,16 +865,16 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
db = self.library_view.model().refresh_ids(
x.updated, cr)
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()]
details = '<p><ul>%s</ul></p>'%(''.join(details))
WarningDialog(_('Failed to download some metadata'),
details = '%s\n'%('\n'.join(details))
warning_dialog(_('Failed to download some metadata'),
_('Failed to download metadata for the following:'),
details, self).exec_()
else:
err = _('<b>Failed to download metadata:')+\
'</b><br><pre>'+x.tb+'</pre>'
ConversionErrorDialog(self, _('Error'), err,
error_dialog(self, _('Error'), err,
show=True)
@ -1051,24 +1051,23 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
return [self.library_view.model().db.id(r) for r in rows]
def convert_bulk(self, checked):
r = self.get_books_for_conversion()
if r is None:
return
comics, others = r
res = convert_bulk_ebooks(self,
self.library_view.model().db, comics, others)
if res is None:
return
jobs, changed = res
row_ids = self.get_books_for_conversion()
if row_ids is None: return
previous = self.library_view.currentIndex()
rows = [x.row() for x in \
self.library_view.selectionModel().selectedRows()]
jobs, changed, bad = convert_bulk_ebook(self,
self.library_view.model().db, row_ids)
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)
self.conversion_jobs[job] = (temp_files, fmt, id)
self.conversion_jobs[job] = (temp_files, fmt, id)
if changed:
self.library_view.model().resort(reset=False)
self.library_view.model().research()
self.library_view.model().refresh_rows(rows)
current = self.library_view.currentIndex()
self.library_view.model().current_changed(current, previous)
def convert_single(self, checked):
row_ids = self.get_books_for_conversion()
@ -1431,7 +1430,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
return
if isinstance(job.exception, JobKilled):
return
ConversionErrorDialog(self, _('Conversion Error'), job.gui_text(),
error_dialog(self, _('Conversion Error'), job.gui_text(),
show=True)

View File

@ -71,109 +71,60 @@ def convert_single_ebook(parent, db, book_ids, auto_conversion=False, out_format
return jobs, changed, bad
def convert_bulk_ebooks(*args):
pass
#(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 = []
def convert_bulk_ebook(parent, db, book_ids):
return [], False, []
changed = False
jobs = []
total = sum(map(len, (others, comics)))
bad = []
total = len(book_ids)
if total == 0:
return
parent.status_bar.showMessage(_('Starting Bulk conversion of %d books')%total, 2000)
return None, None, None
parent.status_bar.showMessage(_('Starting conversion of %d books') % total, 2000)
for i, row in enumerate(others+comics):
row_id = db.id(row)
if row in others:
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
d = SingleConfig(parent, db)
if d.exec_() != QDialog.Accepted:
return jobs, changed, bad
pt = PersistentTemporaryFile('.'+_fmt.lower())
pt.write(data)
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]))
out_format = d.output_format
recs = cPickle.loads(d.recommendations)
if bad_rows:
for i, book_id in enumerate(book_ids):
temp_files = []
try:
d = SingleConfig(parent, db, book_id, None, out_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 = []
for row in bad_rows:
title = db.title(row)
res.append('<li>%s</li>'%title)
for id in bad:
title = db.title(id, True)
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))
warning_dialog(parent, _('Could not convert some books'), msg).exec_()
msg = '%s' % '\n'.join(res)
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):
pt = PersistentTemporaryFile(suffix='_feeds2%s.%s'%(fmt.lower(), fmt.lower()))

View File

@ -19,7 +19,6 @@ from calibre import fit_image
from calibre.utils.fontconfig import find_font_families
from calibre.ebooks.metadata.meta import metadata_from_filename
from calibre.utils.config import prefs
from calibre.gui2.dialogs.warning_ui import Ui_Dialog as Ui_WarningDialog
class ProgressIndicator(QWidget):
@ -56,16 +55,6 @@ class ProgressIndicator(QWidget):
self.movie.setPaused(True)
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):
def __init__(self, parent):