src/eric7/UI/EmailDialog.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
--- a/src/eric7/UI/EmailDialog.py	Wed Jul 13 11:16:20 2022 +0200
+++ b/src/eric7/UI/EmailDialog.py	Wed Jul 13 14:55:47 2022 +0200
@@ -15,8 +15,12 @@
 from PyQt6.QtCore import Qt, pyqtSlot
 from PyQt6.QtGui import QTextOption
 from PyQt6.QtWidgets import (
-    QHeaderView, QLineEdit, QDialog, QInputDialog, QDialogButtonBox,
-    QTreeWidgetItem
+    QHeaderView,
+    QLineEdit,
+    QDialog,
+    QInputDialog,
+    QDialogButtonBox,
+    QTreeWidgetItem,
 )
 
 from EricWidgets import EricMessageBox, EricFileDialog
@@ -46,50 +50,58 @@
     """
     Class implementing a dialog to send bug reports or feature requests.
     """
+
     def __init__(self, mode="bug", parent=None):
         """
         Constructor
-        
+
         @param mode mode of this dialog (string, "bug" or "feature")
         @param parent parent widget of this dialog (QWidget)
         """
         super().__init__(parent)
         self.setupUi(self)
         self.setWindowFlags(Qt.WindowType.Window)
-        
+
         self.message.setWordWrapMode(QTextOption.WrapMode.WordWrap)
-        
+
         self.__mode = mode
         if self.__mode == "feature":
             self.setWindowTitle(self.tr("Send feature request"))
-            self.msgLabel.setText(self.tr(
-                "Enter your &feature request below."
-                " Version information is added automatically."))
+            self.msgLabel.setText(
+                self.tr(
+                    "Enter your &feature request below."
+                    " Version information is added automatically."
+                )
+            )
             self.__toAddress = FeatureAddress
         else:
             # default is bug
-            self.msgLabel.setText(self.tr(
-                "Enter your &bug description below."
-                " Version information is added automatically."))
+            self.msgLabel.setText(
+                self.tr(
+                    "Enter your &bug description below."
+                    " Version information is added automatically."
+                )
+            )
             self.__toAddress = BugAddress
-        
+
         self.sendButton = self.buttonBox.addButton(
-            self.tr("Send"), QDialogButtonBox.ButtonRole.ActionRole)
+            self.tr("Send"), QDialogButtonBox.ButtonRole.ActionRole
+        )
         self.sendButton.setEnabled(False)
         self.sendButton.setDefault(True)
-        
+
         self.googleHelpButton = self.buttonBox.addButton(
-            self.tr("Google Mail API Help"),
-            QDialogButtonBox.ButtonRole.HelpRole)
-        
+            self.tr("Google Mail API Help"), QDialogButtonBox.ButtonRole.HelpRole
+        )
+
         height = self.height()
         self.mainSplitter.setSizes([int(0.7 * height), int(0.3 * height)])
-        
-        self.attachments.headerItem().setText(
-            self.attachments.columnCount(), "")
+
+        self.attachments.headerItem().setText(self.attachments.columnCount(), "")
         self.attachments.header().setSectionResizeMode(
-            QHeaderView.ResizeMode.Interactive)
-        
+            QHeaderView.ResizeMode.Interactive
+        )
+
         sig = Preferences.getUser("Signature")
         if sig:
             self.message.setPlainText(sig)
@@ -97,37 +109,38 @@
             cursor.setPosition(0)
             self.message.setTextCursor(cursor)
             self.message.ensureCursorVisible()
-        
+
         self.__deleteFiles = []
-        
+
         self.__helpDialog = None
         self.__googleMail = None
-    
+
     def keyPressEvent(self, ev):
         """
         Protected method to handle the user pressing the escape key.
-        
+
         @param ev key event (QKeyEvent)
         """
         if ev.key() == Qt.Key.Key_Escape:
             res = EricMessageBox.yesNo(
                 self,
                 self.tr("Close dialog"),
-                self.tr("""Do you really want to close the dialog?"""))
+                self.tr("""Do you really want to close the dialog?"""),
+            )
             if res:
                 self.reject()
-        
+
     def on_buttonBox_clicked(self, button):
         """
         Private slot called by a button of the button box clicked.
-        
+
         @param button button that was clicked (QAbstractButton)
         """
         if button == self.sendButton:
             self.on_sendButton_clicked()
         elif button == self.googleHelpButton:
             self.on_googleHelpButton_clicked()
