File r890881.diff of Package kdepim4

Subject: kmail: fix unreactive encoding change dialog
From: wstephenson@suse.de
Bug: kde#149309,kde#145163
Patch-upstream: 890881
--- kmail/messagecomposer.h	(revision 890880)
+++ kmail/messagecomposer.h	(revision 890881)
@@ -133,12 +133,35 @@ class MessageComposer : public QObject {
                                       bool doSign, bool doEncrypt );
 
     /**
+     * Reads the plain text version and the HTML code from the edit widget,
+     * applies linebreaks and encodes those with the current charset.
+     *
+     * @return false if not all chars could be encoded with the current charset.
+     */
+    bool getSourceText( QString &plainText, QString &htmlSource,
+                        QByteArray &plainTextEncoded, QByteArray &htmlSourceEncoded ) const;
+
+    /**
      * This sets the member variables mHtmlSource and mPlainText and mBodyText.
      * The text is taken from the composer (with proper wordwrapping) and
      * then encoded with the correct codec.
      * The user is warned if the codec can't encode all characters.
+     *
+     * @return false if any error occured, for example if the text of the body
+     *         couldn't be encoded.
+     */
+    bool breakLinesAndApplyCodec();
+
+    /**
+     * This will automatically detect the charset needed to encode the text of
+     * the composer.
+     * mCharset will be set to the detected character set, and the charset of
+     * the composer window will be set as well.
+     *
+     * @return true if the detection was successfull, false if no suitable
+     *         charset was found.
      */
-    void breakLinesAndApplyCodec();
+    bool autoDetectCharset();
 
     /*
       Gets the signature for a message (into mMessage).
--- kmail/kmcomposereditor.h	(revision 890880)
+++ kmail/kmcomposereditor.h	(revision 890881)
@@ -40,6 +40,12 @@ class KMComposerEditor : public KMeditor
     ~KMComposerEditor();
 
     virtual QString quotePrefixName() const;
+    /**
+     * This replaces all characters not known to the specified codec with
+     * questionmarks. HTML formatting is preserved.
+     */
+    void replaceUnknownChars( const QTextCodec *codec );
+
     virtual QString smartQuote( const QString & msg );
     virtual void changeHighlighterColors(KPIM::KEMailQuotingHighlighter * highlighter);
 
--- kmail/messagecomposer.cpp	(revision 890880)
+++ kmail/messagecomposer.cpp	(revision 890881)
@@ -467,20 +467,11 @@ void MessageComposer::readFromComposeWin
   mAllowedCryptoMessageFormats = mComposeWin->cryptoMessageFormat();
 
   if ( mAutoCharset ) {
-    QByteArray charset =
-      KMMsgBase::autoDetectCharset( mCharset, KMMessage::preferredCharsets(),
-                                    mComposeWin->mEditor->textOrHtml() );
-    if ( charset.isEmpty() ) {
-      KMessageBox::sorry( mComposeWin,
-                          i18n( "No suitable encoding could be found for "
-                                "your message.\nPlease set an encoding "
-                                "using the 'Options' menu." ) );
+    bool charsetFound = autoDetectCharset();
+    if ( !charsetFound ) {
       mRc = false;
       return;
     }
-    mCharset = charset;
-    // Also apply this to the composer window
-    mComposeWin->mCharset = charset;
   }
   mReferenceMessage->setCharset(mCharset);
 
@@ -559,7 +550,10 @@ void MessageComposer::readFromComposeWin
 
   mIsRichText = ( mComposeWin->mEditor->textMode() == KMeditor::Rich );
   mIdentityUid = mComposeWin->identityUid();
-  breakLinesAndApplyCodec();
+  if ( !breakLinesAndApplyCodec() ) {
+    mRc = false;
+    return;
+  }
 }
 
 static QByteArray escape_quoted_string( const QByteArray &str ) {
@@ -2126,7 +2120,25 @@ bool MessageComposer::processStructuring
 }
 
 //-----------------------------------------------------------------------------
