src/eric7/UI/EmailDialog.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
13 import contextlib 13 import contextlib
14 14
15 from PyQt6.QtCore import Qt, pyqtSlot 15 from PyQt6.QtCore import Qt, pyqtSlot
16 from PyQt6.QtGui import QTextOption 16 from PyQt6.QtGui import QTextOption
17 from PyQt6.QtWidgets import ( 17 from PyQt6.QtWidgets import (
18 QHeaderView, QLineEdit, QDialog, QInputDialog, QDialogButtonBox, 18 QHeaderView,
19 QTreeWidgetItem 19 QLineEdit,
20 QDialog,
21 QInputDialog,
22 QDialogButtonBox,
23 QTreeWidgetItem,
20 ) 24 )
21 25
22 from EricWidgets import EricMessageBox, EricFileDialog 26 from EricWidgets import EricMessageBox, EricFileDialog
23 from EricGui.EricOverrideCursor import EricOverrideCursor 27 from EricGui.EricOverrideCursor import EricOverrideCursor
24 28
44 48
45 class EmailDialog(QDialog, Ui_EmailDialog): 49 class EmailDialog(QDialog, Ui_EmailDialog):
46 """ 50 """
47 Class implementing a dialog to send bug reports or feature requests. 51 Class implementing a dialog to send bug reports or feature requests.
48 """ 52 """
53
49 def __init__(self, mode="bug", parent=None): 54 def __init__(self, mode="bug", parent=None):
50 """ 55 """
51 Constructor 56 Constructor
52 57
53 @param mode mode of this dialog (string, "bug" or "feature") 58 @param mode mode of this dialog (string, "bug" or "feature")
54 @param parent parent widget of this dialog (QWidget) 59 @param parent parent widget of this dialog (QWidget)
55 """ 60 """
56 super().__init__(parent) 61 super().__init__(parent)
57 self.setupUi(self) 62 self.setupUi(self)
58 self.setWindowFlags(Qt.WindowType.Window) 63 self.setWindowFlags(Qt.WindowType.Window)
59 64
60 self.message.setWordWrapMode(QTextOption.WrapMode.WordWrap) 65 self.message.setWordWrapMode(QTextOption.WrapMode.WordWrap)
61 66
62 self.__mode = mode 67 self.__mode = mode
63 if self.__mode == "feature": 68 if self.__mode == "feature":
64 self.setWindowTitle(self.tr("Send feature request")) 69 self.setWindowTitle(self.tr("Send feature request"))
65 self.msgLabel.setText(self.tr( 70 self.msgLabel.setText(
66 "Enter your &feature request below." 71 self.tr(
67 " Version information is added automatically.")) 72 "Enter your &feature request below."
73 " Version information is added automatically."
74 )
75 )
68 self.__toAddress = FeatureAddress 76 self.__toAddress = FeatureAddress
69 else: 77 else:
70 # default is bug 78 # default is bug
71 self.msgLabel.setText(self.tr( 79 self.msgLabel.setText(
72 "Enter your &bug description below." 80 self.tr(
73 " Version information is added automatically.")) 81 "Enter your &bug description below."
82 " Version information is added automatically."
83 )
84 )
74 self.__toAddress = BugAddress 85 self.__toAddress = BugAddress
75 86
76 self.sendButton = self.buttonBox.addButton( 87 self.sendButton = self.buttonBox.addButton(
77 self.tr("Send"), QDialogButtonBox.ButtonRole.ActionRole) 88 self.tr("Send"), QDialogButtonBox.ButtonRole.ActionRole
89 )
78 self.sendButton.setEnabled(False) 90 self.sendButton.setEnabled(False)
79 self.sendButton.setDefault(True) 91 self.sendButton.setDefault(True)
80 92
81 self.googleHelpButton = self.buttonBox.addButton( 93 self.googleHelpButton = self.buttonBox.addButton(
82 self.tr("Google Mail API Help"), 94 self.tr("Google Mail API Help"), QDialogButtonBox.ButtonRole.HelpRole
83 QDialogButtonBox.ButtonRole.HelpRole) 95 )
84 96
85 height = self.height() 97 height = self.height()
86 self.mainSplitter.setSizes([int(0.7 * height), int(0.3 * height)]) 98 self.mainSplitter.setSizes([int(0.7 * height), int(0.3 * height)])
87 99
88 self.attachments.headerItem().setText( 100 self.attachments.headerItem().setText(self.attachments.columnCount(), "")
89 self.attachments.columnCount(), "")
90 self.attachments.header().setSectionResizeMode( 101 self.attachments.header().setSectionResizeMode(
91 QHeaderView.ResizeMode.Interactive) 102 QHeaderView.ResizeMode.Interactive
92 103 )
104
93 sig = Preferences.getUser("Signature") 105 sig = Preferences.getUser("Signature")
94 if sig: 106 if sig:
95 self.message.setPlainText(sig) 107 self.message.setPlainText(sig)
96 cursor = self.message.textCursor() 108 cursor = self.message.textCursor()
97 cursor.setPosition(0) 109 cursor.setPosition(0)
98 self.message.setTextCursor(cursor) 110 self.message.setTextCursor(cursor)
99 self.message.ensureCursorVisible() 111 self.message.ensureCursorVisible()
100 112
101 self.__deleteFiles = [] 113 self.__deleteFiles = []
102 114
103 self.__helpDialog = None 115 self.__helpDialog = None
104 self.__googleMail = None 116 self.__googleMail = None
105 117
106 def keyPressEvent(self, ev): 118 def keyPressEvent(self, ev):
107 """ 119 """
108 Protected method to handle the user pressing the escape key. 120 Protected method to handle the user pressing the escape key.
109 121
110 @param ev key event (QKeyEvent) 122 @param ev key event (QKeyEvent)
111 """ 123 """
112 if ev.key() == Qt.Key.Key_Escape: 124 if ev.key() == Qt.Key.Key_Escape:
113 res = EricMessageBox.yesNo( 125 res = EricMessageBox.yesNo(
114 self, 126 self,
115 self.tr("Close dialog"), 127 self.tr("Close dialog"),
116 self.tr("""Do you really want to close the dialog?""")) 128 self.tr("""Do you really want to close the dialog?"""),
129 )
117 if res: 130 if res:
118 self.reject() 131 self.reject()
119 132
120 def on_buttonBox_clicked(self, button): 133 def on_buttonBox_clicked(self, button):
121 """ 134 """
122 Private slot called by a button of the button box clicked. 135 Private slot called by a button of the button box clicked.
123 136
124 @param button button that was clicked (QAbstractButton) 137 @param button button that was clicked (QAbstractButton)
125 """ 138 """
126 if button == self.sendButton: 139 if button == self.sendButton:
127 self.on_sendButton_clicked() 140 self.on_sendButton_clicked()
128 elif button == self.googleHelpButton: 141 elif button == self.googleHelpButton:
129 self.on_googleHelpButton_clicked() 142 self.on_googleHelpButton_clicked()
130 143
131 def on_buttonBox_rejected(self): 144 def on_buttonBox_rejected(self):
132 """ 145 """
133 Private slot to handle the rejected signal of the button box. 146 Private slot to handle the rejected signal of the button box.
134 """ 147 """
135 res = EricMessageBox.yesNo( 148 res = EricMessageBox.yesNo(
136 self, 149 self,
137 self.tr("Close dialog"), 150 self.tr("Close dialog"),
138 self.tr("""Do you really want to close the dialog?""")) 151 self.tr("""Do you really want to close the dialog?"""),
152 )
139 if res: 153 if res:
140 self.reject() 154 self.reject()
141 155
142 @pyqtSlot() 156 @pyqtSlot()
143 def on_googleHelpButton_clicked(self): 157 def on_googleHelpButton_clicked(self):
144 """ 158 """
145 Private slot to show some help text "how to turn on the Gmail API". 159 Private slot to show some help text "how to turn on the Gmail API".
146 """ 160 """
147 if self.__helpDialog is None: 161 if self.__helpDialog is None:
148 try: 162 try:
149 from EricNetwork.EricGoogleMail import GoogleMailHelp 163 from EricNetwork.EricGoogleMail import GoogleMailHelp
164
150 helpStr = GoogleMailHelp() 165 helpStr = GoogleMailHelp()
151 except ImportError: 166 except ImportError:
152 from EricNetwork.EricGoogleMailHelpers import getInstallCommand 167 from EricNetwork.EricGoogleMailHelpers import getInstallCommand
168
153 helpStr = self.tr( 169 helpStr = self.tr(
154 "<p>The Google Mail Client API is not installed." 170 "<p>The Google Mail Client API is not installed."
155 " Use <code>{0}</code> to install it.</p>" 171 " Use <code>{0}</code> to install it.</p>"
156 ).format(getInstallCommand()) 172 ).format(getInstallCommand())
157 173
158 from EricWidgets.EricSimpleHelpDialog import EricSimpleHelpDialog 174 from EricWidgets.EricSimpleHelpDialog import EricSimpleHelpDialog
175
159 self.__helpDialog = EricSimpleHelpDialog( 176 self.__helpDialog = EricSimpleHelpDialog(
160 title=self.tr("Gmail API Help"), 177 title=self.tr("Gmail API Help"), helpStr=helpStr, parent=self
161 helpStr=helpStr, parent=self) 178 )
162 179
163 self.__helpDialog.show() 180 self.__helpDialog.show()
164 181
165 @pyqtSlot() 182 @pyqtSlot()
166 def on_sendButton_clicked(self): 183 def on_sendButton_clicked(self):
167 """ 184 """
168 Private slot to send the email message. 185 Private slot to send the email message.
169 """ 186 """
170 msg = ( 187 msg = (
171 self.__createMultipartMail() 188 self.__createMultipartMail()
172 if self.attachments.topLevelItemCount() else 189 if self.attachments.topLevelItemCount()
173 self.__createSimpleMail() 190 else self.__createSimpleMail()
174 ) 191 )
175 192
176 if Preferences.getUser("UseGoogleMailOAuth2"): 193 if Preferences.getUser("UseGoogleMailOAuth2"):
177 self.__sendmailGoogle(msg) 194 self.__sendmailGoogle(msg)
178 else: 195 else:
179 ok = self.__sendmail(msg.as_string()) 196 ok = self.__sendmail(msg.as_string())
180 if ok: 197 if ok:
181 self.__deleteAttachedFiles() 198 self.__deleteAttachedFiles()
182 self.accept() 199 self.accept()
183 200
184 def __deleteAttachedFiles(self): 201 def __deleteAttachedFiles(self):
185 """ 202 """
186 Private method to delete attached files. 203 Private method to delete attached files.
187 """ 204 """
188 for f in self.__deleteFiles: 205 for f in self.__deleteFiles:
189 with contextlib.suppress(OSError): 206 with contextlib.suppress(OSError):
190 os.remove(f) 207 os.remove(f)
191 208
192 def __encodedText(self, txt): 209 def __encodedText(self, txt):
193 """ 210 """
194 Private method to create a MIMEText message with correct encoding. 211 Private method to create a MIMEText message with correct encoding.
195 212
196 @param txt text to be put into the MIMEText object (string) 213 @param txt text to be put into the MIMEText object (string)
197 @return MIMEText object 214 @return MIMEText object
198 """ 215 """
199 try: 216 try:
200 txt.encode("us-ascii") 217 txt.encode("us-ascii")
201 return MIMEText(txt) 218 return MIMEText(txt)
202 except UnicodeEncodeError: 219 except UnicodeEncodeError:
203 coding = Preferences.getSystem("StringEncoding") 220 coding = Preferences.getSystem("StringEncoding")
204 return MIMEText(txt.encode(coding), _charset=coding) 221 return MIMEText(txt.encode(coding), _charset=coding)
205 222
206 def __encodedHeader(self, txt): 223 def __encodedHeader(self, txt):
207 """ 224 """
208 Private method to create a correctly encoded mail header. 225 Private method to create a correctly encoded mail header.
209 226
210 @param txt header text to encode (string) 227 @param txt header text to encode (string)
211 @return encoded header (email.header.Header) 228 @return encoded header (email.header.Header)
212 """ 229 """
213 try: 230 try:
214 txt.encode("us-ascii") 231 txt.encode("us-ascii")
215 return Header(txt) 232 return Header(txt)
216 except UnicodeEncodeError: 233 except UnicodeEncodeError:
217 coding = Preferences.getSystem("StringEncoding") 234 coding = Preferences.getSystem("StringEncoding")
218 return Header(txt, coding) 235 return Header(txt, coding)
219 236
220 def __createSimpleMail(self): 237 def __createSimpleMail(self):
221 """ 238 """
222 Private method to create a simple mail message. 239 Private method to create a simple mail message.
223 240
224 @return prepared mail message 241 @return prepared mail message
225 @rtype email.mime.text.MIMEText 242 @rtype email.mime.text.MIMEText
226 """ 243 """
227 msgtext = "{0}\r\n----\r\n{1}\r\n----\r\n{2}\r\n----\r\n{3}".format( 244 msgtext = "{0}\r\n----\r\n{1}\r\n----\r\n{2}\r\n----\r\n{3}".format(
228 self.message.toPlainText(), 245 self.message.toPlainText(),
229 Utilities.generateVersionInfo("\r\n"), 246 Utilities.generateVersionInfo("\r\n"),
230 Utilities.generatePluginsVersionInfo("\r\n"), 247 Utilities.generatePluginsVersionInfo("\r\n"),
231 Utilities.generateDistroInfo("\r\n")) 248 Utilities.generateDistroInfo("\r\n"),
232 249 )
250
233 msg = self.__encodedText(msgtext) 251 msg = self.__encodedText(msgtext)
234 msg['From'] = Preferences.getUser("Email") 252 msg["From"] = Preferences.getUser("Email")
235 msg['To'] = self.__toAddress 253 msg["To"] = self.__toAddress
236 subject = '[eric7] {0}'.format(self.subject.text()) 254 subject = "[eric7] {0}".format(self.subject.text())
237 msg['Subject'] = self.__encodedHeader(subject) 255 msg["Subject"] = self.__encodedHeader(subject)
238 256
239 return msg 257 return msg
240 258
241 def __createMultipartMail(self): 259 def __createMultipartMail(self):
242 """ 260 """
243 Private method to create a multipart mail message. 261 Private method to create a multipart mail message.
244 262
245 @return prepared mail message 263 @return prepared mail message
246 @rtype email.mime.text.MIMEMultipart 264 @rtype email.mime.text.MIMEMultipart
247 """ 265 """
248 mpPreamble = ("This is a MIME-encoded message with attachments. " 266 mpPreamble = (
249 "If you see this message, your mail client is not " 267 "This is a MIME-encoded message with attachments. "
250 "capable of displaying the attachments.") 268 "If you see this message, your mail client is not "
251 269 "capable of displaying the attachments."
270 )
271
252 msgtext = "{0}\r\n----\r\n{1}\r\n----\r\n{2}\r\n----\r\n{3}".format( 272 msgtext = "{0}\r\n----\r\n{1}\r\n----\r\n{2}\r\n----\r\n{3}".format(
253 self.message.toPlainText(), 273 self.message.toPlainText(),
254 Utilities.generateVersionInfo("\r\n"), 274 Utilities.generateVersionInfo("\r\n"),
255 Utilities.generatePluginsVersionInfo("\r\n"), 275 Utilities.generatePluginsVersionInfo("\r\n"),
256 Utilities.generateDistroInfo("\r\n")) 276 Utilities.generateDistroInfo("\r\n"),
257 277 )
278
258 # first part of multipart mail explains format 279 # first part of multipart mail explains format
259 msg = MIMEMultipart() 280 msg = MIMEMultipart()
260 msg['From'] = Preferences.getUser("Email") 281 msg["From"] = Preferences.getUser("Email")
261 msg['To'] = self.__toAddress 282 msg["To"] = self.__toAddress
262 subject = '[eric7] {0}'.format(self.subject.text()) 283 subject = "[eric7] {0}".format(self.subject.text())
263 msg['Subject'] = self.__encodedHeader(subject) 284 msg["Subject"] = self.__encodedHeader(subject)
264 msg.preamble = mpPreamble 285 msg.preamble = mpPreamble
265 msg.epilogue = '' 286 msg.epilogue = ""
266 287
267 # second part is intended to be read 288 # second part is intended to be read
268 att = self.__encodedText(msgtext) 289 att = self.__encodedText(msgtext)
269 msg.attach(att) 290 msg.attach(att)
270 291
271 # next parts contain the attachments 292 # next parts contain the attachments
272 for index in range(self.attachments.topLevelItemCount()): 293 for index in range(self.attachments.topLevelItemCount()):
273 itm = self.attachments.topLevelItem(index) 294 itm = self.attachments.topLevelItem(index)
274 maintype, subtype = itm.text(1).split('/', 1) 295 maintype, subtype = itm.text(1).split("/", 1)
275 fname = itm.text(0) 296 fname = itm.text(0)
276 name = os.path.basename(fname) 297 name = os.path.basename(fname)
277 298
278 if maintype == 'text': 299 if maintype == "text":
279 with open(fname, 'r', encoding="utf-8") as f: 300 with open(fname, "r", encoding="utf-8") as f:
280 txt = f.read() 301 txt = f.read()
281 try: 302 try:
282 txt.encode("us-ascii") 303 txt.encode("us-ascii")
283 att = MIMEText(txt, _subtype=subtype) 304 att = MIMEText(txt, _subtype=subtype)
284 except UnicodeEncodeError: 305 except UnicodeEncodeError:
285 att = MIMEText( 306 att = MIMEText(
286 txt.encode("utf-8"), _subtype=subtype, 307 txt.encode("utf-8"), _subtype=subtype, _charset="utf-8"
287 _charset="utf-8") 308 )
288 elif maintype == 'image': 309 elif maintype == "image":
289 with open(fname, 'rb') as f: 310 with open(fname, "rb") as f:
290 att = MIMEImage(f.read(), _subtype=subtype) 311 att = MIMEImage(f.read(), _subtype=subtype)
291 elif maintype == 'audio': 312 elif maintype == "audio":
292 with open(fname, 'rb') as f: 313 with open(fname, "rb") as f:
293 att = MIMEAudio(f.read(), _subtype=subtype) 314 att = MIMEAudio(f.read(), _subtype=subtype)
294 else: 315 else:
295 with open(fname, 'rb') as f: 316 with open(fname, "rb") as f:
296 att = MIMEApplication(f.read()) 317 att = MIMEApplication(f.read())
297 att.add_header('Content-Disposition', 'attachment', filename=name) 318 att.add_header("Content-Disposition", "attachment", filename=name)
298 msg.attach(att) 319 msg.attach(att)
299 320
300 return msg 321 return msg
301 322
302 def __sendmail(self, msg): 323 def __sendmail(self, msg):
303 """ 324 """
304 Private method to actually send the message. 325 Private method to actually send the message.
305 326
306 @param msg the message to be sent (string) 327 @param msg the message to be sent (string)
307 @return flag indicating success (boolean) 328 @return flag indicating success (boolean)
308 """ 329 """
309 try: 330 try:
310 encryption = Preferences.getUser("MailServerEncryption") 331 encryption = Preferences.getUser("MailServerEncryption")
311 if encryption == "SSL": 332 if encryption == "SSL":
312 server = smtplib.SMTP_SSL( 333 server = smtplib.SMTP_SSL(
313 Preferences.getUser("MailServer"), 334 Preferences.getUser("MailServer"),
314 Preferences.getUser("MailServerPort")) 335 Preferences.getUser("MailServerPort"),
336 )
315 else: 337 else:
316 server = smtplib.SMTP( 338 server = smtplib.SMTP(
317 Preferences.getUser("MailServer"), 339 Preferences.getUser("MailServer"),
318 Preferences.getUser("MailServerPort")) 340 Preferences.getUser("MailServerPort"),
341 )
319 if encryption == "TLS": 342 if encryption == "TLS":
320 server.starttls() 343 server.starttls()
321 if Preferences.getUser("MailServerAuthentication"): 344 if Preferences.getUser("MailServerAuthentication"):
322 # mail server needs authentication 345 # mail server needs authentication
323 password = Preferences.getUser("MailServerPassword") 346 password = Preferences.getUser("MailServerPassword")
324 if not password: 347 if not password:
325 password, ok = QInputDialog.getText( 348 password, ok = QInputDialog.getText(
326 self, 349 self,
327 self.tr("Mail Server Password"), 350 self.tr("Mail Server Password"),
328 self.tr("Enter your mail server password"), 351 self.tr("Enter your mail server password"),
329 QLineEdit.EchoMode.Password) 352 QLineEdit.EchoMode.Password,
353 )
330 if not ok: 354 if not ok:
331 # abort 355 # abort
332 return False 356 return False
333 try: 357 try:
334 server.login(Preferences.getUser("MailServerUser"), 358 server.login(Preferences.getUser("MailServerUser"), password)
335 password)
336 except (smtplib.SMTPException, OSError) as e: 359 except (smtplib.SMTPException, OSError) as e:
337 if isinstance(e, smtplib.SMTPResponseException): 360 if isinstance(e, smtplib.SMTPResponseException):
338 errorStr = e.smtp_error.decode() 361 errorStr = e.smtp_error.decode()
339 elif isinstance(e, OSError): 362 elif isinstance(e, OSError):
340 errorStr = e.strerror 363 errorStr = e.strerror
344 errorStr = str(e) 367 errorStr = str(e)
345 res = EricMessageBox.retryAbort( 368 res = EricMessageBox.retryAbort(
346 self, 369 self,
347 self.tr("Send Message"), 370 self.tr("Send Message"),
348 self.tr( 371 self.tr(
349 """<p>Authentication failed.<br>Reason: {0}</p>""") 372 """<p>Authentication failed.<br>Reason: {0}</p>"""
350 .format(errorStr), 373 ).format(errorStr),
351 EricMessageBox.Critical) 374 EricMessageBox.Critical,
375 )
352 if res: 376 if res:
353 return self.__sendmail(msg) 377 return self.__sendmail(msg)
354 else: 378 else:
355 return False 379 return False
356 380
357 with EricOverrideCursor(): 381 with EricOverrideCursor():
358 server.sendmail(Preferences.getUser("Email"), self.__toAddress, 382 server.sendmail(Preferences.getUser("Email"), self.__toAddress, msg)
359 msg)
360 server.quit() 383 server.quit()
361 except (smtplib.SMTPException, OSError) as e: 384 except (smtplib.SMTPException, OSError) as e:
362 if isinstance(e, smtplib.SMTPResponseException): 385 if isinstance(e, smtplib.SMTPResponseException):
363 errorStr = e.smtp_error.decode() 386 errorStr = e.smtp_error.decode()
364 elif isinstance(e, smtplib.SMTPException): 387 elif isinstance(e, smtplib.SMTPException):
368 else: 391 else:
369 errorStr = str(e) 392 errorStr = str(e)
370 res = EricMessageBox.retryAbort( 393 res = EricMessageBox.retryAbort(
371 self, 394 self,
372 self.tr("Send Message"), 395 self.tr("Send Message"),
373 self.tr( 396 self.tr("""<p>Message could not be sent.<br>Reason: {0}</p>""").format(
374 """<p>Message could not be sent.<br>Reason: {0}</p>""") 397 errorStr
375 .format(errorStr), 398 ),
376 EricMessageBox.Critical) 399 EricMessageBox.Critical,
400 )
377 if res: 401 if res:
378 return self.__sendmail(msg) 402 return self.__sendmail(msg)
379 else: 403 else:
380 return False 404 return False
381 return True 405 return True
382 406
383 def __sendmailGoogle(self, msg): 407 def __sendmailGoogle(self, msg):
384 """ 408 """
385 Private method to actually send the message via Google Mail. 409 Private method to actually send the message via Google Mail.
386 410
387 @param msg email message to be sent 411 @param msg email message to be sent
388 @type email.mime.text.MIMEBase 412 @type email.mime.text.MIMEBase
389 """ 413 """
390 from EricNetwork.EricGoogleMail import EricGoogleMail 414 from EricNetwork.EricGoogleMail import EricGoogleMail
391 415
392 if self.__googleMail is None: 416 if self.__googleMail is None:
393 self.__googleMail = EricGoogleMail(self) 417 self.__googleMail = EricGoogleMail(self)
394 self.__googleMail.sendResult.connect(self.__gmailSendResult) 418 self.__googleMail.sendResult.connect(self.__gmailSendResult)
395 419
396 self.__googleMail.sendMessage(msg) 420 self.__googleMail.sendMessage(msg)
397 421
398 @pyqtSlot(bool, str) 422 @pyqtSlot(bool, str)
399 def __gmailSendResult(self, ok, message): 423 def __gmailSendResult(self, ok, message):
400 """ 424 """
401 Private slot handling the send result reported by the Google Mail 425 Private slot handling the send result reported by the Google Mail
402 interface. 426 interface.
403 427
404 @param ok flag indicating success 428 @param ok flag indicating success
405 @type bool 429 @type bool
406 @param message message from the interface 430 @param message message from the interface
407 @type str 431 @type str
408 """ 432 """
412 else: 436 else:
413 # we got an error 437 # we got an error
414 EricMessageBox.critical( 438 EricMessageBox.critical(
415 self, 439 self,
416 self.tr("Send Message via Gmail"), 440 self.tr("Send Message via Gmail"),
417 self.tr( 441 self.tr("""<p>Message could not be sent.<br>Reason: {0}</p>""").format(
418 """<p>Message could not be sent.<br>Reason: {0}</p>""") 442 message
419 .format(message) 443 ),
420 ) 444 )
421 445
422 @pyqtSlot() 446 @pyqtSlot()
423 def on_addButton_clicked(self): 447 def on_addButton_clicked(self):
424 """ 448 """
425 Private slot to handle the Add... button. 449 Private slot to handle the Add... button.
426 """ 450 """
427 fname = EricFileDialog.getOpenFileName( 451 fname = EricFileDialog.getOpenFileName(self, self.tr("Attach file"))
428 self,
429 self.tr("Attach file"))
430 if fname: 452 if fname:
431 self.attachFile(fname, False) 453 self.attachFile(fname, False)
432 454
433 def attachFile(self, fname, deleteFile): 455 def attachFile(self, fname, deleteFile):
434 """ 456 """
435 Public method to add an attachment. 457 Public method to add an attachment.
436 458
437 @param fname name of the file to be attached (string) 459 @param fname name of the file to be attached (string)
438 @param deleteFile flag indicating to delete the file after it has 460 @param deleteFile flag indicating to delete the file after it has
439 been sent (boolean) 461 been sent (boolean)
440 """ 462 """
441 mimeType = mimetypes.guess_type(fname)[0] 463 mimeType = mimetypes.guess_type(fname)[0]
442 if not mimeType: 464 if not mimeType:
443 mimeType = "application/octet-stream" 465 mimeType = "application/octet-stream"
444 QTreeWidgetItem(self.attachments, [fname, mimeType]) 466 QTreeWidgetItem(self.attachments, [fname, mimeType])
445 self.attachments.header().resizeSections( 467 self.attachments.header().resizeSections(
446 QHeaderView.ResizeMode.ResizeToContents) 468 QHeaderView.ResizeMode.ResizeToContents
469 )
447 self.attachments.header().setStretchLastSection(True) 470 self.attachments.header().setStretchLastSection(True)
448 471
449 if deleteFile: 472 if deleteFile:
450 self.__deleteFiles.append(fname) 473 self.__deleteFiles.append(fname)
451 474
452 @pyqtSlot() 475 @pyqtSlot()
453 def on_deleteButton_clicked(self): 476 def on_deleteButton_clicked(self):
454 """ 477 """
455 Private slot to handle the Delete button. 478 Private slot to handle the Delete button.
456 """ 479 """
457 itm = self.attachments.currentItem() 480 itm = self.attachments.currentItem()
458 if itm is not None: 481 if itm is not None:
459 itm = self.attachments.takeTopLevelItem( 482 itm = self.attachments.takeTopLevelItem(
460 self.attachments.indexOfTopLevelItem(itm)) 483 self.attachments.indexOfTopLevelItem(itm)
484 )
461 del itm 485 del itm
462 486
463 def on_subject_textChanged(self, txt): 487 def on_subject_textChanged(self, txt):
464 """ 488 """
465 Private slot to handle the textChanged signal of the subject edit. 489 Private slot to handle the textChanged signal of the subject edit.
466 490
467 @param txt changed text (string) 491 @param txt changed text (string)
468 """ 492 """
469 self.sendButton.setEnabled( 493 self.sendButton.setEnabled(
470 self.subject.text() != "" and 494 self.subject.text() != "" and self.message.toPlainText() != ""
471 self.message.toPlainText() != "") 495 )
472 496
473 def on_message_textChanged(self): 497 def on_message_textChanged(self):
474 """ 498 """
475 Private slot to handle the textChanged signal of the message edit. 499 Private slot to handle the textChanged signal of the message edit.
476 """ 500 """
477 self.sendButton.setEnabled( 501 self.sendButton.setEnabled(
478 self.subject.text() != "" and 502 self.subject.text() != "" and self.message.toPlainText() != ""
479 self.message.toPlainText() != "") 503 )

eric ide

mercurial