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
===================================================================