format mailto() sources

some exception dialog enhancements
This commit is contained in:
M2j 2010-12-11 16:39:12 +01:00
parent 1cb9594e58
commit c28b129421
5 changed files with 227 additions and 133 deletions

View File

@ -0,0 +1,38 @@
PSF LICENSE AGREEMENT FOR PYTHON 2.7.1
1. This LICENSE AGREEMENT is between the Python Software Foundation (“PSF”),
and the Individual or Organization (“Licensee”) accessing and otherwise
using Python 2.7.1 software in source or binary form and its associated
documentation.
2. Subject to the terms and conditions of this License Agreement, PSF hereby
grants Licensee a nonexclusive, royalty-free, world-wide license to
reproduce, analyze, test, perform and/or display publicly, prepare
derivative works, distribute, and otherwise use Python 2.7.1 alone or in any
derivative version, provided, however, that PSFs License Agreement and
PSFs notice of copyright, i.e., “Copyright © 2001-2010 Python Software
Foundation; All Rights Reserved” are retained in Python 2.7.1 alone or in
any derivative version prepared by Licensee.
3. In the event Licensee prepares a derivative work that is based on or
incorporates Python 2.7.1 or any part thereof, and wants to make the
derivative work available to others as provided herein, then Licensee hereby
agrees to include in any such work a brief summary of the changes made to
Python 2.7.1.
4. PSF is making Python 2.7.1 available to Licensee on an “AS IS” basis. PSF
MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION
OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT
THE USE OF PYTHON 2.7.1 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 2.7.1 FOR
ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.7.1, OR ANY DERIVATIVE
THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
6. This License Agreement will automatically terminate upon a material breach
of its terms and conditions.
7. Nothing in this License Agreement shall be deemed to create any relationship
of agency, partnership, or joint venture between PSF and Licensee. This
License Agreement does not grant permission to use PSF trademarks or trade
name in a trademark sense to endorse or promote products or services of
Licensee, or any third party.
8. By copying, installing or otherwise using Python 2.7.1, Licensee agrees to
be bound by the terms and conditions of this License Agreement.

View File

