%PDF- %PDF-
| Direktori : /lib/calibre/calibre/gui2/preferences/ |
| Current File : //lib/calibre/calibre/gui2/preferences/emailp.py |
#!/usr/bin/env python3
# License: GPLv3 Copyright: 2010, Kovid Goyal <kovid at kovidgoyal.net>
import re
import textwrap
from qt.core import QAbstractTableModel, QFont, Qt, QAbstractItemView
from calibre.gui2 import gprefs
from calibre.gui2.preferences import AbortCommit, ConfigWidgetBase, test_widget
from calibre.gui2.preferences.email_ui import Ui_Form
from calibre.utils.config import ConfigProxy
from calibre.utils.icu import numeric_sort_key
from calibre.utils.smtp import config as smtp_prefs
from polyglot.builtins import as_unicode
class EmailAccounts(QAbstractTableModel): # {{{
def __init__(self, accounts, subjects, aliases={}, tags={}):
QAbstractTableModel.__init__(self)
self.accounts = accounts
self.subjects = subjects
self.aliases = aliases
self.tags = tags
self.sorted_on = (0, True)
self.account_order = list(self.accounts)
self.do_sort()
self.headers = [_('Email'), _('Formats'), _('Subject'),
_('Auto send'), _('Alias'), _('Auto send only tags')]
self.default_font = QFont()
self.default_font.setBold(True)
self.default_font = (self.default_font)
self.tooltips =[None] + list(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.'),
'<p>'+_('If checked, downloaded news will be automatically '
'mailed to this email address '
'(provided it is in one of the listed formats and has not been filtered by tags).'),
_('Friendly name to use for this email address'),
_('If specified, only news with one of these tags will be sent to'
' this email address. All news downloads have their title as a'
' tag, so you can use this to easily control which news downloads'
' are sent to this email address.')
]))
def do_sort(self):
col = self.sorted_on[0]
if col == 0:
def key(account_key):
return numeric_sort_key(account_key)
elif col == 1:
def key(account_key):
return numeric_sort_key(self.accounts[account_key][0] or '')
elif col == 2:
def key(account_key):
return numeric_sort_key(self.subjects.get(account_key) or '')
elif col == 3:
def key(account_key):
return numeric_sort_key(as_unicode(self.accounts[account_key][0]) or '')
elif col == 4:
def key(account_key):
return numeric_sort_key(self.aliases.get(account_key) or '')
elif col == 5:
def key(account_key):
return numeric_sort_key(self.tags.get(account_key) or '')
self.account_order.sort(key=key, reverse=not self.sorted_on[1])
def sort(self, column, order=Qt.SortOrder.AscendingOrder):
nsort = (column, order == Qt.SortOrder.AscendingOrder)
if nsort != self.sorted_on:
self.sorted_on = nsort
self.beginResetModel()
try:
self.do_sort()
finally:
self.endResetModel()
def rowCount(self, *args):
return len(self.account_order)
def columnCount(self, *args):
return len(self.headers)
def headerData(self, section, orientation, role):
if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.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 account not in self.accounts:
return None
if role == Qt.ItemDataRole.UserRole:
return (account, self.accounts[account])
if role == Qt.ItemDataRole.ToolTipRole:
return self.tooltips[col]
if role in [Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.EditRole]:
if col == 0:
return (account)
if col == 1:
return ', '.join(x.strip() for x in (self.accounts[account][0] or '').split(','))
if col == 2:
return (self.subjects.get(account, ''))
if col == 4:
return (self.aliases.get(account, ''))
if col == 5:
return (self.tags.get(account, ''))
if role == Qt.ItemDataRole.FontRole and self.accounts[account][2]:
return self.default_font
if role == Qt.ItemDataRole.CheckStateRole and col == 3:
return (Qt.CheckState.Checked if self.accounts[account][1] else Qt.CheckState.Unchecked)
return None
def flags(self, index):
if index.column() == 3:
return QAbstractTableModel.flags(self, index)|Qt.ItemFlag.ItemIsUserCheckable
else:
return QAbstractTableModel.flags(self, index)|Qt.ItemFlag.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 == 3:
self.accounts[account][1] ^= True
elif col == 2:
self.subjects[account] = as_unicode(value or '')
elif col == 4:
self.aliases.pop(account, None)
aval = as_unicode(value or '').strip()
if aval:
self.aliases[account] = aval
elif col == 5:
self.tags.pop(account, None)
aval = as_unicode(value or '').strip()
if aval:
self.tags[account] = aval
elif col == 1:
self.accounts[account][0] = re.sub(',+', ',', re.sub(r'\s+', ',', as_unicode(value or '').upper()))
elif col == 0:
na = as_unicode(value or '')
from email.utils import parseaddr
addr = parseaddr(na)[-1]
if not addr or '@' not in na:
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(), 3))
return True
def make_default(self, index):
if index.isValid():
self.beginResetModel()
row = index.row()
for x in self.accounts.values():
x[2] = False
self.accounts[self.account_order[row]][2] = True
self.endResetModel()
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.beginResetModel()
self.accounts[y] = ['MOBI, EPUB', auto_send,
len(self.account_order) == 0]
self.account_order = list(self.accounts)
self.do_sort()
self.endResetModel()
return self.index(self.account_order.index(y), 0)
def remove_rows(self, *rows):
for row in sorted(rows, reverse=True):
try:
account = self.account_order[row]
except Exception:
continue
self.accounts.pop(account)
self.account_order = sorted(self.accounts)
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.beginResetModel()
self.endResetModel()
self.do_sort()
def remove(self, index):
if index.isValid():
self.remove(index.row())
# }}}
class ConfigWidget(ConfigWidgetBase, Ui_Form):
supports_restoring_to_defaults = False
def genesis(self, gui):
self.gui = gui
self.proxy = ConfigProxy(smtp_prefs())
r = self.register
r('add_comments_to_email', gprefs)
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, opts.subjects,
opts.aliases, opts.tags)
connect_lambda(self._email_accounts.dataChanged, self, lambda self: self.changed_signal.emit())
self.email_view.setModel(self._email_accounts)
self.email_view.sortByColumn(0, Qt.SortOrder.AscendingOrder)
self.email_view.setSortingEnabled(True)
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):
if self.email_view.state() == QAbstractItemView.State.EditingState:
# Ensure that the cell being edited is committed by switching focus
# to some other widget, which automatically closes the open editor
self.send_email_widget.setFocus(Qt.FocusReason.OtherFocusReason)
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
self.proxy['subjects'] = self._email_accounts.subjects
self.proxy['aliases'] = self._email_accounts.aliases
self.proxy['tags'] = self._email_accounts.tags
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):
rows = set()
for idx in self.email_view.selectionModel().selectedIndexes():
rows.add(idx.row())
self._email_accounts.remove_rows(*rows)
self.changed_signal.emit()
def refresh_gui(self, gui):
from calibre.gui2.email import gui_sendmail
gui_sendmail.calculate_rate_limit()
if __name__ == '__main__':
from calibre.gui2 import Application
app = Application([])
test_widget('Sharing', 'Email')