-void MessageComposer::breakLinesAndApplyCodec()
+bool MessageComposer::autoDetectCharset()
+{
+  QByteArray charset =
+      KMMsgBase::autoDetectCharset( mCharset, KMMessage::preferredCharsets(),
+                                    mComposeWin->mEditor->textOrHtml() );
+  if ( charset.isEmpty() ) {
+    KMessageBox::sorry( mComposeWin,
+                        i18n( "No suitable encoding could be found for "
+                              "your message.\nPlease set an encoding "
+                              "using the 'Options' menu." ) );
+    return false;
+  }
+  mCharset = charset;
+  return true;
+}
+
+//-----------------------------------------------------------------------------
+bool MessageComposer::getSourceText( QString &plainText, QString &htmlSource,
+                                     QByteArray &plainTextEncoded, QByteArray &htmlSourceEncoded ) const
 {
   // Get the HTML source and the plain text, with proper breaking
   //
@@ -2137,7 +2149,6 @@ void MessageComposer::breakLinesAndApply
   //
   // Therefore, we now read the plain text version directly from the composer,
   // which returns the correct result.
-  QString plainText, htmlSource;
   htmlSource = mComposeWin->mEditor->toHtml();
   if ( mDisableBreaking || !GlobalSettings::self()->wordWrap() )
     plainText = mComposeWin->mEditor->toPlainText();
@@ -2145,7 +2156,6 @@ void MessageComposer::breakLinesAndApply
     plainText = mComposeWin->mEditor->toWrappedPlainText();
 
   // Now, convert the string to a bytearray with the right codec
-  QByteArray plainTextEncoded, htmlSourceEncoded;
   QString newPlainText;
   const QTextCodec *codec = KMMsgBase::codecForName( mCharset );
   if ( mCharset == "us-ascii" ) {
@@ -2166,24 +2176,53 @@ void MessageComposer::breakLinesAndApply
   // Check if we didn't loose any characters during encoding.
   // This can be checked by decoding the encoded text and comparing it with the
   // original, it should be the same.
-  if ( !plainText.isEmpty() && ( newPlainText != plainText ) ) {
-    // FIXME the whole thing here is completely broken, see
-    //       bug 149309 and 145163.
-    //       Furthermore, there is no reason the set the text to the editor,
-    //       it will just break rich text formatting anyway. text() and
-    //       setText() are evil.
-    QString oldText = mComposeWin->mEditor->text();
-    mComposeWin->mEditor->setText( newPlainText );
+  if ( !plainText.isEmpty() && ( newPlainText != plainText ) )
+    return false;
+  else
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+bool MessageComposer::breakLinesAndApplyCodec()
+{
+  // Get the encoded text and HTML
+  QString plainText, htmlSource;
+  QByteArray plainTextEncoded, htmlSourceEncoded;
+  bool ok = getSourceText( plainText, htmlSource, plainTextEncoded, htmlSourceEncoded );
+
+  // Not all chars fit into the current charset, ask the user what to do about it.
+  if ( !ok ) {
     KCursorSaver idle( KBusyPtr::idle() );
-    bool anyway = ( KMessageBox::warningYesNo(
-                      mComposeWin,
-                      i18n("<qt>Not all characters fit into the chosen"
-                           " encoding.<br /><br />Send the message anyway?</qt>"),
-                      i18n("Some Characters Will Be Lost"),
-                      KGuiItem ( i18n("Lose Characters") ),
-                      KGuiItem( i18n("Change Encoding") ) ) == KMessageBox::Yes );
-    if ( !anyway ) {
-      mComposeWin->mEditor->setText( oldText );
+    bool loseChars = ( KMessageBox::warningYesNo(
+                       mComposeWin,
+                       i18n("<qt>Not all characters fit into the chosen"
+                            " encoding.<br /><br />Send the message anyway?</qt>"),
+                       i18n("Some Characters Will Be Lost"),
+                       KGuiItem ( i18n("Lose Characters") ),
+                       KGuiItem( i18n("Change Encoding") ) ) == KMessageBox::Yes );
+    if ( loseChars ) {
+      const QTextCodec *codec = KMMsgBase::codecForName( mCharset );
+      mComposeWin->mEditor->replaceUnknownChars( codec );
+    }
+    else {
+      // The user wants to change the encoding, so auto-detect a correct one.
+      bool charsetFound = autoDetectCharset();
+      if ( charsetFound ) {
+        // Read the values again, this time they should be correct, since we just
+        // set the correct charset.
+        bool ok = getSourceText( plainText, htmlSource, plainTextEncoded, htmlSourceEncoded );
+        if ( !ok ) {
+          kWarning() << "The autodetected charset is still wrong!";
+        }
+
+        // Now, set the charset of the composer, since we just changed it.
+        // Useful when this questionbox was brought up by autosave.
+        mComposeWin->setCharset( mCharset );
+      }
+      else { // no charset could be autodetected
+        mRc = false;
+        return false;
+      }
     }
   }
 
@@ -2213,6 +2252,8 @@ void MessageComposer::breakLinesAndApply
     mBodyText = mHtmlSource;
   else
     mBodyText = mPlainText;
+
+  return true;
 }
 
 //-----------------------------------------------------------------------------
--- kmail/kmcomposereditor.cpp	(revision 890880)
+++ kmail/kmcomposereditor.cpp	(revision 890881)
@@ -79,6 +79,23 @@ QString KMComposerEditor::quotePrefixNam
    return m_composerWin->quotePrefixName();
 }
 
+void KMComposerEditor::replaceUnknownChars( const QTextCodec *codec )
+{
+  QTextCursor cursor( document() );
+  cursor.beginEditBlock();
+  while ( !cursor.atEnd() ) {
+    cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::KeepAnchor );
+    QChar cur = cursor.selectedText().at( 0 );
+    if ( !codec->canEncode( cur ) ) {
+      cursor.insertText( "?" );
+    }
+    else {
+      cursor.clearSelection();
+    }
+  }
+  cursor.endEditBlock();
+}
+
 void KMComposerEditor::dropEvent( QDropEvent *e )
 {
   const QMimeData *md = e->mimeData();
Index: kmail/messagecomposer.h
===================================================================
Index: kmail/kmcomposereditor.h
===================================================================
Index: kmail/messagecomposer.cpp
===================================================================
Index: kmail/kmcomposereditor.cpp
===================================================================
openSUSE Build Service is sponsored by