-        
+
     def on_buttonBox_rejected(self):
         """
         Private slot to handle the rejected signal of the button box.
@@ -135,10 +148,11 @@
         res = EricMessageBox.yesNo(
             self,
             self.tr("Close dialog"),
-            self.tr("""Do you really want to close the dialog?"""))
+            self.tr("""Do you really want to close the dialog?"""),
+        )
         if res:
             self.reject()
-    
+
     @pyqtSlot()
     def on_googleHelpButton_clicked(self):
         """
@@ -147,21 +161,24 @@
         if self.__helpDialog is None:
             try:
                 from EricNetwork.EricGoogleMail import GoogleMailHelp
+
                 helpStr = GoogleMailHelp()
             except ImportError:
                 from EricNetwork.EricGoogleMailHelpers import getInstallCommand
+
                 helpStr = self.tr(
                     "<p>The Google Mail Client API is not installed."
                     " Use <code>{0}</code> to install it.</p>"
                 ).format(getInstallCommand())
-            
+
             from EricWidgets.EricSimpleHelpDialog import EricSimpleHelpDialog
+
             self.__helpDialog = EricSimpleHelpDialog(
-                title=self.tr("Gmail API Help"),
-                helpStr=helpStr, parent=self)
-        
+                title=self.tr("Gmail API Help"), helpStr=helpStr, parent=self
+            )
+
         self.__helpDialog.show()
-    
+
     @pyqtSlot()
     def on_sendButton_clicked(self):
         """
@@ -169,10 +186,10 @@
         """
         msg = (
             self.__createMultipartMail()
-            if self.attachments.topLevelItemCount() else
-            self.__createSimpleMail()
+            if self.attachments.topLevelItemCount()
+            else self.__createSimpleMail()
         )
-        
+
         if Preferences.getUser("UseGoogleMailOAuth2"):
             self.__sendmailGoogle(msg)
         else:
@@ -180,7 +197,7 @@
             if ok:
                 self.__deleteAttachedFiles()
                 self.accept()
-    
+
     def __deleteAttachedFiles(self):
         """
         Private method to delete attached files.
@@ -188,11 +205,11 @@
         for f in self.__deleteFiles:
             with contextlib.suppress(OSError):
                 os.remove(f)
-    
+
     def __encodedText(self, txt):
         """
         Private method to create a MIMEText message with correct encoding.
-        
+
         @param txt text to be put into the MIMEText object (string)
         @return MIMEText object
         """
@@ -202,11 +219,11 @@
         except UnicodeEncodeError:
             coding = Preferences.getSystem("StringEncoding")
             return MIMEText(txt.encode(coding), _charset=coding)
-        
+
     def __encodedHeader(self, txt):
         """
         Private method to create a correctly encoded mail header.
-        
+
         @param txt header text to encode (string)
         @return encoded header (email.header.Header)
         """
@@ -216,11 +233,11 @@
         except UnicodeEncodeError:
             coding = Preferences.getSystem("StringEncoding")
             return Header(txt, coding)
-        
+
     def __createSimpleMail(self):
         """
         Private method to create a simple mail message.
-        
+
         @return prepared mail message
         @rtype email.mime.text.MIMEText
         """
@@ -228,81 +245,85 @@
             self.message.toPlainText(),
             Utilities.generateVersionInfo("\r\n"),
             Utilities.generatePluginsVersionInfo("\r\n"),
-            Utilities.generateDistroInfo("\r\n"))
-        
+            Utilities.generateDistroInfo("\r\n"),
+        )
+
         msg = self.__encodedText(msgtext)
-        msg['From'] = Preferences.getUser("Email")
-        msg['To'] = self.__toAddress
-        subject = '[eric7] {0}'.format(self.subject.text())
-        msg['Subject'] = self.__encodedHeader(subject)
-        
+        msg["From"] = Preferences.getUser("Email")
+        msg["To"] = self.__toAddress
+        subject = "[eric7] {0}".format(self.subject.text())
+        msg["Subject"] = self.__encodedHeader(subject)
+
         return msg
-        
+
     def __createMultipartMail(self):
         """
         Private method to create a multipart mail message.
