UI/EmailDialog.py

changeset 0
de9c2efb9d02
child 12
1d8dd9706f46
equal deleted inserted replaced
-1:000000000000 0:de9c2efb9d02
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2003 - 2009 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog to send bug reports.
8 """
9
10 import sys
11 import os
12 import mimetypes
13 import smtplib
14 import socket
15
16 from PyQt4.QtCore import *
17 from PyQt4.QtGui import *
18
19 from Ui_EmailDialog import Ui_EmailDialog
20
21 from Info import Program, Version, BugAddress, FeatureAddress
22 import Preferences
23 import Utilities
24
25 from email import Encoders
26 from email.MIMEBase import MIMEBase
27 from email.MIMEText import MIMEText
28 from email.MIMEImage import MIMEImage
29 from email.MIMEAudio import MIMEAudio
30 from email.MIMEMultipart import MIMEMultipart
31
32 class EmailDialog(QDialog, Ui_EmailDialog):
33 """
34 Class implementing a dialog to send bug reports.
35 """
36 def __init__(self, mode = "bug", parent = None):
37 """
38 Constructor
39
40 @param mode mode of this dialog (string, "bug" or "feature")
41 @param parent parent widget of this dialog (QWidget)
42 """
43 QDialog.__init__(self, parent)
44 self.setupUi(self)
45
46 self.__mode = mode
47 if self.__mode == "feature":
48 self.setWindowTitle(self.trUtf8("Send feature request"))
49 self.msgLabel.setText(self.trUtf8(
50 "Enter your &feature request below."
51 " Version information is added automatically."))
52 self.__toAddress = FeatureAddress
53 else:
54 # default is bug
55 self.msgLabel.setText(self.trUtf8(
56 "Enter your &bug description below."
57 " Version information is added automatically."))
58 self.__toAddress = BugAddress
59
60 self.sendButton = \
61 self.buttonBox.addButton(self.trUtf8("Send"), QDialogButtonBox.ActionRole)
62 self.sendButton.setEnabled(False)
63 self.sendButton.setDefault(True)
64
65 height = self.height()
66 self.mainSplitter.setSizes([int(0.7 * height), int(0.3 * height)])
67
68 self.attachments.headerItem().setText(self.attachments.columnCount(), "")
69 self.attachments.header().setResizeMode(QHeaderView.Interactive)
70
71 sig = Preferences.getUser("Signature")
72 if sig:
73 self.message.setPlainText(sig)
74 cursor = self.message.textCursor()
75 cursor.setPosition(0)
76 self.message.setTextCursor(cursor)
77 self.message.ensureCursorVisible()
78
79 self.__deleteFiles = []
80
81 def keyPressEvent(self, ev):
82 """
83 Re-implemented to handle the user pressing the escape key.
84
85 @param ev key event (QKeyEvent)
86 """
87 if ev.key() == Qt.Key_Escape:
88 res = QMessageBox.question(self,
89 self.trUtf8("Close dialog"),
90 self.trUtf8("""Do you really want to close the dialog?"""),
91 QMessageBox.StandardButtons(\
92 QMessageBox.No | \
93 QMessageBox.Yes),
94 QMessageBox.No)
95 if res == QMessageBox.Yes:
96 self.reject()
97
98 def on_buttonBox_clicked(self, button):
99 """
100 Private slot called by a button of the button box clicked.
101
102 @param button button that was clicked (QAbstractButton)
103 """
104 if button == self.sendButton:
105 self.on_sendButton_clicked()
106
107 def on_buttonBox_rejected(self):
108 """
109 Private slot to handle the rejected signal of the button box.
110 """
111 res = QMessageBox.question(self,
112 self.trUtf8("Close dialog"),
113 self.trUtf8("""Do you really want to close the dialog?"""),
114 QMessageBox.StandardButtons(\
115 QMessageBox.No | \
116 QMessageBox.Yes),
117 QMessageBox.No)
118 if res == QMessageBox.Yes:
119 self.reject()
120
121 @pyqtSlot()
122 def on_sendButton_clicked(self):
123 """
124 Private slot to send the email message.
125 """
126 if self.attachments.topLevelItemCount():
127 msg = self.__createMultipartMail()
128 else:
129 msg = self.__createSimpleMail()
130
131 ok = self.__sendmail(msg)
132
133 if ok:
134 for f in self.__deleteFiles:
135 try:
136 os.remove(f)
137 except OSError:
138 pass
139 self.accept()
140
141 def __createSimpleMail(self):
142 """
143 Private method to create a simple mail message.
144
145 @return string containing the mail message
146 """
147 try:
148 import sipconfig
149 sip_version_str = sipconfig.Configuration().sip_version_str
150 except ImportError:
151 sip_version_str = "sip version not available"
152
153 msgtext = "%s\r\n----\r\n%s----\r\n%s----\r\n%s" % \
154 (self.message.toPlainText(),
155 Utilities.generateVersionInfo("\r\n"),
156 Utilities.generatePluginsVersionInfo("\r\n"),
157 Utilities.generateDistroInfo("\r\n"))
158
159 msg = MIMEText(msgtext,
160 _charset = Preferences.getSystem("StringEncoding"))
161 msg['From'] = Preferences.getUser("Email")
162 msg['To'] = self.__toAddress
163 msg['Subject'] = '[eric5] %s' % self.subject.text()
164
165 return msg.as_string()
166
167 def __createMultipartMail(self):
168 """
169 Private method to create a multipart mail message.
170
171 @return string containing the mail message
172 """
173 try:
174 import sipconfig
175 sip_version_str = sipconfig.Configuration().sip_version_str
176 except ImportError:
177 sip_version_str = "sip version not available"
178
179 mpPreamble = ("This is a MIME-encoded message with attachments. "
180 "If you see this message, your mail client is not "
181 "capable of displaying the attachments.")
182
183 msgtext = "%s\r\n----\r\n%s----\r\n%s----\r\n%s" % \
184 (self.message.toPlainText(),
185 Utilities.generateVersionInfo("\r\n"),
186 Utilities.generatePluginsVersionInfo("\r\n"),
187 Utilities.generateDistroInfo("\r\n"))
188
189 # first part of multipart mail explains format
190 msg = MIMEMultipart()
191 msg['From'] = Preferences.getUser("Email")
192 msg['To'] = self.__toAddress
193 msg['Subject'] = '[eric5] %s' % self.subject.text()
194 msg.preamble = mpPreamble
195 msg.epilogue = ''
196
197 # second part is intended to be read
198 att = MIMEText(msgtext,
199 _charset = Preferences.getSystem("StringEncoding"))
200 msg.attach(att)
201
202 # next parts contain the attachments
203 for index in range(self.attachments.topLevelItemCount()):
204 itm = self.attachments.topLevelItem(index)
205 maintype, subtype = str(itm.text(1)).split('/', 1)
206 fname = itm.text(0)
207 name = os.path.basename(fname)
208
209 if maintype == 'text':
210 att = MIMEText(open(fname, 'rb').read(), _subtype = subtype)
211 elif maintype == 'image':
212 att = MIMEImage(open(fname, 'rb').read(), _subtype = subtype)
213 elif maintype == 'audio':
214 att = MIMEAudio(open(fname, 'rb').read(), _subtype = subtype)
215 else:
216 att = MIMEBase(maintype, subtype)
217 att.set_payload(open(fname, 'rb').read())
218 Encoders.encode_base64(att)
219 att.add_header('Content-Disposition', 'attachment', filename = fname)
220 msg.attach(att)
221
222 return msg.as_string()
223
224 def __sendmail(self, msg):
225 """
226 Private method to actually send the message.
227
228 @param msg the message to be sent (string)
229 @return flag indicating success (boolean)
230 """
231 try:
232 server = smtplib.SMTP(str(Preferences.getUser("MailServer")),
233 Preferences.getUser("MailServerPort"))
234 if Preferences.getUser("MailServerUseTLS"):
235 server.starttls()
236 if Preferences.getUser("MailServerAuthentication"):
237 # mail server needs authentication
238 password = Preferences.getUser("MailServerPassword")
239 if not password:
240 password, ok = QInputDialog.getText(\
241 self,
242 self.trUtf8("Mail Server Password"),
243 self.trUtf8("Enter your mail server password"),
244 QLineEdit.Password)
245 if not ok:
246 # abort
247 return False
248 try:
249 server.login(Preferences.getUser("MailServerUser"),
250 password)
251 except (smtplib.SMTPException, socket.error), e:
252 res = QMessageBox.critical(self,
253 self.trUtf8("Send bug report"),
254 self.trUtf8("""<p>Authentication failed.<br>Reason: {0}</p>""")
255 .format(unicode(e)),
256 QMessageBox.StandardButtons(\
257 QMessageBox.Abort | \
258 QMessageBox.Retry),
259 QMessageBox.Retry)
260 if res == QMessageBox.Retry:
261 return self.__sendmail(msg)
262 else:
263 return False
264
265 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
266 QApplication.processEvents()
267 result = server.sendmail(Preferences.getUser("Email"),
268 self.__toAddress, msg)
269 server.quit()
270 QApplication.restoreOverrideCursor()
271 except (smtplib.SMTPException, socket.error), e:
272 QApplication.restoreOverrideCursor()
273 res = QMessageBox.critical(self,
274 self.trUtf8("Send bug report"),
275 self.trUtf8("""<p>Message could not be sent.<br>Reason: {0}</p>""")
276 .format(unicode(e)),
277 QMessageBox.StandardButtons(\
278 QMessageBox.Abort | \
279 QMessageBox.Retry),
280 QMessageBox.Retry)
281 if res == QMessageBox.Retry:
282 return self.__sendmail(msg)
283 else:
284 return False
285 return True
286
287 @pyqtSlot()
288 def on_addButton_clicked(self):
289 """
290 Private slot to handle the Add... button.
291 """
292 fname = QFileDialog.getOpenFileName(\
293 self,
294 self.trUtf8("Attach file"))
295 if fname:
296 self.attachFile(fname, False)
297
298 def attachFile(self, fname, deleteFile):
299 """
300 Public method to add an attachment.
301
302 @param fname name of the file to be attached (string)
303 @param deleteFile flag indicating to delete the file after it has
304 been sent (boolean)
305 """
306 type = mimetypes.guess_type(fname)[0]
307 if not type:
308 type = "application/octet-stream"
309 itm = QTreeWidgetItem(self.attachments, [fname, type])
310 self.attachments.header().resizeSections(QHeaderView.ResizeToContents)
311 self.attachments.header().setStretchLastSection(True)
312
313 if deleteFile:
314 self.__deleteFiles.append(fname)
315
316 @pyqtSlot()
317 def on_deleteButton_clicked(self):
318 """
319 Private slot to handle the Delete button.
320 """
321 itm = self.attachments.currentItem()
322 if itm is not None:
323 itm = self.attachments.takeTopLevelItem(\
324 self.attachments.indexOfTopLevelItem(itm))
325 del itm
326
327 def on_subject_textChanged(self, txt):
328 """
329 Private slot to handle the textChanged signal of the subject edit.
330
331 @param txt changed text (string)
332 """
333 self.sendButton.setEnabled(\
334 self.subject.text() != "" and \
335 self.message.toPlainText() != "")
336
337 def on_message_textChanged(self):
338 """
339 Private slot to handle the textChanged signal of the message edit.
340
341 @param txt changed text (string)
342 """
343 self.sendButton.setEnabled(\
344 self.subject.text() != "" and \
345 self.message.toPlainText() != "")

eric ide

mercurial