@ -1,12 +1,24 @@
#!/usr/bin/env python # -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
'''Utilities for opening files or URLs in the registered default application ###############################################################################
and for sending e-mail using the user's preferred composer. # Utilities for opening files or URLs in the registered default application #
# and for sending e-mail using the user's preferred composer. #
# --------------------------------------------------------------------------- #
# Copyright (c) 2007 Antonio Valentino #
# All rights reserved. #
# --------------------------------------------------------------------------- #
# This program offered under the PSF License as published by the Python #
# Software Foundation. #
# #
# The license text can be found at http://docs.python.org/license.html #
# #
# This code is taken from: http://code.activestate.com/recipes/511443 #
# It is modified to be used in OpenLP (http://openlp.org) #
###############################################################################
''' __version__ = u'1.1'
__all__ = [u'open', u'mailto']
__version__ = '1.1'
__all__ = ['open', 'mailto']
import os import os
import sys import sys
@ -20,7 +32,9 @@ _open = None
class BaseController(object): class BaseController(object):
'''Base class for open program controllers.''' """
Base class for open program controllers.
"""
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
@ -30,14 +44,16 @@ class BaseController(object):
class Controller(BaseController): class Controller(BaseController):
'''Controller for a generic open program.''' """
Controller for a generic open program.
"""
def __init__(self, *args): def __init__(self, *args):
super(Controller, self).__init__(os.path.basename(args[0])) super(Controller, self).__init__(os.path.basename(args[0]))
self.args = list(args) self.args = list(args)
def _invoke(self, cmdline): def _invoke(self, cmdline):
if sys.platform[:3] == 'win': if sys.platform[:3] == u'win':
closefds = False closefds = False
startupinfo = subprocess.STARTUPINFO() startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
@ -45,9 +61,9 @@ class Controller(BaseController):
closefds = True closefds = True
startupinfo = None startupinfo = None
if (os.environ.get('DISPLAY') or sys.platform[:3] == 'win' or if (os.environ.get(u'DISPLAY') or sys.platform[:3] == u'win' or \
sys.platform == 'darwin'): sys.platform == u'darwin'):
inout = file(os.devnull, 'r+') inout = file(os.devnull, u'r+')
else: else:
# for TTY programs, we need stdin/out # for TTY programs, we need stdin/out
inout = None inout = None
@ -55,19 +71,19 @@ class Controller(BaseController):
# if possible, put the child precess in separate process group, # if possible, put the child precess in separate process group,
# so keyboard interrupts don't affect child precess as well as # so keyboard interrupts don't affect child precess as well as
# Python # Python
setsid = getattr(os, 'setsid', None) setsid = getattr(os, u'setsid', None)
if not setsid: if not setsid:
setsid = getattr(os, 'setpgrp', None) setsid = getattr(os, u'setpgrp', None)
pipe = subprocess.Popen(cmdline, stdin=inout, stdout=inout, pipe = subprocess.Popen(cmdline, stdin=inout, stdout=inout,
stderr=inout, close_fds=closefds, stderr=inout, close_fds=closefds, preexec_fn=setsid,
preexec_fn=setsid, startupinfo=startupinfo) startupinfo=startupinfo)
# It is assumed that this kind of tools (gnome-open, kfmclient, # It is assumed that this kind of tools (gnome-open, kfmclient,
# exo-open, xdg-open and open for OSX) immediately exit after lauching # exo-open, xdg-open and open for OSX) immediately exit after lauching
# the specific application # the specific application
returncode = pipe.wait() returncode = pipe.wait()
if hasattr(self, 'fixreturncode'): if hasattr(self, u'fixreturncode'):
returncode = self.fixreturncode(returncode) returncode = self.fixreturncode(returncode)
return not returncode return not returncode
@ -84,10 +100,12 @@ class Controller(BaseController):
# Platform support for Windows # Platform support for Windows
if sys.platform[:3] == 'win': if sys.platform[:3] == u'win':
class Start(BaseController): class Start(BaseController):
'''Controller for the win32 start progam through os.startfile.''' """
Controller for the win32 start progam through os.startfile.
"""
def open(self, filename): def open(self, filename):
try: try:
@ -99,14 +117,14 @@ if sys.platform[:3] == 'win':
else: else:
return True return True
_controllers['windows-default'] = Start('start') _controllers[u'windows-default'] = Start(u'start')
_open = _controllers['windows-default'].open _open = _controllers[u'windows-default'].open
# Platform support for MacOS # Platform support for MacOS
elif sys.platform == 'darwin': elif sys.platform == u'darwin':
_controllers['open']= Controller('open') _controllers[u'open']= Controller(u'open')
_open = _controllers['open'].open _open = _controllers[u'open'].open
# Platform support for Unix # Platform support for Unix
@ -118,20 +136,22 @@ else:
from webbrowser import _iscommand from webbrowser import _iscommand
class KfmClient(Controller): class KfmClient(Controller):
'''Controller for the KDE kfmclient program.''' """
Controller for the KDE kfmclient program.
"""
def __init__(self, kfmclient='kfmclient'): def __init__(self, kfmclient=u'kfmclient'):
super(KfmClient, self).__init__(kfmclient, 'exec') super(KfmClient, self).__init__(kfmclient, u'exec')
self.kde_version = self.detect_kde_version() self.kde_version = self.detect_kde_version()
def detect_kde_version(self): def detect_kde_version(self):
kde_version = None kde_version = None
try: try:
info = commands.getoutput('kde-config --version') info = commands.getoutput(u'kfmclient --version')
for line in info.splitlines(): for line in info.splitlines():
if line.startswith('KDE'): if line.startswith(u'KDE'):
kde_version = line.split(':')[-1].strip() kde_version = line.split(u':')[-1].strip()
break break
except (OSError, RuntimeError): except (OSError, RuntimeError):
pass pass
@ -139,30 +159,30 @@ else:
return kde_version return kde_version
def fixreturncode(self, returncode): def fixreturncode(self, returncode):
if returncode is not None and self.kde_version > '3.5.4': if returncode is not None and self.kde_version > u'3.5.4':
return returncode return returncode
else: else:
return os.EX_OK return os.EX_OK
def detect_desktop_environment(): def detect_desktop_environment():
'''Checks for known desktop environments """
Checks for known desktop environments
Return the desktop environments name, lowercase (kde, gnome, xfce) Return the desktop environments name, lowercase (kde, gnome, xfce)
or "generic" or "generic"
"""
''' desktop_environment = u'generic'
desktop_environment = 'generic' if os.environ.get(u'KDE_FULL_SESSION') == u'true':
desktop_environment = u'kde'
if os.environ.get('KDE_FULL_SESSION') == 'true': elif os.environ.get(u'GNOME_DESKTOP_SESSION_ID'):
desktop_environment = 'kde' desktop_environment = u'gnome'
elif os.environ.get('GNOME_DESKTOP_SESSION_ID'):
desktop_environment = 'gnome'
else: else:
try: try:
info = commands.getoutput('xprop -root _DT_SAVE_MODE') info = commands.getoutput(u'xprop -root _DT_SAVE_MODE')
if ' = "xfce4"' in info: if u' = "xfce4"' in info:
desktop_environment = 'xfce' desktop_environment = u'xfce'
except (OSError, RuntimeError): except (OSError, RuntimeError):
pass pass
@ -170,18 +190,19 @@ else:
def register_X_controllers(): def register_X_controllers():
if _iscommand('kfmclient'): if _iscommand(u'kfmclient'):
_controllers['kde-open'] = KfmClient() _controllers[u'kde-open'] = KfmClient()
for command in ('gnome-open', 'exo-open', 'xdg-open'): for command in (u'gnome-open', u'exo-open', u'xdg-open'):
if _iscommand(command): if _iscommand(command):
_controllers[command] = Controller(command) _controllers[command] = Controller(command)
def get(): def get():
controllers_map = { controllers_map = {
'gnome': 'gnome-open', u'gnome': u'gnome-open',
'kde': 'kde-open', u'kde': u'kde-open',
'xfce': 'exo-open', u'xfce': u'exo-open',
} }
desktop_environment = detect_desktop_environment() desktop_environment = detect_desktop_environment()
@ -191,25 +212,26 @@ else:
return _controllers[controller_name].open return _controllers[controller_name].open
except KeyError: except KeyError:
if _controllers.has_key('xdg-open'): if _controllers.has_key(u'xdg-open'):
return _controllers['xdg-open'].open return _controllers[u'xdg-open'].open
else: else:
return webbrowser.open return webbrowser.open
if os.environ.get(u'DISPLAY'):
if os.environ.get("DISPLAY"):
register_X_controllers() register_X_controllers()
_open = get() _open = get()
def open(filename): def open(filename):
'''Open a file or an URL in the registered default application.''' """
Open a file or an URL in the registered default application.
"""
return _open(filename) return _open(filename)
def _fix_addersses(**kwargs): def _fix_addersses(**kwargs):
for headername in ('address', 'to', 'cc', 'bcc'): for headername in (u'address', u'to', u'cc', u'bcc'):
try: try:
headervalue = kwargs[headername] headervalue = kwargs[headername]
if not headervalue: if not headervalue:
@ -217,16 +239,14 @@ def _fix_addersses(**kwargs):
continue continue
elif not isinstance(headervalue, basestring): elif not isinstance(headervalue, basestring):
# assume it is a sequence # assume it is a sequence
headervalue = ','.join(headervalue) headervalue = u','.join(headervalue)
except KeyError: except KeyError:
pass pass
except TypeError: except TypeError:
raise TypeError('string or sequence expected for "%s", ' raise TypeError(u'string or sequence expected for "%s", %s '
'%s found' % (headername, u'found' % (headername, type(headervalue).__name__))
type(headervalue).__name__))
else: else:
translation_map = {'%': '%25', '&': '%26', '?': '%3F'} translation_map = {u'%': u'%25', u'&': u'%26', u'?': u'%3F'}
for char, replacement in translation_map.items(): for char, replacement in translation_map.items():
headervalue = headervalue.replace(char, replacement) headervalue = headervalue.replace(char, replacement)
kwargs[headername] = headervalue kwargs[headername] = headervalue
@ -235,31 +255,35 @@ def _fix_addersses(**kwargs):
def mailto_format(**kwargs): def mailto_format(**kwargs):
"""
Compile mailto string from call parameters
"""
# @TODO: implement utf8 option # @TODO: implement utf8 option
kwargs = _fix_addersses(**kwargs) kwargs = _fix_addersses(**kwargs)
parts = [] parts = []
for headername in ('to', 'cc', 'bcc', 'subject', 'body', 'attach'): for headername in (u'to', u'cc', u'bcc', u'subject', u'body', u'attach'):
if kwargs.has_key(headername): if kwargs.has_key(headername):
headervalue = kwargs[headername] headervalue = kwargs[headername]
if not headervalue: if not headervalue:
continue continue
if headername in ('address', 'to', 'cc', 'bcc'): if headername in (u'address', u'to', u'cc', u'bcc'):
parts.append('%s=%s' % (headername, headervalue)) parts.append(u'%s=%s' % (headername, headervalue))
else: else:
headervalue = encode_rfc2231(headervalue) # @TODO: check headervalue = encode_rfc2231(headervalue) # @TODO: check
parts.append('%s=%s' % (headername, headervalue)) parts.append(u'%s=%s' % (headername, headervalue))
mailto_string = 'mailto:%s' % kwargs.get('address', '') mailto_string = u'mailto:%s' % kwargs.get(u'address', '')
if parts: if parts:
mailto_string = '%s?%s' % (mailto_string, '&'.join(parts)) mailto_string = u'%s?%s' % (mailto_string, u'&'.join(parts))
return mailto_string return mailto_string
def mailto(address, to=None, cc=None, bcc=None, subject=None, body=None, def mailto(address, to=None, cc=None, bcc=None, subject=None, body=None,
attach=None): attach=None):
'''Send an e-mail using the user's preferred composer. """
Send an e-mail using the user's preferred composer.
Open the user's preferred e-mail composer in order to send a mail to Open the user's preferred e-mail composer in order to send a mail to
address(es) that must follow the syntax of RFC822. Multiple addresses address(es) that must follow the syntax of RFC822. Multiple addresses
@ -270,49 +294,61 @@ def mailto(address, to=None, cc=None, bcc=None, subject=None, body=None,
the user's e-mail composer. The user will have the opportunity to the user's e-mail composer. The user will have the opportunity to
change any of this information before actually sending the e-mail. change any of this information before actually sending the e-mail.
address - specify the destination recipient ``address``
cc - specify a recipient to be copied on the e-mail specify the destination recipient
bcc - specify a recipient to be blindly copied on the e-mail
subject - specify a subject for the e-mail
body - specify a body for the e-mail. Since the user will be able
to make changes before actually sending the e-mail, this
can be used to provide the user with a template for the
e-mail text may contain linebreaks
attach - specify an attachment for the e-mail. file must point to
an existing file
''' ``cc``
specify a recipient to be copied on the e-mail
``bcc``
specify a recipient to be blindly copied on the e-mail
``subject``
specify a subject for the e-mail
``body``
specify a body for the e-mail. Since the user will be able to make
changes before actually sending the e-mail, this can be used to provide
the user with a template for the e-mail text may contain linebreaks
``attach``
specify an attachment for the e-mail. file must point to an existing
file
"""
mailto_string = mailto_format(**locals()) mailto_string = mailto_format(**locals())
return open(mailto_string) return open(mailto_string)
if __name__ == '__main__': if __name__ == u'__main__':
"""
Option handler for CLI usage
"""
from optparse import OptionParser from optparse import OptionParser
version = '%%prog %s' % __version__ version = u'%%prog %s' % __version__
usage = ( usage = (
'\n\n%prog FILENAME [FILENAME(s)] -- for opening files' u'\n\n%prog FILENAME [FILENAME(s)] -- for opening files'
'\n\n%prog -m [OPTIONS] ADDRESS [ADDRESS(es)] -- for sending e-mails' u'\n\n%prog -m [OPTIONS] ADDRESS [ADDRESS(es)] -- for sending e-mails'
) )
parser = OptionParser(usage=usage, version=version, description=__doc__) parser = OptionParser(usage=usage, version=version, description=__doc__)
parser.add_option('-m', '--mailto', dest='mailto_mode', default=False, parser.add_option(u'-m', u'--mailto', dest=u'mailto_mode', default=False,
action='store_true', help='set mailto mode. ' action=u'store_true', help=u'set mailto mode. If not set any other '
'If not set any other option is ignored') u'option is ignored')
parser.add_option('--cc', dest='cc', help='specify a recipient to be ' parser.add_option(u'--cc', dest=u'cc', help=u'specify a recipient to be '
'copied on the e-mail') u'copied on the e-mail')
parser.add_option('--bcc', dest='bcc', help='specify a recipient to be ' parser.add_option(u'--bcc', dest=u'bcc', help=u'specify a recipient to be '
'blindly copied on the e-mail') u'blindly copied on the e-mail')
parser.add_option('--subject', dest='subject', parser.add_option(u'--subject', dest=u'subject', help=u'specify a subject '
help='specify a subject for the e-mail') u'for the e-mail')
parser.add_option('--body', dest='body', help='specify a body for the ' parser.add_option(u'--body', dest=u'body', help=u'specify a body for the '
'e-mail. Since the user will be able to make changes ' u'e-mail. Since the user will be able to make changes before actually '
'before actually sending the e-mail, this can be used ' u'sending the e-mail, this can be used to provide the user with a '
'to provide the user with a template for the e-mail ' u'template for the e-mail text may contain linebreaks')
'text may contain linebreaks') parser.add_option(u'--attach', dest=u'attach', help=u'specify an '
parser.add_option('--attach', dest='attach', help='specify an attachment ' u'attachment for the e-mail. file must point to an existing file')
'for the e-mail. file must point to an existing file')
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
@ -322,17 +358,18 @@ if __name__ == '__main__':
if options.mailto_mode: if options.mailto_mode:
if not mailto(args, None, options.cc, options.bcc, options.subject, if not mailto(args, None, options.cc, options.bcc, options.subject,
options.body, options.attach): options.body, options.attach):
sys.exit('Unable to open the e-mail client') sys.exit(u'Unable to open the e-mail client')
else: else:
for name in ('cc', 'bcc', 'subject', 'body', 'attach'): for name in (u'cc', u'bcc', u'subject', u'body', u'attach'):
if getattr(options, name): if getattr(options, name):
parser.error('The "cc", "bcc", "subject", "body" and "attach" ' parser.error(u'The "cc", "bcc", "subject", "body" and "attach" '
'options are only accepten in mailto mode') u'options are only accepten in mailto mode')
success = False success = False
for arg in args: for arg in args:
if not open(arg): if not open(arg):
print 'Unable to open "%s"' % arg print u'Unable to open "%s"' % arg
else: else:
success = True success = True
sys.exit(success) sys.exit(success)

View File

@ -1,4 +0,0 @@
Cross-platform startfile and mailto functions
Author: Antonio Valentino
License: PSF license (http://docs.python.org/license.html)
Source: http://code.activestate.com/recipes/511443-cross-platform-startfile-and-mailto-functions/

View File

@ -74,6 +74,7 @@ class Ui_ExceptionDialog(object):
self.sendReportButton.setObjectName(u'sendReportButton') self.sendReportButton.setObjectName(u'sendReportButton')
self.exceptionButtonBox.addButton(self.sendReportButton, self.exceptionButtonBox.addButton(self.sendReportButton,
QtGui.QDialogButtonBox.ActionRole) QtGui.QDialogButtonBox.ActionRole)
self.retranslateUi(exceptionDialog) self.retranslateUi(exceptionDialog)
QtCore.QObject.connect(self.exceptionButtonBox, QtCore.QObject.connect(self.exceptionButtonBox,
QtCore.SIGNAL(u'accepted()'), exceptionDialog.accept) QtCore.SIGNAL(u'accepted()'), exceptionDialog.accept)

View File

@ -24,23 +24,38 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
import re
import os import os
import platform import platform
import sqlalchemy import sqlalchemy
import BeautifulSoup import BeautifulSoup
import enchant from lxml import etree
import chardet from PyQt4 import Qt, QtCore, QtGui
try:
from PyQt4.phonon import Phonon
phonon_version = Phonon.phononVersion()
except ImportError:
phonon_version = u'-'
try:
import chardet
chardet_version = chardet.__version__
except ImportError:
chardet_version = u'-'
try:
import enchant
enchant_version = enchant.__version__
except ImportError:
enchant_version = u'-'
try: try:
import sqlite import sqlite
sqlite_version = sqlite.version sqlite_version = sqlite.version
except ImportError: except ImportError:
sqlite_version = u'-' sqlite_version = u'-'
from lxml import etree from openlp.core.lib import translate, SettingsManager
from PyQt4 import Qt, QtCore, QtGui from openlp.core.lib.mailto import mailto
from openlp.core.lib import translate, SettingsManager, mailto
from exceptiondialog import Ui_ExceptionDialog from exceptiondialog import Ui_ExceptionDialog
@ -52,26 +67,27 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
QtGui.QDialog.__init__(self, parent) QtGui.QDialog.__init__(self, parent)
self.setupUi(self) self.setupUi(self)
self.settingsSection = u'crashreport' self.settingsSection = u'crashreport'
#TODO: Icons
def _createReport(self): def _createReport(self):
openlp_version = self.parent().applicationVersion[u'full'] openlp_version = self.parent().applicationVersion[u'full']
traceback = unicode(self.exceptionTextEdit.toPlainText()) traceback = unicode(self.exceptionTextEdit.toPlainText())
system = unicode(translate('OpenLP.ExceptionForm', system = unicode(translate('OpenLP.ExceptionForm',
'Platform: %s\n')) % (platform.platform()) 'Platform: %s\n')) % platform.platform()
libraries = unicode(translate('OpenLP.ExceptionForm', libraries = u'Python: %s\n' % platform.python_version() + \
'Python: %s\n' u'Qt4: %s\n' % Qt.qVersion() + \
'PyQt4: %s\n' u'Phonon: %s\n' % phonon_version + \
'Qt4: %s\n' u'PyQt4: %s\n' % Qt.PYQT_VERSION_STR + \
'SQLAlchemy: %s\n' u'SQLAlchemy: %s\n' % sqlalchemy.__version__ + \
'lxml: %s\n' u'BeautifulSoup: %s\n' % BeautifulSoup.__version__ + \
'BeautifulSoup: %s\n' u'lxml: %s\n' % etree.__version__ + \
'PyEnchant: %s\n' u'Chardet: %s\n' % chardet_version + \
'Chardet: %s\n' u'PyEnchant: %s\n' % enchant_version + \
'PySQLite: %s\n')) % (platform.python_version(), u'PySQLite: %s\n' % sqlite_version
Qt.PYQT_VERSION_STR, Qt.qVersion(), sqlalchemy.__version__, if platform.system() == u'Linux':
etree.__version__, BeautifulSoup.__version__ , enchant.__version__, if os.environ.get(u'KDE_FULL_SESSION') == u'true':
chardet.__version__, sqlite_version) system = system + u'Desktop: KDE SC\n'
elif os.environ.get(u'GNOME_DESKTOP_SESSION_ID'):
system = system + u'Desktop: GNOME\n'
return (openlp_version, traceback, system, libraries) return (openlp_version, traceback, system, libraries)
def onSaveReportButtonPressed(self): def onSaveReportButtonPressed(self):
@ -110,12 +126,18 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
Opening systems default email client and inserting exception log and Opening systems default email client and inserting exception log and
system informations. system informations.
""" """
email_body = unicode(translate('OpenLP.ExceptionForm', body = unicode(translate('OpenLP.ExceptionForm',
'*OpenLP Bug Report*\n' '*OpenLP Bug Report*\n'
'Version: %s\n\n' 'Version: %s\n\n'
'--- Please enter the report below this line. ---\n\n\n' '--- Please enter the report below this line. ---\n\n\n'
'--- Exception Traceback ---\n%s\n' '--- Exception Traceback ---\n%s\n'
'--- System information ---\n%s\n' '--- System information ---\n%s\n'
'--- Library Versions ---\n%s\n')) '--- Library Versions ---\n%s\n'))
mailto.mailto(address=u'bugs@openlp.org', subject=u'OpenLP Bug Report', content = self._createReport()
body=email_body % self._createReport()) for line in content[1].split(u'\n'):
if re.search(r'[/\\]openlp[/\\]', line):
source = re.sub(r'.*[/\\]openlp[/\\](.*)".*', r'\1', line)
if u':' in line:
exception = line.split(u'\n')[-1].split(u':')[0]
subject = u'Bug report: %s in %s' % (exception, source)
mailto(address=u'bugs@openlp.org', subject=subject, body=body % content)