-        
+
         @return prepared mail message
         @rtype email.mime.text.MIMEMultipart
         """
-        mpPreamble = ("This is a MIME-encoded message with attachments. "
-                      "If you see this message, your mail client is not "
-                      "capable of displaying the attachments.")
-        
+        mpPreamble = (
+            "This is a MIME-encoded message with attachments. "
+            "If you see this message, your mail client is not "
+            "capable of displaying the attachments."
+        )
+
         msgtext = "{0}\r\n----\r\n{1}\r\n----\r\n{2}\r\n----\r\n{3}".format(
             self.message.toPlainText(),
             Utilities.generateVersionInfo("\r\n"),
             Utilities.generatePluginsVersionInfo("\r\n"),
-            Utilities.generateDistroInfo("\r\n"))
-        
+            Utilities.generateDistroInfo("\r\n"),
+        )
+
         # first part of multipart mail explains format
         msg = MIMEMultipart()
-        msg['From'] = Preferences.getUser("Email")
-        msg['To'] = self.__toAddress
-        subject = '[eric7] {0}'.format(self.subject.text())
-        msg['Subject'] = self.__encodedHeader(subject)
+        msg["From"] = Preferences.getUser("Email")
+        msg["To"] = self.__toAddress
+        subject = "[eric7] {0}".format(self.subject.text())
+        msg["Subject"] = self.__encodedHeader(subject)
         msg.preamble = mpPreamble
-        msg.epilogue = ''
-        
+        msg.epilogue = ""
+
         # second part is intended to be read
         att = self.__encodedText(msgtext)
         msg.attach(att)
-        
+
         # next parts contain the attachments
         for index in range(self.attachments.topLevelItemCount()):
             itm = self.attachments.topLevelItem(index)
-            maintype, subtype = itm.text(1).split('/', 1)
+            maintype, subtype = itm.text(1).split("/", 1)
             fname = itm.text(0)
             name = os.path.basename(fname)
-            
-            if maintype == 'text':
-                with open(fname, 'r', encoding="utf-8") as f:
+
+            if maintype == "text":
+                with open(fname, "r", encoding="utf-8") as f:
                     txt = f.read()
                 try:
                     txt.encode("us-ascii")
                     att = MIMEText(txt, _subtype=subtype)
                 except UnicodeEncodeError:
                     att = MIMEText(
-                        txt.encode("utf-8"), _subtype=subtype,
-                        _charset="utf-8")
-            elif maintype == 'image':
-                with open(fname, 'rb') as f:
+                        txt.encode("utf-8"), _subtype=subtype, _charset="utf-8"
+                    )
+            elif maintype == "image":
+                with open(fname, "rb") as f:
                     att = MIMEImage(f.read(), _subtype=subtype)
-            elif maintype == 'audio':
-                with open(fname, 'rb') as f:
+            elif maintype == "audio":
+                with open(fname, "rb") as f:
                     att = MIMEAudio(f.read(), _subtype=subtype)
             else:
-                with open(fname, 'rb') as f:
+                with open(fname, "rb") as f:
                     att = MIMEApplication(f.read())
-            att.add_header('Content-Disposition', 'attachment', filename=name)
+            att.add_header("Content-Disposition", "attachment", filename=name)
             msg.attach(att)
-            
+
         return msg
 
     def __sendmail(self, msg):
         """
         Private method to actually send the message.
-        
+
         @param msg the message to be sent (string)
         @return flag indicating success (boolean)
         """
@@ -311,11 +332,13 @@
             if encryption == "SSL":
                 server = smtplib.SMTP_SSL(
                     Preferences.getUser("MailServer"),
-                    Preferences.getUser("MailServerPort"))
+                    Preferences.getUser("MailServerPort"),
+                )
             else:
                 server = smtplib.SMTP(
                     Preferences.getUser("MailServer"),
-                    Preferences.getUser("MailServerPort"))
+                    Preferences.getUser("MailServerPort"),
+                )
                 if encryption == "TLS":
                     server.starttls()
             if Preferences.getUser("MailServerAuthentication"):
@@ -326,13 +349,13 @@
                         self,
                         self.tr("Mail Server Password"),
                         self.tr("Enter your mail server password"),
-                        QLineEdit.EchoMode.Password)
+                        QLineEdit.EchoMode.Password,
+                    )
                     if not ok:
                         # abort
                         return False
                 try:
-                    server.login(Preferences.getUser("MailServerUser"),
-                                 password)
+                    server.login(Preferences.getUser("MailServerUser"), password)
                 except (smtplib.SMTPException, OSError) as e:
                     if isinstance(e, smtplib.SMTPResponseException):
                         errorStr = e.smtp_error.decode()
@@ -346,17 +369,17 @@
                         self,
                         self.tr("Send Message"),
                         self.tr(
-                            """<p>Authentication failed.<br>Reason: {0}</p>""")
-                        .format(errorStr),
-                        EricMessageBox.Critical)
+                            """<p>Authentication failed.<br>Reason: {0}</p>"""
+                        ).format(errorStr),
+                        EricMessageBox.Critical,
+                    )
                     if res:
                         return self.__sendmail(msg)
                     else:
                         return False
 
             with EricOverrideCursor():
-                server.sendmail(Preferences.getUser("Email"), self.__toAddress,
-                                msg)
+                server.sendmail(Preferences.getUser("Email"), self.__toAddress, msg)
                 server.quit()
         except (smtplib.SMTPException, OSError) as e:
             if isinstance(e, smtplib.SMTPResponseException):
@@ -370,37 +393,38 @@
             res = EricMessageBox.retryAbort(
                 self,
                 self.tr("Send Message"),
-                self.tr(
-                    """<p>Message could not be sent.<br>Reason: {0}</p>""")
-                .format(errorStr),
-                EricMessageBox.Critical)
+                self.tr("""<p>Message could not be sent.<br>Reason: {0}</p>""").format(
+                    errorStr
+                ),
+                EricMessageBox.Critical,
+            )
             if res:
                 return self.__sendmail(msg)
             else:
                 return False
         return True
-    
+
     def __sendmailGoogle(self, msg):
         """
         Private method to actually send the message via Google Mail.
