From 88ba36c9ddc7ae9202522a4ac9dd815139ca3fd9 Mon Sep 17 00:00:00 2001 From: M2j Date: Fri, 10 Dec 2010 21:42:20 +0100 Subject: [PATCH 1/7] Bug report features for exception dialog --- openlp/core/ui/aboutform.py | 7 +++ openlp/core/ui/exceptionform.py | 86 ++++++++++++++++++++++++++++++++- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/openlp/core/ui/aboutform.py b/openlp/core/ui/aboutform.py index 3b49ff274..f3b519465 100644 --- a/openlp/core/ui/aboutform.py +++ b/openlp/core/ui/aboutform.py @@ -54,6 +54,13 @@ class AboutForm(QtGui.QDialog, Ui_AboutDialog): QtCore.QObject.connect(self.contributeButton, QtCore.SIGNAL(u'clicked()'), self.onContributeButtonClicked) + def reject(self): + """ + Raise a exception to test the exception handler. + """ + self.done(QtGui.QDialog.Rejected) + str(u'unvern\u00FCnftig') + def onContributeButtonClicked(self): """ Launch a web browser and go to the contribute page on the site. diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py index b40c9e063..b116aa6cf 100644 --- a/openlp/core/ui/exceptionform.py +++ b/openlp/core/ui/exceptionform.py @@ -24,7 +24,12 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### -from PyQt4 import QtGui +import os + +from PyQt4 import QtCore, QtGui + +from openlp.core.lib import translate, build_icon, SettingsManager +from openlp.core.ui.mailto import mailto from exceptiondialog import Ui_ExceptionDialog @@ -35,3 +40,82 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog): def __init__(self, parent): QtGui.QDialog.__init__(self, parent) self.setupUi(self) + self.settingsSection = u'crashreport' + #TODO: Icons + self.saveReportButton = QtGui.QPushButton(self) + self.saveReportButton.setIcon(build_icon(u':/icon/openlp-logo-16x16.png')) + self.saveReportButton.setText(translate('OpenLP.ExceptionForm', 'Save Report to File')) + self.saveReportButton.setObjectName(u'saveReportButton') + self.sendReportButton = QtGui.QPushButton(self) + self.sendReportButton.setIcon(build_icon(u':/icon/openlp-logo-16x16.png')) + self.sendReportButton.setText(translate('OpenLP.ExceptionForm', 'Send Report Mail')) + self.sendReportButton.setObjectName(u'sendReportButton') + self.exceptionButtonBox.addButton(self.saveReportButton, + QtGui.QDialogButtonBox.ActionRole) + self.exceptionButtonBox.addButton(self.sendReportButton, + QtGui.QDialogButtonBox.ActionRole) + QtCore.QObject.connect(self.saveReportButton, + QtCore.SIGNAL(u'pressed()'), self.onSaveReportButtonPressed) + QtCore.QObject.connect(self.sendReportButton, + QtCore.SIGNAL(u'pressed()'), self.onSendReportButtonPressed) + + def _createReport(self): + system = unicode(translate('OpenLP.ExceptionForm', + 'Operating System: %s\n' + 'Desktop Envoirnment: %s')) + libraries = unicode(translate('OpenLP.ExceptionForm', + 'Python: %s\n' + 'PyQt: %s\n' + 'SQLAlchemy: %s\n' + 'lxml: %s\n' + 'BeautifulSoup: %s\n' + 'PyEnchant: %s\n' + 'Chardet: %s\n' + 'pysqlite: %s')) + #TODO: collect the informations + version = self.parent().applicationVersion[u'full'] + return (version, system, libraries) + + def onSaveReportButtonPressed(self): + """ + Saving exception log and system informations to a file. + """ + report = unicode(translate('OpenLP.ExceptionForm', + '*OpenLP Bug Report*\n' + 'Version: %s\n' + '--- System information. ---\n%s\n' + '--- Library Versions ---\n%s\n')) + filename = QtGui.QFileDialog.getSaveFileName(self, + translate('OpenLP.ExceptionForm', 'Save Crash Report'), + SettingsManager.get_last_dir(self.settingsSection), + translate('OpenLP.ExceptionForm', 'Text files (*.log *.text *.txt)')) + if filename: + filename = unicode(QtCore.QDir.toNativeSeparators(filename)) + SettingsManager.set_last_dir(self.settingsSection, os.path.dirname( + filename)) + report = report % self._createReport() + try: + file = open(filename, u'w') + try: + file.write(report) + except UnicodeError: + file.close() + file = open(filename, u'wb') + file.write(report.encode(u'utf-8')) + file.close() + except IOError: + log.exception(u'Failed to write crash report') + + def onSendReportButtonPressed(self): + """ + Opening systems default email client and inserting exception log and + system informations. + """ + email_body = unicode(translate('OpenLP.ExceptionForm', + '*OpenLP Bug Report*\n' + 'Version: %s\n' + '--- Please enter the report below this line. ---\n\n\n' + '--- System information. ---\n%s\n' + '--- Library Versions ---\n%s\n')) + mailto(address=u'bugs@openlp.org', subject=u'OpenLP Bug Report', + body=email_body % self._createReport()) From 5bae9c74e3c91738bca34c3cb170600ccf72bf3c Mon Sep 17 00:00:00 2001 From: M2j Date: Fri, 10 Dec 2010 22:19:46 +0100 Subject: [PATCH 2/7] added mailto code --- openlp/core/ui/exceptionform.py | 2 +- openlp/core/ui/mailto/README | 4 + openlp/core/ui/mailto/__init__.py | 338 ++++++++++++++++++++++++++++++ 3 files changed, 343 insertions(+), 1 deletion(-) create mode 100644 openlp/core/ui/mailto/README create mode 100644 openlp/core/ui/mailto/__init__.py diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py index b116aa6cf..2a7b872c9 100644 --- a/openlp/core/ui/exceptionform.py +++ b/openlp/core/ui/exceptionform.py @@ -88,7 +88,7 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog): filename = QtGui.QFileDialog.getSaveFileName(self, translate('OpenLP.ExceptionForm', 'Save Crash Report'), SettingsManager.get_last_dir(self.settingsSection), - translate('OpenLP.ExceptionForm', 'Text files (*.log *.text *.txt)')) + translate('OpenLP.ExceptionForm', 'Text files (*.txt *.log *.text)')) if filename: filename = unicode(QtCore.QDir.toNativeSeparators(filename)) SettingsManager.set_last_dir(self.settingsSection, os.path.dirname( diff --git a/openlp/core/ui/mailto/README b/openlp/core/ui/mailto/README new file mode 100644 index 000000000..d1e278147 --- /dev/null +++ b/openlp/core/ui/mailto/README @@ -0,0 +1,4 @@ +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/ diff --git a/openlp/core/ui/mailto/__init__.py b/openlp/core/ui/mailto/__init__.py new file mode 100644 index 000000000..1ec8b6b90 --- /dev/null +++ b/openlp/core/ui/mailto/__init__.py @@ -0,0 +1,338 @@ +#!/usr/bin/env python + +'''Utilities for opening files or URLs in the registered default application +and for sending e-mail using the user's preferred composer. + +''' + +__version__ = '1.1' +__all__ = ['open', 'mailto'] + +import os +import sys +import webbrowser +import subprocess + +from email.Utils import encode_rfc2231 + +_controllers = {} +_open = None + + +class BaseController(object): + '''Base class for open program controllers.''' + + def __init__(self, name): + self.name = name + + def open(self, filename): + raise NotImplementedError + + +class Controller(BaseController): + '''Controller for a generic open program.''' + + def __init__(self, *args): + super(Controller, self).__init__(os.path.basename(args[0])) + self.args = list(args) + + def _invoke(self, cmdline): + if sys.platform[:3] == 'win': + closefds = False + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + else: + closefds = True + startupinfo = None + + if (os.environ.get('DISPLAY') or sys.platform[:3] == 'win' or + sys.platform == 'darwin'): + inout = file(os.devnull, 'r+') + else: + # for TTY programs, we need stdin/out + inout = None + + # if possible, put the child precess in separate process group, + # so keyboard interrupts don't affect child precess as well as + # Python + setsid = getattr(os, 'setsid', None) + if not setsid: + setsid = getattr(os, 'setpgrp', None) + + pipe = subprocess.Popen(cmdline, stdin=inout, stdout=inout, + stderr=inout, close_fds=closefds, + preexec_fn=setsid, startupinfo=startupinfo) + + # It is assumed that this kind of tools (gnome-open, kfmclient, + # exo-open, xdg-open and open for OSX) immediately exit after lauching + # the specific application + returncode = pipe.wait() + if hasattr(self, 'fixreturncode'): + returncode = self.fixreturncode(returncode) + return not returncode + + def open(self, filename): + if isinstance(filename, basestring): + cmdline = self.args + [filename] + else: + # assume it is a sequence + cmdline = self.args + filename + try: + return self._invoke(cmdline) + except OSError: + return False + + +# Platform support for Windows +if sys.platform[:3] == 'win': + + class Start(BaseController): + '''Controller for the win32 start progam through os.startfile.''' + + def open(self, filename): + try: + os.startfile(filename) + except WindowsError: + # [Error 22] No application is associated with the specified + # file for this operation: '' + return False + else: + return True + + _controllers['windows-default'] = Start('start') + _open = _controllers['windows-default'].open + + +# Platform support for MacOS +elif sys.platform == 'darwin': + _controllers['open']= Controller('open') + _open = _controllers['open'].open + + +# Platform support for Unix +else: + + import commands + + # @WARNING: use the private API of the webbrowser module + from webbrowser import _iscommand + + class KfmClient(Controller): + '''Controller for the KDE kfmclient program.''' + + def __init__(self, kfmclient='kfmclient'): + super(KfmClient, self).__init__(kfmclient, 'exec') + self.kde_version = self.detect_kde_version() + + def detect_kde_version(self): + kde_version = None + try: + info = commands.getoutput('kde-config --version') + + for line in info.splitlines(): + if line.startswith('KDE'): + kde_version = line.split(':')[-1].strip() + break + except (OSError, RuntimeError): + pass + + return kde_version + + def fixreturncode(self, returncode): + if returncode is not None and self.kde_version > '3.5.4': + return returncode + else: + return os.EX_OK + + def detect_desktop_environment(): + '''Checks for known desktop environments + + Return the desktop environments name, lowercase (kde, gnome, xfce) + or "generic" + + ''' + + desktop_environment = 'generic' + + if os.environ.get('KDE_FULL_SESSION') == 'true': + desktop_environment = 'kde' + elif os.environ.get('GNOME_DESKTOP_SESSION_ID'): + desktop_environment = 'gnome' + else: + try: + info = commands.getoutput('xprop -root _DT_SAVE_MODE') + if ' = "xfce4"' in info: + desktop_environment = 'xfce' + except (OSError, RuntimeError): + pass + + return desktop_environment + + + def register_X_controllers(): + if _iscommand('kfmclient'): + _controllers['kde-open'] = KfmClient() + + for command in ('gnome-open', 'exo-open', 'xdg-open'): + if _iscommand(command): + _controllers[command] = Controller(command) + + def get(): + controllers_map = { + 'gnome': 'gnome-open', + 'kde': 'kde-open', + 'xfce': 'exo-open', + } + + desktop_environment = detect_desktop_environment() + + try: + controller_name = controllers_map[desktop_environment] + return _controllers[controller_name].open + + except KeyError: + if _controllers.has_key('xdg-open'): + return _controllers['xdg-open'].open + else: + return webbrowser.open + + + if os.environ.get("DISPLAY"): + register_X_controllers() + _open = get() + + +def open(filename): + '''Open a file or an URL in the registered default application.''' + + return _open(filename) + + +def _fix_addersses(**kwargs): + for headername in ('address', 'to', 'cc', 'bcc'): + try: + headervalue = kwargs[headername] + if not headervalue: + del kwargs[headername] + continue + elif not isinstance(headervalue, basestring): + # assume it is a sequence + headervalue = ','.join(headervalue) + + except KeyError: + pass + except TypeError: + raise TypeError('string or sequence expected for "%s", ' + '%s found' % (headername, + type(headervalue).__name__)) + else: + translation_map = {'%': '%25', '&': '%26', '?': '%3F'} + for char, replacement in translation_map.items(): + headervalue = headervalue.replace(char, replacement) + kwargs[headername] = headervalue + + return kwargs + + +def mailto_format(**kwargs): + # @TODO: implement utf8 option + + kwargs = _fix_addersses(**kwargs) + parts = [] + for headername in ('to', 'cc', 'bcc', 'subject', 'body', 'attach'): + if kwargs.has_key(headername): + headervalue = kwargs[headername] + if not headervalue: + continue + if headername in ('address', 'to', 'cc', 'bcc'): + parts.append('%s=%s' % (headername, headervalue)) + else: + headervalue = encode_rfc2231(headervalue) # @TODO: check + parts.append('%s=%s' % (headername, headervalue)) + + mailto_string = 'mailto:%s' % kwargs.get('address', '') + if parts: + mailto_string = '%s?%s' % (mailto_string, '&'.join(parts)) + + return mailto_string + + +def mailto(address, to=None, cc=None, bcc=None, subject=None, body=None, + attach=None): + '''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 + address(es) that must follow the syntax of RFC822. Multiple addresses + may be provided (for address, cc and bcc parameters) as separate + arguments. + + All parameters provided are used to prefill corresponding fields in + the user's e-mail composer. The user will have the opportunity to + change any of this information before actually sending the e-mail. + + address - specify the destination recipient + 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()) + return open(mailto_string) + + +if __name__ == '__main__': + from optparse import OptionParser + + version = '%%prog %s' % __version__ + usage = ( + '\n\n%prog FILENAME [FILENAME(s)] -- for opening files' + '\n\n%prog -m [OPTIONS] ADDRESS [ADDRESS(es)] -- for sending e-mails' + ) + + parser = OptionParser(usage=usage, version=version, description=__doc__) + parser.add_option('-m', '--mailto', dest='mailto_mode', default=False, + action='store_true', help='set mailto mode. ' + 'If not set any other option is ignored') + parser.add_option('--cc', dest='cc', help='specify a recipient to be ' + 'copied on the e-mail') + parser.add_option('--bcc', dest='bcc', help='specify a recipient to be ' + 'blindly copied on the e-mail') + parser.add_option('--subject', dest='subject', + help='specify a subject for the e-mail') + parser.add_option('--body', dest='body', help='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') + parser.add_option('--attach', dest='attach', help='specify an attachment ' + 'for the e-mail. file must point to an existing file') + + (options, args) = parser.parse_args() + + if not args: + parser.print_usage() + parser.exit(1) + + if options.mailto_mode: + if not mailto(args, None, options.cc, options.bcc, options.subject, + options.body, options.attach): + sys.exit('Unable to open the e-mail client') + else: + for name in ('cc', 'bcc', 'subject', 'body', 'attach'): + if getattr(options, name): + parser.error('The "cc", "bcc", "subject", "body" and "attach" ' + 'options are only accepten in mailto mode') + success = False + for arg in args: + if not open(arg): + print 'Unable to open "%s"' % arg + else: + success = True + sys.exit(success) From 8ad603b2513684b41e66cf33cc12a6105065e50a Mon Sep 17 00:00:00 2001 From: M2j Date: Sat, 11 Dec 2010 01:26:41 +0100 Subject: [PATCH 3/7] completed exception report dialog --- openlp/core/{ui => lib}/mailto/__init__.py | 0 .../mailto/README => lib/mailto/mailto.INFO} | 0 openlp/core/ui/exceptiondialog.py | 22 +++++- openlp/core/ui/exceptionform.py | 64 +++++++++--------- resources/images/general_email.png | Bin 0 -> 755 bytes resources/images/openlp-2.qrc | 1 + 6 files changed, 53 insertions(+), 34 deletions(-) rename openlp/core/{ui => lib}/mailto/__init__.py (100%) rename openlp/core/{ui/mailto/README => lib/mailto/mailto.INFO} (100%) create mode 100644 resources/images/general_email.png diff --git a/openlp/core/ui/mailto/__init__.py b/openlp/core/lib/mailto/__init__.py similarity index 100% rename from openlp/core/ui/mailto/__init__.py rename to openlp/core/lib/mailto/__init__.py diff --git a/openlp/core/ui/mailto/README b/openlp/core/lib/mailto/mailto.INFO similarity index 100% rename from openlp/core/ui/mailto/README rename to openlp/core/lib/mailto/mailto.INFO diff --git a/openlp/core/ui/exceptiondialog.py b/openlp/core/ui/exceptiondialog.py index 49e2c8151..6fb7c7985 100644 --- a/openlp/core/ui/exceptiondialog.py +++ b/openlp/core/ui/exceptiondialog.py @@ -26,7 +26,7 @@ from PyQt4 import QtCore, QtGui -from openlp.core.lib import translate +from openlp.core.lib import translate, build_icon class Ui_ExceptionDialog(object): def setupUi(self, exceptionDialog): @@ -63,12 +63,26 @@ class Ui_ExceptionDialog(object): self.exceptionButtonBox.setStandardButtons(QtGui.QDialogButtonBox.Close) self.exceptionButtonBox.setObjectName(u'exceptionButtonBox') self.exceptionLayout.addWidget(self.exceptionButtonBox) - + self.saveReportButton = QtGui.QPushButton(exceptionDialog) + self.saveReportButton.setIcon(build_icon(u':/general/general_save.png')) + self.saveReportButton.setObjectName(u'saveReportButton') + self.exceptionButtonBox.addButton(self.saveReportButton, + QtGui.QDialogButtonBox.ActionRole) + self.sendReportButton = QtGui.QPushButton(exceptionDialog) + self.sendReportButton.setIcon(build_icon( + u':/general/general_email.png')) + self.sendReportButton.setObjectName(u'sendReportButton') + self.exceptionButtonBox.addButton(self.sendReportButton, + QtGui.QDialogButtonBox.ActionRole) self.retranslateUi(exceptionDialog) QtCore.QObject.connect(self.exceptionButtonBox, QtCore.SIGNAL(u'accepted()'), exceptionDialog.accept) QtCore.QObject.connect(self.exceptionButtonBox, QtCore.SIGNAL(u'rejected()'), exceptionDialog.reject) + QtCore.QObject.connect(self.saveReportButton, + QtCore.SIGNAL(u'pressed()'), self.onSaveReportButtonPressed) + QtCore.QObject.connect(self.sendReportButton, + QtCore.SIGNAL(u'pressed()'), self.onSendReportButtonPressed) QtCore.QMetaObject.connectSlotsByName(exceptionDialog) def retranslateUi(self, exceptionDialog): @@ -80,3 +94,7 @@ class Ui_ExceptionDialog(object): 'developers, so please e-mail it to bugs@openlp.org, along with a ' 'detailed description of what you were doing when the problem ' 'occurred.')) + self.saveReportButton.setText(translate('OpenLP.ExceptionDialog', + 'Save Report to File')) + self.sendReportButton.setText(translate('OpenLP.ExceptionDialog', + 'Send Report Mail')) diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py index 2a7b872c9..09cdc1414 100644 --- a/openlp/core/ui/exceptionform.py +++ b/openlp/core/ui/exceptionform.py @@ -25,11 +25,22 @@ ############################################################################### import os +import platform -from PyQt4 import QtCore, QtGui +import sqlalchemy +import BeautifulSoup +import enchant +import chardet +try: + import sqlite + sqlite_version = sqlite.version +except ImportError: + sqlite_version = u'-' -from openlp.core.lib import translate, build_icon, SettingsManager -from openlp.core.ui.mailto import mailto +from lxml import etree +from PyQt4 import Qt, QtCore, QtGui + +from openlp.core.lib import translate, SettingsManager, mailto from exceptiondialog import Ui_ExceptionDialog @@ -42,48 +53,36 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog): self.setupUi(self) self.settingsSection = u'crashreport' #TODO: Icons - self.saveReportButton = QtGui.QPushButton(self) - self.saveReportButton.setIcon(build_icon(u':/icon/openlp-logo-16x16.png')) - self.saveReportButton.setText(translate('OpenLP.ExceptionForm', 'Save Report to File')) - self.saveReportButton.setObjectName(u'saveReportButton') - self.sendReportButton = QtGui.QPushButton(self) - self.sendReportButton.setIcon(build_icon(u':/icon/openlp-logo-16x16.png')) - self.sendReportButton.setText(translate('OpenLP.ExceptionForm', 'Send Report Mail')) - self.sendReportButton.setObjectName(u'sendReportButton') - self.exceptionButtonBox.addButton(self.saveReportButton, - QtGui.QDialogButtonBox.ActionRole) - self.exceptionButtonBox.addButton(self.sendReportButton, - QtGui.QDialogButtonBox.ActionRole) - QtCore.QObject.connect(self.saveReportButton, - QtCore.SIGNAL(u'pressed()'), self.onSaveReportButtonPressed) - QtCore.QObject.connect(self.sendReportButton, - QtCore.SIGNAL(u'pressed()'), self.onSendReportButtonPressed) def _createReport(self): + openlp_version = self.parent().applicationVersion[u'full'] + traceback = unicode(self.exceptionTextEdit.toPlainText()) system = unicode(translate('OpenLP.ExceptionForm', - 'Operating System: %s\n' - 'Desktop Envoirnment: %s')) + 'Platform: %s\n')) % (platform.platform()) libraries = unicode(translate('OpenLP.ExceptionForm', 'Python: %s\n' - 'PyQt: %s\n' + 'PyQt4: %s\n' + 'Qt4: %s\n' 'SQLAlchemy: %s\n' 'lxml: %s\n' 'BeautifulSoup: %s\n' 'PyEnchant: %s\n' 'Chardet: %s\n' - 'pysqlite: %s')) - #TODO: collect the informations - version = self.parent().applicationVersion[u'full'] - return (version, system, libraries) + 'PySQLite: %s\n')) % (platform.python_version(), + Qt.PYQT_VERSION_STR, Qt.qVersion(), sqlalchemy.__version__, + etree.__version__, BeautifulSoup.__version__ , enchant.__version__, + chardet.__version__, sqlite_version) + return (openlp_version, traceback, system, libraries) def onSaveReportButtonPressed(self): """ Saving exception log and system informations to a file. """ report = unicode(translate('OpenLP.ExceptionForm', - '*OpenLP Bug Report*\n' - 'Version: %s\n' - '--- System information. ---\n%s\n' + '**OpenLP Bug Report**\n' + 'Version: %s\n\n' + '--- Exception Traceback ---\n%s\n' + '--- System information ---\n%s\n' '--- Library Versions ---\n%s\n')) filename = QtGui.QFileDialog.getSaveFileName(self, translate('OpenLP.ExceptionForm', 'Save Crash Report'), @@ -113,9 +112,10 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog): """ email_body = unicode(translate('OpenLP.ExceptionForm', '*OpenLP Bug Report*\n' - 'Version: %s\n' + 'Version: %s\n\n' '--- Please enter the report below this line. ---\n\n\n' - '--- System information. ---\n%s\n' + '--- Exception Traceback ---\n%s\n' + '--- System information ---\n%s\n' '--- Library Versions ---\n%s\n')) - mailto(address=u'bugs@openlp.org', subject=u'OpenLP Bug Report', + mailto.mailto(address=u'bugs@openlp.org', subject=u'OpenLP Bug Report', body=email_body % self._createReport()) diff --git a/resources/images/general_email.png b/resources/images/general_email.png new file mode 100644 index 0000000000000000000000000000000000000000..d1e9f2b647a6315fbbc0b1c30f87bdcb14e2c5a2 GIT binary patch literal 755 zcmV$)Z`J$S2g%9JmbD3M4! zu{h^&92b_wQFA{5fWR1V_gV*t2*d>flL>Ry1##!fag$$Fw5KU?vj4`-mn*DmD0T$F z&QrROfV3<`n(B;+0EkFC3OgmtzRyAtN6-h{npp$$N*Nx;_vDM)F*F8hAOwdcgqgsY z32g;*mkcwboe1;IG-sMxDa;jqWwYQ6dPK(<%H-jc6<8jv*(chIt&gDn$b1JSgBM{)rOK&F=4NbdZGm$ROV%Q%JNg5MFmQQje@{Autbx*AD?_c3k*N=u9qU0` ztRLNxAjtDj`ScO!j>B;kmN&L>x}{F*3gYt;3SH+hI=up0wMKZG*i0=>_9CRWJNarI zdr;LyetZl7Gb2BqPnzfTNq`=X<7mi-g?ks!Lg@__4u^ZA(WniLs&5VQVkQqwhvy#p lBINeJ^wrhX)c^mDe*n71HFqDb<*xt$002ovPDHLkV1k15PuKte literal 0 HcmV?d00001 diff --git a/resources/images/openlp-2.qrc b/resources/images/openlp-2.qrc index 2a3282461..e9ec5c0a3 100644 --- a/resources/images/openlp-2.qrc +++ b/resources/images/openlp-2.qrc @@ -39,6 +39,7 @@ general_new.png general_open.png general_save.png + general_email.png slide_close.png From 1cb9594e5881c1090876a92b073f8b93158d952b Mon Sep 17 00:00:00 2001 From: M2j Date: Sat, 11 Dec 2010 01:29:57 +0100 Subject: [PATCH 4/7] test exception removed --- openlp/core/ui/aboutform.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/openlp/core/ui/aboutform.py b/openlp/core/ui/aboutform.py index f3b519465..3b49ff274 100644 --- a/openlp/core/ui/aboutform.py +++ b/openlp/core/ui/aboutform.py @@ -54,13 +54,6 @@ class AboutForm(QtGui.QDialog, Ui_AboutDialog): QtCore.QObject.connect(self.contributeButton, QtCore.SIGNAL(u'clicked()'), self.onContributeButtonClicked) - def reject(self): - """ - Raise a exception to test the exception handler. - """ - self.done(QtGui.QDialog.Rejected) - str(u'unvern\u00FCnftig') - def onContributeButtonClicked(self): """ Launch a web browser and go to the contribute page on the site. From c28b1294218c68f4ce48dff5926f38454e01e0d0 Mon Sep 17 00:00:00 2001 From: M2j Date: Sat, 11 Dec 2010 16:39:12 +0100 Subject: [PATCH 5/7] format mailto() sources some exception dialog enhancements --- openlp/core/lib/mailto/LICENSE | 38 +++++ openlp/core/lib/mailto/__init__.py | 247 +++++++++++++++++------------ openlp/core/lib/mailto/mailto.INFO | 4 - openlp/core/ui/exceptiondialog.py | 1 + openlp/core/ui/exceptionform.py | 70 +++++--- 5 files changed, 227 insertions(+), 133 deletions(-) create mode 100644 openlp/core/lib/mailto/LICENSE delete mode 100644 openlp/core/lib/mailto/mailto.INFO diff --git a/openlp/core/lib/mailto/LICENSE b/openlp/core/lib/mailto/LICENSE new file mode 100644 index 000000000..967fbb0f4 --- /dev/null +++ b/openlp/core/lib/mailto/LICENSE @@ -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 PSF’s License Agreement and + PSF’s 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. + diff --git a/openlp/core/lib/mailto/__init__.py b/openlp/core/lib/mailto/__init__.py index 1ec8b6b90..44f38e31f 100644 --- a/openlp/core/lib/mailto/__init__.py +++ b/openlp/core/lib/mailto/__init__.py @@ -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__ = '1.1' -__all__ = ['open', 'mailto'] +__version__ = u'1.1' +__all__ = [u'open', u'mailto'] import os import sys @@ -20,7 +32,9 @@ _open = None class BaseController(object): - '''Base class for open program controllers.''' + """ + Base class for open program controllers. + """ def __init__(self, name): self.name = name @@ -30,14 +44,16 @@ class BaseController(object): class Controller(BaseController): - '''Controller for a generic open program.''' + """ + Controller for a generic open program. + """ def __init__(self, *args): super(Controller, self).__init__(os.path.basename(args[0])) self.args = list(args) def _invoke(self, cmdline): - if sys.platform[:3] == 'win': + if sys.platform[:3] == u'win': closefds = False startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW @@ -45,9 +61,9 @@ class Controller(BaseController): closefds = True startupinfo = None - if (os.environ.get('DISPLAY') or sys.platform[:3] == 'win' or - sys.platform == 'darwin'): - inout = file(os.devnull, 'r+') + if (os.environ.get(u'DISPLAY') or sys.platform[:3] == u'win' or \ + sys.platform == u'darwin'): + inout = file(os.devnull, u'r+') else: # for TTY programs, we need stdin/out inout = None @@ -55,19 +71,19 @@ class Controller(BaseController): # if possible, put the child precess in separate process group, # so keyboard interrupts don't affect child precess as well as # Python - setsid = getattr(os, 'setsid', None) + setsid = getattr(os, u'setsid', None) if not setsid: - setsid = getattr(os, 'setpgrp', None) + setsid = getattr(os, u'setpgrp', None) pipe = subprocess.Popen(cmdline, stdin=inout, stdout=inout, - stderr=inout, close_fds=closefds, - preexec_fn=setsid, startupinfo=startupinfo) + stderr=inout, close_fds=closefds, preexec_fn=setsid, + startupinfo=startupinfo) # It is assumed that this kind of tools (gnome-open, kfmclient, # exo-open, xdg-open and open for OSX) immediately exit after lauching # the specific application returncode = pipe.wait() - if hasattr(self, 'fixreturncode'): + if hasattr(self, u'fixreturncode'): returncode = self.fixreturncode(returncode) return not returncode @@ -84,10 +100,12 @@ class Controller(BaseController): # Platform support for Windows -if sys.platform[:3] == 'win': +if sys.platform[:3] == u'win': 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): try: @@ -99,14 +117,14 @@ if sys.platform[:3] == 'win': else: return True - _controllers['windows-default'] = Start('start') - _open = _controllers['windows-default'].open + _controllers[u'windows-default'] = Start(u'start') + _open = _controllers[u'windows-default'].open # Platform support for MacOS -elif sys.platform == 'darwin': - _controllers['open']= Controller('open') - _open = _controllers['open'].open +elif sys.platform == u'darwin': + _controllers[u'open']= Controller(u'open') + _open = _controllers[u'open'].open # Platform support for Unix @@ -118,20 +136,22 @@ else: from webbrowser import _iscommand class KfmClient(Controller): - '''Controller for the KDE kfmclient program.''' + """ + Controller for the KDE kfmclient program. + """ - def __init__(self, kfmclient='kfmclient'): - super(KfmClient, self).__init__(kfmclient, 'exec') + def __init__(self, kfmclient=u'kfmclient'): + super(KfmClient, self).__init__(kfmclient, u'exec') self.kde_version = self.detect_kde_version() def detect_kde_version(self): kde_version = None try: - info = commands.getoutput('kde-config --version') + info = commands.getoutput(u'kfmclient --version') for line in info.splitlines(): - if line.startswith('KDE'): - kde_version = line.split(':')[-1].strip() + if line.startswith(u'KDE'): + kde_version = line.split(u':')[-1].strip() break except (OSError, RuntimeError): pass @@ -139,30 +159,30 @@ else: return kde_version 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 else: return os.EX_OK def detect_desktop_environment(): - '''Checks for known desktop environments + """ + Checks for known desktop environments Return the desktop environments name, lowercase (kde, gnome, xfce) or "generic" + """ - ''' + desktop_environment = u'generic' - desktop_environment = 'generic' - - if os.environ.get('KDE_FULL_SESSION') == 'true': - desktop_environment = 'kde' - elif os.environ.get('GNOME_DESKTOP_SESSION_ID'): - desktop_environment = 'gnome' + if os.environ.get(u'KDE_FULL_SESSION') == u'true': + desktop_environment = u'kde' + elif os.environ.get(u'GNOME_DESKTOP_SESSION_ID'): + desktop_environment = u'gnome' else: try: - info = commands.getoutput('xprop -root _DT_SAVE_MODE') - if ' = "xfce4"' in info: - desktop_environment = 'xfce' + info = commands.getoutput(u'xprop -root _DT_SAVE_MODE') + if u' = "xfce4"' in info: + desktop_environment = u'xfce' except (OSError, RuntimeError): pass @@ -170,18 +190,19 @@ else: def register_X_controllers(): - if _iscommand('kfmclient'): - _controllers['kde-open'] = KfmClient() + if _iscommand(u'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): _controllers[command] = Controller(command) + def get(): controllers_map = { - 'gnome': 'gnome-open', - 'kde': 'kde-open', - 'xfce': 'exo-open', + u'gnome': u'gnome-open', + u'kde': u'kde-open', + u'xfce': u'exo-open', } desktop_environment = detect_desktop_environment() @@ -191,25 +212,26 @@ else: return _controllers[controller_name].open except KeyError: - if _controllers.has_key('xdg-open'): - return _controllers['xdg-open'].open + if _controllers.has_key(u'xdg-open'): + return _controllers[u'xdg-open'].open else: return webbrowser.open - - if os.environ.get("DISPLAY"): + if os.environ.get(u'DISPLAY'): register_X_controllers() _open = get() 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) def _fix_addersses(**kwargs): - for headername in ('address', 'to', 'cc', 'bcc'): + for headername in (u'address', u'to', u'cc', u'bcc'): try: headervalue = kwargs[headername] if not headervalue: @@ -217,16 +239,14 @@ def _fix_addersses(**kwargs): continue elif not isinstance(headervalue, basestring): # assume it is a sequence - headervalue = ','.join(headervalue) - + headervalue = u','.join(headervalue) except KeyError: pass except TypeError: - raise TypeError('string or sequence expected for "%s", ' - '%s found' % (headername, - type(headervalue).__name__)) + raise TypeError(u'string or sequence expected for "%s", %s ' + u'found' % (headername, type(headervalue).__name__)) else: - translation_map = {'%': '%25', '&': '%26', '?': '%3F'} + translation_map = {u'%': u'%25', u'&': u'%26', u'?': u'%3F'} for char, replacement in translation_map.items(): headervalue = headervalue.replace(char, replacement) kwargs[headername] = headervalue @@ -235,31 +255,35 @@ def _fix_addersses(**kwargs): def mailto_format(**kwargs): + """ + Compile mailto string from call parameters + """ # @TODO: implement utf8 option kwargs = _fix_addersses(**kwargs) 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): headervalue = kwargs[headername] if not headervalue: continue - if headername in ('address', 'to', 'cc', 'bcc'): - parts.append('%s=%s' % (headername, headervalue)) + if headername in (u'address', u'to', u'cc', u'bcc'): + parts.append(u'%s=%s' % (headername, headervalue)) else: 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: - mailto_string = '%s?%s' % (mailto_string, '&'.join(parts)) + mailto_string = u'%s?%s' % (mailto_string, u'&'.join(parts)) return mailto_string def mailto(address, to=None, cc=None, bcc=None, subject=None, body=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 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 change any of this information before actually sending the e-mail. - address - specify the destination recipient - 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 + ``address`` + specify the destination recipient - ''' + ``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()) return open(mailto_string) -if __name__ == '__main__': +if __name__ == u'__main__': + """ + Option handler for CLI usage + """ + from optparse import OptionParser - version = '%%prog %s' % __version__ + version = u'%%prog %s' % __version__ usage = ( - '\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 FILENAME [FILENAME(s)] -- for opening files' + u'\n\n%prog -m [OPTIONS] ADDRESS [ADDRESS(es)] -- for sending e-mails' ) parser = OptionParser(usage=usage, version=version, description=__doc__) - parser.add_option('-m', '--mailto', dest='mailto_mode', default=False, - action='store_true', help='set mailto mode. ' - 'If not set any other option is ignored') - parser.add_option('--cc', dest='cc', help='specify a recipient to be ' - 'copied on the e-mail') - parser.add_option('--bcc', dest='bcc', help='specify a recipient to be ' - 'blindly copied on the e-mail') - parser.add_option('--subject', dest='subject', - help='specify a subject for the e-mail') - parser.add_option('--body', dest='body', help='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') - parser.add_option('--attach', dest='attach', help='specify an attachment ' - 'for the e-mail. file must point to an existing file') + parser.add_option(u'-m', u'--mailto', dest=u'mailto_mode', default=False, + action=u'store_true', help=u'set mailto mode. If not set any other ' + u'option is ignored') + parser.add_option(u'--cc', dest=u'cc', help=u'specify a recipient to be ' + u'copied on the e-mail') + parser.add_option(u'--bcc', dest=u'bcc', help=u'specify a recipient to be ' + u'blindly copied on the e-mail') + parser.add_option(u'--subject', dest=u'subject', help=u'specify a subject ' + u'for the e-mail') + parser.add_option(u'--body', dest=u'body', help=u'specify a body for the ' + u'e-mail. Since the user will be able to make changes before actually ' + u'sending the e-mail, this can be used to provide the user with a ' + u'template for the e-mail text may contain linebreaks') + parser.add_option(u'--attach', dest=u'attach', help=u'specify an ' + u'attachment for the e-mail. file must point to an existing file') (options, args) = parser.parse_args() @@ -322,17 +358,18 @@ if __name__ == '__main__': if options.mailto_mode: if not mailto(args, None, options.cc, options.bcc, options.subject, - options.body, options.attach): - sys.exit('Unable to open the e-mail client') + options.body, options.attach): + sys.exit(u'Unable to open the e-mail client') 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): - parser.error('The "cc", "bcc", "subject", "body" and "attach" ' - 'options are only accepten in mailto mode') + parser.error(u'The "cc", "bcc", "subject", "body" and "attach" ' + u'options are only accepten in mailto mode') success = False for arg in args: if not open(arg): - print 'Unable to open "%s"' % arg + print u'Unable to open "%s"' % arg else: success = True sys.exit(success) + diff --git a/openlp/core/lib/mailto/mailto.INFO b/openlp/core/lib/mailto/mailto.INFO deleted file mode 100644 index d1e278147..000000000 --- a/openlp/core/lib/mailto/mailto.INFO +++ /dev/null @@ -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/ diff --git a/openlp/core/ui/exceptiondialog.py b/openlp/core/ui/exceptiondialog.py index 6fb7c7985..22395af90 100644 --- a/openlp/core/ui/exceptiondialog.py +++ b/openlp/core/ui/exceptiondialog.py @@ -74,6 +74,7 @@ class Ui_ExceptionDialog(object): self.sendReportButton.setObjectName(u'sendReportButton') self.exceptionButtonBox.addButton(self.sendReportButton, QtGui.QDialogButtonBox.ActionRole) + self.retranslateUi(exceptionDialog) QtCore.QObject.connect(self.exceptionButtonBox, QtCore.SIGNAL(u'accepted()'), exceptionDialog.accept) diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py index 09cdc1414..5fa0a7dd1 100644 --- a/openlp/core/ui/exceptionform.py +++ b/openlp/core/ui/exceptionform.py @@ -24,23 +24,38 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### +import re import os import platform import sqlalchemy import BeautifulSoup -import enchant -import chardet +from lxml import etree +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: import sqlite sqlite_version = sqlite.version except ImportError: sqlite_version = u'-' -from lxml import etree -from PyQt4 import Qt, QtCore, QtGui - -from openlp.core.lib import translate, SettingsManager, mailto +from openlp.core.lib import translate, SettingsManager +from openlp.core.lib.mailto import mailto from exceptiondialog import Ui_ExceptionDialog @@ -52,26 +67,27 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog): QtGui.QDialog.__init__(self, parent) self.setupUi(self) self.settingsSection = u'crashreport' - #TODO: Icons def _createReport(self): openlp_version = self.parent().applicationVersion[u'full'] traceback = unicode(self.exceptionTextEdit.toPlainText()) system = unicode(translate('OpenLP.ExceptionForm', - 'Platform: %s\n')) % (platform.platform()) - libraries = unicode(translate('OpenLP.ExceptionForm', - 'Python: %s\n' - 'PyQt4: %s\n' - 'Qt4: %s\n' - 'SQLAlchemy: %s\n' - 'lxml: %s\n' - 'BeautifulSoup: %s\n' - 'PyEnchant: %s\n' - 'Chardet: %s\n' - 'PySQLite: %s\n')) % (platform.python_version(), - Qt.PYQT_VERSION_STR, Qt.qVersion(), sqlalchemy.__version__, - etree.__version__, BeautifulSoup.__version__ , enchant.__version__, - chardet.__version__, sqlite_version) + 'Platform: %s\n')) % platform.platform() + libraries = u'Python: %s\n' % platform.python_version() + \ + u'Qt4: %s\n' % Qt.qVersion() + \ + u'Phonon: %s\n' % phonon_version + \ + u'PyQt4: %s\n' % Qt.PYQT_VERSION_STR + \ + u'SQLAlchemy: %s\n' % sqlalchemy.__version__ + \ + u'BeautifulSoup: %s\n' % BeautifulSoup.__version__ + \ + u'lxml: %s\n' % etree.__version__ + \ + u'Chardet: %s\n' % chardet_version + \ + u'PyEnchant: %s\n' % enchant_version + \ + u'PySQLite: %s\n' % sqlite_version + if platform.system() == u'Linux': + if os.environ.get(u'KDE_FULL_SESSION') == u'true': + 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) def onSaveReportButtonPressed(self): @@ -110,12 +126,18 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog): Opening systems default email client and inserting exception log and system informations. """ - email_body = unicode(translate('OpenLP.ExceptionForm', + body = unicode(translate('OpenLP.ExceptionForm', '*OpenLP Bug Report*\n' 'Version: %s\n\n' '--- Please enter the report below this line. ---\n\n\n' '--- Exception Traceback ---\n%s\n' '--- System information ---\n%s\n' '--- Library Versions ---\n%s\n')) - mailto.mailto(address=u'bugs@openlp.org', subject=u'OpenLP Bug Report', - body=email_body % self._createReport()) + content = 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) From af202e3358f7fb123928471560f6a4dfa8995940 Mon Sep 17 00:00:00 2001 From: M2j Date: Sat, 11 Dec 2010 21:22:03 +0100 Subject: [PATCH 6/7] removed CLI interface of the mailto library --- openlp/core/lib/mailto/__init__.py | 54 ------------------------------ 1 file changed, 54 deletions(-) diff --git a/openlp/core/lib/mailto/__init__.py b/openlp/core/lib/mailto/__init__.py index 44f38e31f..be7125155 100644 --- a/openlp/core/lib/mailto/__init__.py +++ b/openlp/core/lib/mailto/__init__.py @@ -319,57 +319,3 @@ def mailto(address, to=None, cc=None, bcc=None, subject=None, body=None, mailto_string = mailto_format(**locals()) return open(mailto_string) - -if __name__ == u'__main__': - """ - Option handler for CLI usage - """ - - from optparse import OptionParser - - version = u'%%prog %s' % __version__ - usage = ( - u'\n\n%prog FILENAME [FILENAME(s)] -- for opening files' - u'\n\n%prog -m [OPTIONS] ADDRESS [ADDRESS(es)] -- for sending e-mails' - ) - - parser = OptionParser(usage=usage, version=version, description=__doc__) - parser.add_option(u'-m', u'--mailto', dest=u'mailto_mode', default=False, - action=u'store_true', help=u'set mailto mode. If not set any other ' - u'option is ignored') - parser.add_option(u'--cc', dest=u'cc', help=u'specify a recipient to be ' - u'copied on the e-mail') - parser.add_option(u'--bcc', dest=u'bcc', help=u'specify a recipient to be ' - u'blindly copied on the e-mail') - parser.add_option(u'--subject', dest=u'subject', help=u'specify a subject ' - u'for the e-mail') - parser.add_option(u'--body', dest=u'body', help=u'specify a body for the ' - u'e-mail. Since the user will be able to make changes before actually ' - u'sending the e-mail, this can be used to provide the user with a ' - u'template for the e-mail text may contain linebreaks') - parser.add_option(u'--attach', dest=u'attach', help=u'specify an ' - u'attachment for the e-mail. file must point to an existing file') - - (options, args) = parser.parse_args() - - if not args: - parser.print_usage() - parser.exit(1) - - if options.mailto_mode: - if not mailto(args, None, options.cc, options.bcc, options.subject, - options.body, options.attach): - sys.exit(u'Unable to open the e-mail client') - else: - for name in (u'cc', u'bcc', u'subject', u'body', u'attach'): - if getattr(options, name): - parser.error(u'The "cc", "bcc", "subject", "body" and "attach" ' - u'options are only accepten in mailto mode') - success = False - for arg in args: - if not open(arg): - print u'Unable to open "%s"' % arg - else: - success = True - sys.exit(success) - From f3f2e5cdc8832d60bacf4fd8eda64c3f930fd4d4 Mon Sep 17 00:00:00 2001 From: M2j Date: Sun, 12 Dec 2010 00:25:49 +0100 Subject: [PATCH 7/7] minor changes --- openlp/core/lib/mailto/LICENSE | 12 ++++++------ openlp/core/lib/mailto/__init__.py | 2 +- openlp/core/ui/exceptiondialog.py | 20 ++++++++++---------- resources/images/general_email.png | Bin 755 -> 833 bytes 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/openlp/core/lib/mailto/LICENSE b/openlp/core/lib/mailto/LICENSE index 967fbb0f4..d8ab2d8d2 100644 --- a/openlp/core/lib/mailto/LICENSE +++ b/openlp/core/lib/mailto/LICENSE @@ -1,23 +1,23 @@ 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 + 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 PSF’s License Agreement and - PSF’s notice of copyright, i.e., “Copyright © 2001-2010 Python Software - Foundation; All Rights Reserved” are retained in Python 2.7.1 alone or in + derivative version, provided, however, that PSF's License Agreement and + PSF's notice of copyright, i.e., "Copyright (c) 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 + 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 diff --git a/openlp/core/lib/mailto/__init__.py b/openlp/core/lib/mailto/__init__.py index be7125155..102c4c94a 100644 --- a/openlp/core/lib/mailto/__init__.py +++ b/openlp/core/lib/mailto/__init__.py @@ -14,7 +14,7 @@ # 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) # +# Modified for use in OpenLP # ############################################################################### __version__ = u'1.1' diff --git a/openlp/core/ui/exceptiondialog.py b/openlp/core/ui/exceptiondialog.py index 22395af90..03bbde764 100644 --- a/openlp/core/ui/exceptiondialog.py +++ b/openlp/core/ui/exceptiondialog.py @@ -63,27 +63,27 @@ class Ui_ExceptionDialog(object): self.exceptionButtonBox.setStandardButtons(QtGui.QDialogButtonBox.Close) self.exceptionButtonBox.setObjectName(u'exceptionButtonBox') self.exceptionLayout.addWidget(self.exceptionButtonBox) - self.saveReportButton = QtGui.QPushButton(exceptionDialog) - self.saveReportButton.setIcon(build_icon(u':/general/general_save.png')) - self.saveReportButton.setObjectName(u'saveReportButton') - self.exceptionButtonBox.addButton(self.saveReportButton, - QtGui.QDialogButtonBox.ActionRole) self.sendReportButton = QtGui.QPushButton(exceptionDialog) self.sendReportButton.setIcon(build_icon( u':/general/general_email.png')) self.sendReportButton.setObjectName(u'sendReportButton') self.exceptionButtonBox.addButton(self.sendReportButton, QtGui.QDialogButtonBox.ActionRole) + self.saveReportButton = QtGui.QPushButton(exceptionDialog) + self.saveReportButton.setIcon(build_icon(u':/general/general_save.png')) + self.saveReportButton.setObjectName(u'saveReportButton') + self.exceptionButtonBox.addButton(self.saveReportButton, + QtGui.QDialogButtonBox.ActionRole) self.retranslateUi(exceptionDialog) QtCore.QObject.connect(self.exceptionButtonBox, QtCore.SIGNAL(u'accepted()'), exceptionDialog.accept) QtCore.QObject.connect(self.exceptionButtonBox, QtCore.SIGNAL(u'rejected()'), exceptionDialog.reject) - QtCore.QObject.connect(self.saveReportButton, - QtCore.SIGNAL(u'pressed()'), self.onSaveReportButtonPressed) QtCore.QObject.connect(self.sendReportButton, QtCore.SIGNAL(u'pressed()'), self.onSendReportButtonPressed) + QtCore.QObject.connect(self.saveReportButton, + QtCore.SIGNAL(u'pressed()'), self.onSaveReportButtonPressed) QtCore.QMetaObject.connectSlotsByName(exceptionDialog) def retranslateUi(self, exceptionDialog): @@ -95,7 +95,7 @@ class Ui_ExceptionDialog(object): 'developers, so please e-mail it to bugs@openlp.org, along with a ' 'detailed description of what you were doing when the problem ' 'occurred.')) - self.saveReportButton.setText(translate('OpenLP.ExceptionDialog', - 'Save Report to File')) self.sendReportButton.setText(translate('OpenLP.ExceptionDialog', - 'Send Report Mail')) + 'Send E-Mail')) + self.saveReportButton.setText(translate('OpenLP.ExceptionDialog', + 'Save to File')) diff --git a/resources/images/general_email.png b/resources/images/general_email.png index d1e9f2b647a6315fbbc0b1c30f87bdcb14e2c5a2..bb3cab8f309beb40436493078b9cc01283b8e53a 100644 GIT binary patch literal 833 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~&H|6fVxZ#d zAk65bF}ngN$X?><>&kwMQH)7Mw$lIh51^jq0X`wFKq&}dVq)S11DF7U21)@rjEsy3 zA#5y&G6Mqxh@`EpEs!y5)+_-5f!VWX$Hv8(nwd2;G;Ub8{^-$TFJHa-`0-;vP;g*S z@Snf`|Nj5~@83TO2`L%(IkIx{@}Beb!XV0E9Z^5e7>&{=eeEI6l zYgaGbx_kfjy@z)nK7R1%>4V2lA3l2a@bR-pk6%1~`uy38S1(?^dhzPbi&t-7yng%g z)w`Fk-@JP9h`~L06 zukYV~{P_9n$FDy>zkm7p>-W#!e}4V`^Bai%{QdnGi2nci^A{8>fB*gc_a6u@7|mD) z3{Cx#AirP+MkZ!94qkp?ITZtA3oC0Idj~g9FW=zk*u><_{QTmHlc&vJwd35qPv3z- z`tRStNf+CIS{akP-CcTexGy;aIX66A977~7Cnqp4nX#&tv8fzTx_epqc-I4C&Wsl? zGrJ59v+lSOm6bjF>Q2dpHGEI6+_P-Q4i#%tOU<2Uu3g;aHpg+1rmgK_CH?igR%jTjul8+nTxD#% z`{Kc~ch8-*w6WeD-Q~D!`GyU9m|1qM;^wYSkw~cyXwYe1V#76og+Zy*f$`>+IhjB| OGI+ZBxvX0b000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs0007TNkl$)Z`J$S2g%9JmbD3M4!u{h^&92b_wQFA{5fWR1V z_gV*t2*d>flL>Ry1##!fag$$Fw5KU?vj4`-mn*DmD0T$F&QrROfV3<`n(B;+0EkFC z3OgmtzRyAtN6-h{npp$$N*Nx;_vDM)F*F8hAOwdcgnya9mH}};Ph{xkdr_+#9;_SI@9BZ>N5IqdH>Va}O(Df0VInilb>vntk>a*vN z{yGc}4u6`_HO5$}R8ZB1l2b8Vy}eKb+1QBM*Na%2ewwt1F%mu>1ZQ}&uz*6Lfad0A zY;A3Ua}G<^BBwk01BWnhd1!x6I)to&(q1b=t&x$b511Y6L0haJ-H{;3^HBNp5$KM? zaTS&~wsE?pPU{Nd^AZYO=P^3H0$a64c$?TvEniOdBBZxF`Dz_|P}N0#d<+0HBR`%` zn&NdCJ#-A=N|eZ