diff --git a/src/calibre/gui2/actions/convert.py b/src/calibre/gui2/actions/convert.py index caf65932d8..36f420c7bb 100644 --- a/src/calibre/gui2/actions/convert.py +++ b/src/calibre/gui2/actions/convert.py @@ -51,7 +51,7 @@ class ConvertAction(InterfaceAction): self.queue_convert_jobs(jobs, changed, bad, rows, previous, self.book_auto_converted, extra_job_args=[on_card]) - def auto_convert_mail(self, to, fmts, delete_from_library, book_ids, format): + def auto_convert_mail(self, to, fmts, delete_from_library, book_ids, format, subject): previous = self.gui.library_view.currentIndex() rows = [x.row() for x in \ self.gui.library_view.selectionModel().selectedRows()] @@ -59,7 +59,7 @@ class ConvertAction(InterfaceAction): if jobs == []: return self.queue_convert_jobs(jobs, changed, bad, rows, previous, self.book_auto_converted_mail, - extra_job_args=[delete_from_library, to, fmts]) + extra_job_args=[delete_from_library, to, fmts, subject]) def auto_convert_news(self, book_ids, format): previous = self.gui.library_view.currentIndex() @@ -145,9 +145,10 @@ class ConvertAction(InterfaceAction): self.gui.sync_to_device(on_card, False, specific_format=fmt, send_ids=[book_id], do_auto_convert=False) def book_auto_converted_mail(self, job): - temp_files, fmt, book_id, delete_from_library, to, fmts = self.conversion_jobs[job] + temp_files, fmt, book_id, delete_from_library, to, fmts, subject = self.conversion_jobs[job] self.book_converted(job) - self.gui.send_by_mail(to, fmts, delete_from_library, specific_format=fmt, send_ids=[book_id], do_auto_convert=False) + self.gui.send_by_mail(to, fmts, delete_from_library, subject=subject, + specific_format=fmt, send_ids=[book_id], do_auto_convert=False) def book_auto_converted_news(self, job): temp_files, fmt, book_id = self.conversion_jobs[job] diff --git a/src/calibre/gui2/actions/device.py b/src/calibre/gui2/actions/device.py index a4ca95a9bb..bfefbc5f64 100644 --- a/src/calibre/gui2/actions/device.py +++ b/src/calibre/gui2/actions/device.py @@ -82,7 +82,8 @@ class ShareConnMenu(QMenu): # {{{ keys = sorted(opts.accounts.keys()) for account in keys: formats, auto, default = opts.accounts[account] - dest = 'mail:'+account+';'+formats + subject = opts.subjects.get(account, '') + dest = 'mail:'+account+';'+formats+';'+subject action1 = DeviceAction(dest, False, False, I('mail.png'), account) action2 = DeviceAction(dest, True, False, I('mail.png'), diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index 6163c01d27..4d4f66eab1 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -887,9 +887,14 @@ class DeviceMixin(object): # {{{ on_card = dest self.sync_to_device(on_card, delete, fmt) elif dest == 'mail': - to, fmts = sub_dest.split(';') + sub_dest_parts = sub_dest.split(';') + while len(sub_dest_parts) < 3: + sub_dest_parts.append('') + to = sub_dest_parts[0] + fmts = sub_dest_parts[1] + subject = ';'.join(sub_dest_parts[2:]) fmts = [x.strip().lower() for x in fmts.split(',')] - self.send_by_mail(to, fmts, delete) + self.send_by_mail(to, fmts, delete, subject=subject) def cover_to_thumbnail(self, data): if self.device_manager.device and \ diff --git a/src/calibre/gui2/email.py b/src/calibre/gui2/email.py index 81c1d9c255..c6d58fa340 100644 --- a/src/calibre/gui2/email.py +++ b/src/calibre/gui2/email.py @@ -22,6 +22,7 @@ from calibre.customize.ui import available_input_formats, available_output_forma from calibre.ebooks.metadata import authors_to_string from calibre.constants import preferred_encoding from calibre.gui2 import config, Dispatcher, warning_dialog +from calibre.library.save_to_disk import get_components from calibre.utils.config import tweaks class EmailJob(BaseJob): # {{{ @@ -210,7 +211,7 @@ class EmailMixin(object): # {{{ def __init__(self): self.emailer = Emailer(self.job_manager) - def send_by_mail(self, to, fmts, delete_from_library, send_ids=None, + def send_by_mail(self, to, fmts, delete_from_library, subject='', send_ids=None, do_auto_convert=True, specific_format=None): ids = [self.library_view.model().id(r) for r in self.library_view.selectionModel().selectedRows()] if send_ids is None else send_ids if not ids or len(ids) == 0: @@ -239,7 +240,14 @@ class EmailMixin(object): # {{{ remove_ids.append(id) jobnames.append(t) attachments.append(f) - subjects.append(_('E-book:')+ ' '+t) + if not subject: + subjects.append(_('E-book:')+ ' '+t) + else: + components = get_components(subject, mi, id) + if not components: + components = [mi.title] + subject = os.path.join(*components) + subjects.append(subject) a = authors_to_string(mi.authors if mi.authors else \ [_('Unknown')]) texts.append(_('Attached, you will find the e-book') + \ @@ -292,7 +300,7 @@ class EmailMixin(object): # {{{ if self.auto_convert_question( _('Auto convert the following books before sending via ' 'email?'), autos): - self.iactions['Convert Books'].auto_convert_mail(to, fmts, delete_from_library, auto, format) + self.iactions['Convert Books'].auto_convert_mail(to, fmts, delete_from_library, auto, format, subject) if bad: bad = '\n'.join('%s'%(i,) for i in bad) diff --git a/src/calibre/gui2/preferences/emailp.py b/src/calibre/gui2/preferences/emailp.py index 19007dfcf1..ded6891387 100644 --- a/src/calibre/gui2/preferences/emailp.py +++ b/src/calibre/gui2/preferences/emailp.py @@ -5,6 +5,8 @@ __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' +import textwrap + from PyQt4.Qt import QAbstractTableModel, QVariant, QFont, Qt @@ -17,25 +19,30 @@ from calibre.utils.smtp import config as smtp_prefs class EmailAccounts(QAbstractTableModel): # {{{ - def __init__(self, accounts): + def __init__(self, accounts, subjects): QAbstractTableModel.__init__(self) self.accounts = accounts + self.subjects = subjects self.account_order = sorted(self.accounts.keys()) - self.headers = map(QVariant, [_('Email'), _('Formats'), _('Auto send')]) + self.headers = map(QVariant, [_('Email'), _('Formats'), _('Subject'), _('Auto send')]) self.default_font = QFont() self.default_font.setBold(True) self.default_font = QVariant(self.default_font) - self.tooltips =[NONE] + map(QVariant, + self.tooltips =[NONE] + list(map(QVariant, map(textwrap.fill, [_('Formats to email. The first matching format will be sent.'), + _('Subject of the email to use when sending. When left blank ' + 'the title will be used for the subject. Also, the same ' + 'templates used for "Save to disk" such as {title} and ' + '{author_sort} can be used here.'), '

