mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 18:54:09 -04:00
Preferences widget for email sending
This commit is contained in:
parent
6b8d204f07
commit
a6bd77247d
@ -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]
|
||||
|
||||
#}}}
|
||||
|
||||
|
@ -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))
|
||||
|
112
src/calibre/gui2/preferences/email.ui
Normal file
112
src/calibre/gui2/preferences/email.ui
Normal 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>&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 &default</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="email_remove">
|
||||
<property name="text">
|
||||
<string>&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>
|
196
src/calibre/gui2/preferences/emailp.py
Normal file
196
src/calibre/gui2/preferences/emailp.py
Normal 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')
|
||||
|
@ -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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user