-        
+
         @param msg email message to be sent
         @type email.mime.text.MIMEBase
         """
         from EricNetwork.EricGoogleMail import EricGoogleMail
-        
+
         if self.__googleMail is None:
             self.__googleMail = EricGoogleMail(self)
             self.__googleMail.sendResult.connect(self.__gmailSendResult)
-        
+
         self.__googleMail.sendMessage(msg)
-    
+
     @pyqtSlot(bool, str)
     def __gmailSendResult(self, ok, message):
         """
         Private slot handling the send result reported by the Google Mail
         interface.
-        
+
         @param ok flag indicating success
         @type bool
         @param message message from the interface
@@ -414,26 +438,24 @@
             EricMessageBox.critical(
                 self,
                 self.tr("Send Message via Gmail"),
-                self.tr(
-                    """<p>Message could not be sent.<br>Reason: {0}</p>""")
-                .format(message)
+                self.tr("""<p>Message could not be sent.<br>Reason: {0}</p>""").format(
+                    message
+                ),
             )
-    
+
     @pyqtSlot()
     def on_addButton_clicked(self):
         """
         Private slot to handle the Add... button.
         """
-        fname = EricFileDialog.getOpenFileName(
-            self,
-            self.tr("Attach file"))
+        fname = EricFileDialog.getOpenFileName(self, self.tr("Attach file"))
         if fname:
             self.attachFile(fname, False)
-        
+
     def attachFile(self, fname, deleteFile):
         """
         Public method to add an attachment.
-        
+
         @param fname name of the file to be attached (string)
         @param deleteFile flag indicating to delete the file after it has
             been sent (boolean)
@@ -443,12 +465,13 @@
             mimeType = "application/octet-stream"
         QTreeWidgetItem(self.attachments, [fname, mimeType])
         self.attachments.header().resizeSections(
-            QHeaderView.ResizeMode.ResizeToContents)
+            QHeaderView.ResizeMode.ResizeToContents
+        )
         self.attachments.header().setStretchLastSection(True)
-        
+
         if deleteFile:
             self.__deleteFiles.append(fname)
-        
+
     @pyqtSlot()
     def on_deleteButton_clicked(self):
         """
@@ -457,23 +480,24 @@
         itm = self.attachments.currentItem()
         if itm is not None:
             itm = self.attachments.takeTopLevelItem(
-                self.attachments.indexOfTopLevelItem(itm))
+                self.attachments.indexOfTopLevelItem(itm)
+            )
             del itm
-        
+
     def on_subject_textChanged(self, txt):
         """
         Private slot to handle the textChanged signal of the subject edit.
-        
+
         @param txt changed text (string)
         """
         self.sendButton.setEnabled(
-            self.subject.text() != "" and
-            self.message.toPlainText() != "")
-        
+            self.subject.text() != "" and self.message.toPlainText() != ""
+        )
+
     def on_message_textChanged(self):
         """
         Private slot to handle the textChanged signal of the message edit.
         """
         self.sendButton.setEnabled(
-            self.subject.text() != "" and
-            self.message.toPlainText() != "")
+            self.subject.text() != "" and self.message.toPlainText() != ""
+        )

eric ide

mercurial