Preferences widget for email sending

This commit is contained in:
Kovid Goyal 2010-09-04 22:33:33 -06:00
parent 6b8d204f07
commit a6bd77247d
5 changed files with 342 additions and 12 deletions

View File

@ -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]
#}}}

View File

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

View File

@ -0,0 +1,112 @@
<?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>701</width>
<height>494</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_22">
<property name="text">
<string>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.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QTableView" name="email_view">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="QToolButton" name="email_add">
<property name="toolTip">
<string>Add an email address to which to send books</string>
</property>
<property name="text">
<string>&amp;Add email</string>
</property>
<property name="icon">
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/plus.png</normaloff>:/images/plus.png</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextUnderIcon</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="email_make_default">
<property name="text">
<string>Make &amp;default</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="email_remove">
<property name="text">
<string>&amp;Remove email</string>
</property>
<property name="icon">
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/minus.png</normaloff>:/images/minus.png</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextUnderIcon</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="SendEmail" name="send_email_widget" native="true"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>SendEmail</class>
<extends>QWidget</extends>
<header>calibre/gui2/wizard/send_email.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../../../../resources/images.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -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 <kovid@kovidgoyal.net>'
__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.'),
'<p>'+_('If checked, downloaded news will be automatically '
'mailed <br>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')

View File

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