'+_('If checked, downloaded news will be automatically ' 'mailed
to this email address ' - '(provided it is in one of the listed formats).')]) + '(provided it is in one of the listed formats).')]))) def rowCount(self, *args): return len(self.account_order) def columnCount(self, *args): - return 3 + return len(self.headers) def headerData(self, section, orientation, role): if role == Qt.DisplayRole and orientation == Qt.Horizontal: @@ -56,14 +63,16 @@ class EmailAccounts(QAbstractTableModel): # {{{ return QVariant(account) if col == 1: return QVariant(self.accounts[account][0]) + if col == 2: + return QVariant(self.subjects.get(account, '')) if role == Qt.FontRole and self.accounts[account][2]: return self.default_font - if role == Qt.CheckStateRole and col == 2: + if role == Qt.CheckStateRole and col == 3: return QVariant(Qt.Checked if self.accounts[account][1] else Qt.Unchecked) return NONE def flags(self, index): - if index.column() == 2: + if index.column() == 3: return QAbstractTableModel.flags(self, index)|Qt.ItemIsUserCheckable else: return QAbstractTableModel.flags(self, index)|Qt.ItemIsEditable @@ -73,8 +82,10 @@ class EmailAccounts(QAbstractTableModel): # {{{ return False row, col = index.row(), index.column() account = self.account_order[row] - if col == 2: + if col == 3: self.accounts[account][1] ^= True + if col == 2: + self.subjects[account] = unicode(value.toString()) elif col == 1: self.accounts[account][0] = unicode(value.toString()).upper() else: @@ -143,7 +154,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): self.send_email_widget.initialize(self.preferred_to_address) self.send_email_widget.changed_signal.connect(self.changed_signal.emit) opts = self.send_email_widget.smtp_opts - self._email_accounts = EmailAccounts(opts.accounts) + self._email_accounts = EmailAccounts(opts.accounts, opts.subjects) self._email_accounts.dataChanged.connect(lambda x,y: self.changed_signal.emit()) self.email_view.setModel(self._email_accounts) @@ -170,6 +181,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): if not self.send_email_widget.set_email_settings(to_set): raise AbortCommit('abort') self.proxy['accounts'] = self._email_accounts.accounts + self.proxy['subjects'] = self._email_accounts.subjects return ConfigWidgetBase.commit(self) diff --git a/src/calibre/utils/smtp.py b/src/calibre/utils/smtp.py index 81936a8f71..1e05cf8287 100644 --- a/src/calibre/utils/smtp.py +++ b/src/calibre/utils/smtp.py @@ -250,6 +250,7 @@ def config(defaults=None): c = Config('smtp',desc) if defaults is None else StringConfig(defaults,desc) c.add_opt('from_') c.add_opt('accounts', default={}) + c.add_opt('subjects', default={}) c.add_opt('relay_host') c.add_opt('relay_port', default=25) c.add_opt('relay_username')