diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index a5007fe618..6f5a858d49 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -766,8 +766,17 @@ class Sending(PreferencesPlugin): name_order = 3 config_widget = 'calibre.gui2.preferences.sending' +class Email(PreferencesPlugin): + name = 'Email' + gui_name = _('Sending books by email') + category = 'Sharing' + gui_category = _('Sharing') + category_order = 4 + name_order = 1 + config_widget = 'calibre.gui2.preferences.emailp' + plugins += [LookAndFeel, Behavior, Columns, Toolbar, InputOptions, - CommonOptions, OutputOptions, Adding, Saving, Sending] + CommonOptions, OutputOptions, Adding, Saving, Sending, Email] #}}} diff --git a/src/calibre/gui2/preferences/__init__.py b/src/calibre/gui2/preferences/__init__.py index ab4ffe3f3b..4f895c97c4 100644 --- a/src/calibre/gui2/preferences/__init__.py +++ b/src/calibre/gui2/preferences/__init__.py @@ -19,6 +19,7 @@ class AbortCommit(Exception): class ConfigWidgetInterface(object): changed_signal = None + supports_restoring_to_defaults = True def genesis(self, gui): raise NotImplementedError() @@ -165,6 +166,7 @@ class CommaSeparatedList(Setting): class ConfigWidgetBase(QWidget, ConfigWidgetInterface): changed_signal = pyqtSignal() + supports_restoring_to_defaults = True def __init__(self, parent=None): QWidget.__init__(self, parent) @@ -243,6 +245,7 @@ def test_widget(category, name, gui=None): w = pl.create_widget(d) d.set_widget(w) bb.button(bb.RestoreDefaults).clicked.connect(w.restore_defaults) + bb.button(bb.RestoreDefaults).setEnabled(w.supports_restoring_to_defaults) bb.button(bb.Apply).setEnabled(False) bb.button(bb.Apply).clicked.connect(d.accept) w.changed_signal.connect(lambda : bb.button(bb.Apply).setEnabled(True)) diff --git a/src/calibre/gui2/preferences/email.ui b/src/calibre/gui2/preferences/email.ui new file mode 100644 index 0000000000..2ffeb756d9 --- /dev/null +++ b/src/calibre/gui2/preferences/email.ui @@ -0,0 +1,112 @@ + + + Form + + + + 0 + 0 + 701 + 494 + + + + Form + + + + + + calibre can send your books to you (or your reader) by email. Emails will be automatically sent for downloaded news to all email addresses that have Auto-send checked. + + + true + + + + + + + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + + + + + + + Add an email address to which to send books + + + &Add email + + + + :/images/plus.png:/images/plus.png + + + + 24 + 24 + + + + Qt::ToolButtonTextUnderIcon + + + + + + + Make &default + + + + + + + &Remove email + + + + :/images/minus.png:/images/minus.png + + + + 24 + 24 + + + + Qt::ToolButtonTextUnderIcon + + + + + + + + + + + + + + + SendEmail + QWidget +
calibre/gui2/wizard/send_email.h
+ 1 +
+
+ + + + +
diff --git a/src/calibre/gui2/preferences/emailp.py b/src/calibre/gui2/preferences/emailp.py new file mode 100644 index 0000000000..f0b079e209 --- /dev/null +++ b/src/calibre/gui2/preferences/emailp.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai + +__license__ = 'GPL v3' +__copyright__ = '2010, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + +from PyQt4.Qt import QAbstractTableModel, QVariant, QFont, Qt + + +from calibre.gui2.preferences import ConfigWidgetBase, test_widget, \ + AbortCommit +from calibre.gui2.preferences.email_ui import Ui_Form +from calibre.utils.config import ConfigProxy +from calibre.gui2 import NONE +from calibre.utils.smtp import config as smtp_prefs + +class EmailAccounts(QAbstractTableModel): # {{{ + + def __init__(self, accounts): + QAbstractTableModel.__init__(self) + self.accounts = accounts + self.account_order = sorted(self.accounts.keys()) + self.headers = map(QVariant, [_('Email'), _('Formats'), _('Auto send')]) + self.default_font = QFont() + self.default_font.setBold(True) + self.default_font = QVariant(self.default_font) + self.tooltips =[NONE] + map(QVariant, + [_('Formats to email. The first matching format will be sent.'), + '

'+_('If checked, downloaded news will be automatically ' + 'mailed
to this email address ' + '(provided it is in one of the listed formats).')]) + + def rowCount(self, *args): + return len(self.account_order) + + def columnCount(self, *args): + return 3 + + def headerData(self, section, orientation, role): + if role == Qt.DisplayRole and orientation == Qt.Horizontal: + return self.headers[section] + return NONE + + def data(self, index, role): + row, col = index.row(), index.column() + if row < 0 or row >= self.rowCount(): + return NONE + account = self.account_order[row] + if role == Qt.UserRole: + return (account, self.accounts[account]) + if role == Qt.ToolTipRole: + return self.tooltips[col] + if role in [Qt.DisplayRole, Qt.EditRole]: + if col == 0: + return QVariant(account) + if col == 1: + return QVariant(self.accounts[account][0]) + if role == Qt.FontRole and self.accounts[account][2]: + return self.default_font + if role == Qt.CheckStateRole and col == 2: + return QVariant(Qt.Checked if self.accounts[account][1] else Qt.Unchecked) + return NONE + + def flags(self, index): + if index.column() == 2: + return QAbstractTableModel.flags(self, index)|Qt.ItemIsUserCheckable + else: + return QAbstractTableModel.flags(self, index)|Qt.ItemIsEditable + + def setData(self, index, value, role): + if not index.isValid(): + return False + row, col = index.row(), index.column() + account = self.account_order[row] + if col == 2: + self.accounts[account][1] ^= True + elif col == 1: + self.accounts[account][0] = unicode(value.toString()).upper() + else: + na = unicode(value.toString()) + from email.utils import parseaddr + addr = parseaddr(na)[-1] + if not addr: + return False + self.accounts[na] = self.accounts.pop(account) + self.account_order[row] = na + if '@kindle.com' in addr: + self.accounts[na][0] = 'AZW, MOBI, TPZ, PRC, AZW1' + + self.dataChanged.emit( + self.index(index.row(), 0), self.index(index.row(), 2)) + return True + + def make_default(self, index): + if index.isValid(): + row = index.row() + for x in self.accounts.values(): + x[2] = False + self.accounts[self.account_order[row]][2] = True + self.reset() + + def add(self): + x = _('new email address') + y = x + c = 0 + while y in self.accounts: + c += 1 + y = x + str(c) + auto_send = len(self.accounts) < 1 + self.accounts[y] = ['MOBI, EPUB', auto_send, + len(self.account_order) == 0] + self.account_order = sorted(self.accounts.keys()) + self.reset() + return self.index(self.account_order.index(y), 0) + + def remove(self, index): + if index.isValid(): + row = index.row() + account = self.account_order[row] + self.accounts.pop(account) + self.account_order = sorted(self.accounts.keys()) + has_default = False + for account in self.account_order: + if self.accounts[account][2]: + has_default = True + break + if not has_default and self.account_order: + self.accounts[self.account_order[0]][2] = True + + self.reset() + +# }}} + +class ConfigWidget(ConfigWidgetBase, Ui_Form): + + supports_restoring_to_defaults = False + + def genesis(self, gui): + self.gui = gui + self.proxy = ConfigProxy(smtp_prefs()) + + 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.dataChanged.connect(lambda x,y: + self.changed_signal.emit()) + self.email_view.setModel(self._email_accounts) + + self.email_add.clicked.connect(self.add_email_account) + self.email_make_default.clicked.connect(self.make_default) + self.email_view.resizeColumnsToContents() + self.email_remove.clicked.connect(self.remove_email_account) + + def preferred_to_address(self): + if self._email_accounts.account_order: + return self._email_accounts.account_order[0] + + def initialize(self): + ConfigWidgetBase.initialize(self) + # Initializing all done in genesis + + def restore_defaults(self): + ConfigWidgetBase.restore_defaults(self) + # No defaults to restore to + + def commit(self): + to_set = bool(self._email_accounts.accounts) + if not self.send_email_widget.set_email_settings(to_set): + raise AbortCommit('abort') + self.proxy['accounts'] = self._email_accounts.accounts + return ConfigWidgetBase.commit(self) + + def make_default(self, *args): + self._email_accounts.make_default(self.email_view.currentIndex()) + self.changed_signal.emit() + + def add_email_account(self, *args): + index = self._email_accounts.add() + self.email_view.setCurrentIndex(index) + self.email_view.resizeColumnsToContents() + self.email_view.edit(index) + self.changed_signal.emit() + + def remove_email_account(self, *args): + idx = self.email_view.currentIndex() + self._email_accounts.remove(idx) + self.changed_signal.emit() + + +if __name__ == '__main__': + from PyQt4.Qt import QApplication + app = QApplication([]) + test_widget('Sharing', 'Email') + diff --git a/src/calibre/gui2/wizard/send_email.py b/src/calibre/gui2/wizard/send_email.py index 504c426359..61b9c9f934 100644 --- a/src/calibre/gui2/wizard/send_email.py +++ b/src/calibre/gui2/wizard/send_email.py @@ -9,7 +9,7 @@ __docformat__ = 'restructuredtext en' import cStringIO, sys from binascii import hexlify, unhexlify -from PyQt4.Qt import QWidget, SIGNAL, QDialog, Qt +from PyQt4.Qt import QWidget, pyqtSignal, QDialog, Qt from calibre.gui2.wizard.send_email_ui import Ui_Form from calibre.utils.smtp import config as smtp_prefs @@ -24,7 +24,7 @@ class TestEmail(QDialog, TE_Dialog): self.setupUi(self) opts = smtp_prefs().parse() self.test_func = parent.test_email_settings - self.connect(self.test_button, SIGNAL('clicked(bool)'), self.test) + self.test_button.clicked.connect(self.test) self.from_.setText(unicode(self.from_.text())%opts.from_) if pa: self.to.setText(pa) @@ -33,7 +33,7 @@ class TestEmail(QDialog, TE_Dialog): (opts.relay_username, unhexlify(opts.relay_password), opts.relay_host, opts.relay_port, opts.encryption)) - def test(self): + def test(self, *args): self.log.setPlainText(_('Sending...')) self.test_button.setEnabled(False) try: @@ -47,6 +47,8 @@ class TestEmail(QDialog, TE_Dialog): class SendEmail(QWidget, Ui_Form): + changed_signal = pyqtSignal() + def __init__(self, parent=None): QWidget.__init__(self, parent) self.setupUi(self) @@ -57,23 +59,31 @@ class SendEmail(QWidget, Ui_Form): self.smtp_opts = opts if opts.from_: self.email_from.setText(opts.from_) + self.email_from.textChanged.connect(self.changed) if opts.relay_host: self.relay_host.setText(opts.relay_host) + self.relay_host.textChanged.connect(self.changed) self.relay_port.setValue(opts.relay_port) + self.relay_port.valueChanged.connect(self.changed) if opts.relay_username: self.relay_username.setText(opts.relay_username) + self.relay_username.textChanged.connect(self.changed) if opts.relay_password: self.relay_password.setText(unhexlify(opts.relay_password)) + self.relay_password.textChanged.connect(self.changed) (self.relay_tls if opts.encryption == 'TLS' else self.relay_ssl).setChecked(True) - self.connect(self.relay_use_gmail, SIGNAL('clicked(bool)'), - self.create_gmail_relay) - self.connect(self.relay_show_password, SIGNAL('stateChanged(int)'), - lambda - state:self.relay_password.setEchoMode(self.relay_password.Password if - state == 0 else self.relay_password.Normal)) - self.connect(self.test_email_button, SIGNAL('clicked(bool)'), - self.test_email) + self.relay_tls.toggled.connect(self.changed) + self.relay_use_gmail.clicked.connect( + self.create_gmail_relay) + self.relay_show_password.stateChanged.connect( + lambda state : self.relay_password.setEchoMode( + self.relay_password.Password if + state == 0 else self.relay_password.Normal)) + self.test_email_button.clicked.connect(self.test_email) + + def changed(self, *args): + self.changed_signal.emit() def test_email(self, *args): pa = self.preferred_to_address()