[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kmail-devel
Subject:    [PATCH] composing html messages
From:       Edwin Schepers <yez () home ! nl>
Date:       2004-01-26 19:33:47
Message-ID: 200401262033.47326.yez () home ! nl
[Download RAW message or body]

Hi,
This is a first rough patch for composing html messages. Could someone review 
it ?

Thanks,
Edwin

behaviour is :
- Composing a new mail : default always starting in plaintext. when some 
markup is selected, the mail becomes multipart/altenative.
- Spellchecking : on "cancel", the original text is not set. only the 
spellchecking dialog disappears.
- With a menu option "Editor" in the "options" menu, one can explicitly choose 
the type. here, richtext can be set back to plaintext.
- in "Settings"->"Toolbars", the HTML toolbar can be choosen

Automatic Spellchecking on RichText is not possible, since QSyntaxHighlighter 
doesn't supprt this.

TODO :
- more \n cq. <p></p> appear in the message after repeatedly opening and 
saving from drafts

- spacing between lines is much more when first started with selecting for 
example the bold-button than when selecting all text and then selecting bold. 
Is this a QTextEdit issue which cannot be solved easily?
- boundaries dissapear after setMultiPartBody() .Could someone help me with 
this one ? The boundaries are set, but it seems setMultiPartBody() deletes 
them again. Maybe with a reason but I don't know. (kmail however doesn't have 
a problem showing the message)
Debug info from a test :
KMComposeWin::composeMessage():
      98.a:



|||--Boundary-00=_QQWFAngVx+VKruL
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

test
--Boundary-00=_QQWFAngVx+VKruL
Content-Type: text/html
Content-Transfer-Encoding: 7bit

<html><head><meta name="qrichtext" content="1" /></head><body 
style="font-size:12pt;font-family:helvetica">
<p><span style="font-weight:600">test</span></p>
</body></html>
kmail: |||





kmail:
kmail:






KMComposeWin::composeMessage():
      99.:



|||From: JES <yez@home.nl>
Reply-To:
Bcc:
To:
Subject:
Date: Mon, 26 Jan 2004 20:01:36 +0100
User-Agent: KMail/1.6.50
Cc:
MIME-Version: 1.0
Content-Description:
Content-Disposition: inline
Content-Type: multipart/alternative;
  charset="us-ascii"
Content-Transfer-Encoding: 7bit


--
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

test
--
Content-Type: text/html
Content-Transfer-Encoding: 7bit

<html><head><meta name="qrichtext" content="1" /></head><body 
style="font-size:12pt;font-family:helvetica">
<p><span style="font-weight:600">test</span></p>
</body></html>

----
kmail: |||

["htmlmail.diff" (text/x-diff)]

Index: kmail/kmcomposerui.rc
===================================================================
RCS file: /home/kde/kdepim/kmail/kmcomposerui.rc,v
retrieving revision 1.28
diff -u -r1.28 kmcomposerui.rc
--- kmail/kmcomposerui.rc	11 Nov 2003 01:23:52 -0000	1.28
+++ kmail/kmcomposerui.rc	26 Jan 2004 19:12:07 -0000
@@ -32,6 +32,10 @@
    <Action name="encrypt_message" />
    <Separator/>
    <Action name="options_select_crypto" />
+   <Menu name="editor"><text>&amp;Editor</text>
+    <Action name="plaintext"/>
+    <Action name="html"/>
+   </Menu>
    <Action name="charsets" />
    <Action name="wordwrap" />
    <Action name="options_auto_spellchecking" />
@@ -74,6 +78,7 @@
    <Action name="setup_spellchecker" append="save_merge"/>
   </Menu>
  </MenuBar>
+
  <ToolBar noMerge="1" name="mainToolBar" fullWidth="true" ><text>Main Toolbar</text>
   <Action name="send_default" />
   <Action name="send_alternative" />
@@ -88,4 +93,18 @@
   <Action name="encrypt_message" />
   <Action name="options_select_crypto" />
  </ToolBar>
+ <ToolBar noMerge="1" name="htmlToolBar" ><text>Html Toolbar</text>
+  <Action name="text_list" />
+  <Action name="text_font" />
+  <Action name="text_size" />
+  <Action name="text_bold" />
+  <Action name="text_italic" />
+  <Action name="text_under" />
+  <Action name="format_color" />
+  <Action name="align_left" />
+  <Action name="align_right" />
+  <Action name="align_center" />
+  <Action name="align_justify" />
+ </ToolBar>
+
 </kpartgui>
Index: kmail/kmcomposewin.cpp
===================================================================
RCS file: /home/kde/kdepim/kmail/kmcomposewin.cpp,v
retrieving revision 1.772
diff -u -r1.772 kmcomposewin.cpp
--- kmail/kmcomposewin.cpp	24 Jan 2004 23:39:03 -0000	1.772
+++ kmail/kmcomposewin.cpp	26 Jan 2004 19:12:26 -0000
@@ -7,6 +7,7 @@
 #define DEFAULT_EDITOR_STR "kate %f"
 
 //#define STRICT_RULES_OF_GERMAN_GOVERNMENT_01
+#define DEBUG
 
 #undef GrayScale
 #undef Color
@@ -75,6 +76,8 @@
 #include <kspelldlg.h>
 #include <spellingfilter.h>
 #include <ksyntaxhighlighter.h>
+#include <kcoloractions.h>
+#include <kcolordialog.h>
 
 #include <qtabdialog.h>
 #include <qregexp.h>
@@ -213,10 +216,29 @@
            SLOT( slotUpdateAttachActions() ) );
   mAttachMenu = 0;
 
+  useHTMLEditor = false;
+  mEditor->setAcceptDrops( true );
   readConfig();
   setupStatusBar();
   setupEditor();
   setupActions();
+
+  // configuration is read now
+  if (useHTMLEditor)
+    slotToggleToHTML();
+  else {
+    if ( aMsg ) {
+      if ( aMsg->typeStr()=="multipart" && aMsg->subtypeStr()=="alternative") {
+        slotToggleToHTML();
+      }
+      else {
+        slotToggleToPlaintext();
+      }
+    }
+    else
+      slotToggleToPlaintext();
+  }
+
   applyMainWindowSettings(KMKernel::config(), "Composer");
 
   connect(mEdtSubject,SIGNAL(textChanged(const QString&)),
@@ -288,6 +310,7 @@
     kdDebug(5006) << "KMAIL_DEBUG_COMPOSER_CRYPTO = FALSE" << endl;
   }
   mDone = true;
+
 }
 
 
@@ -943,9 +966,9 @@
     composerConfig.readBoolEntry( "autoSpellChecking", true );
   mAutoSpellCheckingAction->setEnabled( !mUseExtEditor );
   mAutoSpellCheckingAction->setChecked( !mUseExtEditor && spellChecking );
-  mEditor->slotAutoSpellCheckingToggled( !mUseExtEditor && spellChecking );
+  slotAutoSpellCheckingToggled( !mUseExtEditor && spellChecking );
   connect( mAutoSpellCheckingAction, SIGNAL( toggled( bool ) ),
-           mEditor, SLOT( slotAutoSpellCheckingToggled( bool ) ) );
+           this, SLOT( slotAutoSpellCheckingToggled( bool ) ) );
 
   QStringList encodings = KMMsgBase::supportedEncodings(TRUE);
   encodings.prepend( i18n("Auto-Detect"));
@@ -953,6 +976,14 @@
   mEncodingAction->setCurrentItem( -1 );
 
   //these are checkable!!!
+  plainTextAction = new KToggleAction (i18n("Plain text"), 0, this, \
SLOT(slotToggleToPlaintext()), +                      actionCollection(), \
"plaintext"); +
+  markupAction = new KToggleAction (i18n("With markup"), 0, this, \
SLOT(slotToggleToHTML()), +                      actionCollection(), "html");
+  plainTextAction->setChecked(!useHTMLEditor);
+  markupAction->setChecked(useHTMLEditor);
+
   mAllFieldsAction = new KToggleAction (i18n("&All Fields"), 0, this,
                                        SLOT(slotView()),
                                        actionCollection(), "show_all_fields");
@@ -1091,6 +1122,56 @@
     mCryptoModuleAction->setCurrentItem( idx );
   }
 
+  QStringList styleItems;
+  styleItems << i18n( "Standard" );
+  styleItems << i18n( "Bullet List (Disc)" );
+  styleItems << i18n( "Bullet List (Circle)" );
+  styleItems << i18n( "Bullet List (Square)" );
+  styleItems << i18n( "Ordered List (Decimal)" );
+  styleItems << i18n( "Ordered List (Alpha lower)" );
+  styleItems << i18n( "Ordered List (Alpha upper)" );
+
+  listAction = new KSelectAction( i18n( "Select Style" ), 0, actionCollection(),
+				  "text_list" );
+  listAction->setItems( styleItems );
+  connect( listAction, SIGNAL( activated( const QString& ) ),
+           SLOT( slotListAction( const QString& ) ) );
+  fontAction = new KFontAction( "Select Font", 0, actionCollection(), 
+				"text_font" );
+  connect( fontAction, SIGNAL( activated( const QString& ) ),
+           SLOT( slotFontAction( const QString& ) ) );
+  fontSizeAction = new KFontSizeAction( "Select Size", 0, actionCollection(), 
+					"text_size" );
+  connect( fontSizeAction, SIGNAL( fontSizeChanged( int ) ),
+           SLOT( slotSizeAction( int ) ) );
+
+  alignLeftAction = new KToggleAction (i18n("Align Left"), "text_left", 0,
+                      this, SLOT(slotAlignLeft()), actionCollection(), 
+                      "align_left");
+  alignLeftAction->setChecked( TRUE );
+  alignRightAction = new KToggleAction (i18n("Align Right"), "text_right", 0, 
+                      this, SLOT(slotAlignRight()), actionCollection(), 
+                      "align_right");
+  alignCenterAction = new KToggleAction (i18n("Align Center"), "text_center", 0,
+                       this, SLOT(slotAlignCenter()), actionCollection(), 
+                       "align_center");
+  alignJustifyAction = new KToggleAction (i18n("Align Justify"), "kmtextjustify", 0, \
 +                        this, SLOT(slotAlignJustify()),
+                        actionCollection(),
+                        "align_justify");
+  textBoldAction = new KToggleAction (i18n("&Bold"), "text_bold", 0,
+				      this, SLOT(slotTextBold()),
+				      actionCollection(), "text_bold");
+  textItalicAction = new KToggleAction (i18n("&Italic"), "text_italic", 0, 
+					this, SLOT(slotTextItalic()),
+					actionCollection(), "text_italic");
+  textUnderAction = new KToggleAction (i18n("&Under"), "text_under", 0,
+				       this, SLOT(slotTextUnder()),
+				       actionCollection(), "text_under");
+  actionFormatColor = new KAction( i18n( "Text Color..." ), "colorize", 0,
+                                     this, SLOT( slotTextColor() ),
+                                     actionCollection(), "format_color");
+
   createGUI("kmcomposerui.rc");
 }
 
@@ -1164,6 +1245,10 @@
   */
   updateCursorPosition();
   connect(mEditor,SIGNAL(CursorPositionChanged()),SLOT(updateCursorPosition()));
+  connect( mEditor, SIGNAL( currentFontChanged( const QFont & ) ),
+	   this, SLOT( fontChanged( const QFont & ) ) );
+  connect( mEditor, SIGNAL( currentAlignmentChanged( int ) ),
+	   this, SLOT( alignmentChanged( int ) ) );
 }
 
 
@@ -1224,11 +1309,14 @@
 {
   KMMessagePart bodyPart, *msgPart;
   int i, num;
+#ifdef DEBUG
+      kdDebug(5006) << "entering KMComposeWin::setMsg()" << endl;
+#endif
 
   //assert(newMsg!=0);
   if(!newMsg)
     {
-      kdDebug(5006) << "KMComposeWin::setMsg() : newMsg == 0!\n" << endl;
+      kdDebug(5006) << "KMComposeWin::setMsg() : newMsg == 0!" << endl;
       return;
     }
   mMsg = newMsg;
@@ -1346,10 +1434,23 @@
   if (num > 0)
   {
     QCString bodyDecoded;
-    mMsg->bodyPart(0, &bodyPart);
+    int firstAttachment=0;
 
-    int firstAttachment = (bodyPart.typeStr().lower() == "text") ? 1 : 0;
-    if (firstAttachment)
+    mMsg->bodyPart(1, &bodyPart);
+    if (bodyPart.typeStr().lower() == "text" && bodyPart.subtypeStr().lower() == \
"html" ) { +      kdDebug(5006) << "KMComposeWin::setMsg() : text/html found" << \
endl; +      firstAttachment = 2;
+      slotToggleToHTML();
+    } else {
+      mMsg->bodyPart(0, &bodyPart);
+      if (bodyPart.typeStr().lower() == "text" ) {
+        kdDebug(5006) << "KMComposeWin::setMsg() : text/ found" << endl;
+        firstAttachment = 1;
+        slotToggleToPlaintext();
+      }
+    }
+
+    if (firstAttachment != 0) // there's text to show
     {
       mCharset = bodyPart.charset();
       if ( mCharset.isEmpty() || mCharset == "default" )
@@ -1368,11 +1469,12 @@
 
       const QTextCodec *codec = KMMsgBase::codecForName(mCharset);
       if (codec)
-        mEditor->setText(codec->toUnicode(bodyDecoded));
+        setBody(codec->toUnicode(bodyDecoded));
       else
-        mEditor->setText(QString::fromLocal8Bit(bodyDecoded));
+        setBody(QString::fromLocal8Bit(bodyDecoded));
       mEditor->insertLine("\n", -1);
-    } else mEditor->setText("");
+    } else setBody("");
+
     for(i=firstAttachment; i<num; i++)
     {
       msgPart = new KMMessagePart;
@@ -1397,9 +1499,9 @@
 
     const QTextCodec *codec = KMMsgBase::codecForName(mCharset);
     if (codec) {
-      mEditor->setText(codec->toUnicode(bodyDecoded));
+      setBody(codec->toUnicode(bodyDecoded));
     } else
-      mEditor->setText(QString::fromLocal8Bit(bodyDecoded));
+      setBody(QString::fromLocal8Bit(bodyDecoded));
   }
 
   setCharset(mCharset);
@@ -1416,6 +1518,7 @@
     kmkernel->dumpDeadLetters();
   }
   mEditor->setModified(isModified);
+  kdDebug(5006) << "leaving KMComposeWin::setMsg()" << endl;
 }
 
 
@@ -1536,6 +1639,9 @@
 {
   QString str, atmntStr;
   QString temp, replyAddr;
+#ifdef DEBUG
+  kdDebug(5006) << "entering KMComposeWin::applyChanges" << endl;
+#endif
 
   //assert(mMsg!=0);
   if(!mMsg)
@@ -1909,6 +2015,12 @@
                                            bool ignoreBcc,
                                            QCString& signCertFingerprint )
 {
+#ifdef DEBUG
+  kdDebug(5006) << "entering KMComposeWin::composeMessage" << endl;
+  doSign?kdDebug(5006) <<"doSign=true"<<endl:kdDebug(5006) <<"doSign=false"<<endl;
+  doEncrypt?kdDebug(5006) <<"doEncrypt=true"<<endl:kdDebug(5006) \
<<"doEncrypt=false"<<endl; +#endif
+
   Kpgp::Result result = Kpgp::Ok;
   // create informative header for those that have no mime-capable
   // email client
@@ -1976,14 +2088,69 @@
   }
 
   KMMessagePart oldBodyPart;
-  oldBodyPart.setTypeStr(   earlyAddAttachments ? "multipart" : "text" );
-  oldBodyPart.setSubtypeStr(earlyAddAttachments ? "mixed"     : "plain");
+  if ( useHTMLEditor ) {
+    oldBodyPart.setTypeStr(   "multipart");
+    oldBodyPart.setSubtypeStr(earlyAddAttachments ? "mixed"     : "alternative");
+  }
+  else {
+    oldBodyPart.setTypeStr(   earlyAddAttachments ? "multipart" : "text" );
+    oldBodyPart.setSubtypeStr(earlyAddAttachments ? "mixed"     : "plain");
+  }
   oldBodyPart.setContentDisposition( "inline" );
 
-  QCString boundaryCStr;
-
   bool isQP = kmkernel->msgSender()->sendQuotedPrintable();
 
+  if (useHTMLEditor) {
+    // calculate a boundary string
+    QCString boundaryCStr;  // storing boundary string data
+    QCString newbody="";
+    DwMediaType tmpCT;
+    tmpCT.CreateBoundary( 0 );
+    boundaryCStr = tmpCT.Boundary().c_str();
+    QValueList<int> allowedCTEs;
+
+    KMMessagePart textBodyPart;
+    textBodyPart.setTypeStr("text");
+    textBodyPart.setSubtypeStr("plain");
+    mEditor->setTextFormat(Qt::PlainText);
+    QCString textbody = breakLinesAndApplyCodec();
+    mEditor->setTextFormat(Qt::RichText);
+    textBodyPart.setBodyAndGuessCte(textbody, allowedCTEs, !isQP && !doSign,
+                                     doSign);
+    DwBodyPart* textDwPart = theMessage.createDWBodyPart( &textBodyPart );
+    textDwPart->Assemble();
+    newbody += "--";
+    newbody +=     boundaryCStr;
+    newbody +=                 "\n";
+    newbody += textDwPart->AsString().c_str();
+    delete textDwPart;
+    textDwPart = 0;
+
+    KMMessagePart htmlBodyPart;
+    htmlBodyPart.setTypeStr("text");
+    htmlBodyPart.setSubtypeStr("html");
+    // the signed body must not be 8bit encoded
+    QCString htmlbody = breakLinesAndApplyCodec();
+    htmlBodyPart.setBodyAndGuessCte(htmlbody, allowedCTEs, !isQP && !doSign,
+                                     doSign);
+    DwBodyPart* htmlDwPart = theMessage.createDWBodyPart( &htmlBodyPart );
+    htmlDwPart->Assemble();
+    newbody += "\n--";
+    newbody +=     boundaryCStr;
+    newbody +=                 "\n";
+    newbody += htmlDwPart->AsString().c_str();
+    delete htmlDwPart;
+    htmlDwPart = 0;
+
+    //newbody += "--";
+    //newbody +=     boundaryCStr;
+    //newbody +=                 "\n";
+    kdDebug(5006) << "###newbody to  add in message : \"" << newbody << "\""<<endl;
+    body = newbody;
+  }
+
+  QCString boundaryCStr;
+
   if( earlyAddAttachments ) {
     // calculate a boundary string
     ++previousBoundaryLevel;
@@ -1992,15 +2159,21 @@
     boundaryCStr = tmpCT.Boundary().c_str();
     // add the normal body text
     KMMessagePart innerBodyPart;
-    innerBodyPart.setTypeStr(   "text" );
-    innerBodyPart.setSubtypeStr("plain");
+    if ( useHTMLEditor ) {
+      innerBodyPart.setTypeStr(   "text" );
+      innerBodyPart.setSubtypeStr("html");
+    }
+    else {
+      innerBodyPart.setTypeStr(   "text" );
+      innerBodyPart.setSubtypeStr("plain");
+    }
     innerBodyPart.setContentDisposition( "inline" );
     QValueList<int> allowedCTEs;
     // the signed body must not be 8bit encoded
     innerBodyPart.setBodyAndGuessCte(body, allowedCTEs, !isQP && !doSign,
                                      doSign);
     innerBodyPart.setCharset(mCharset);
-    innerBodyPart.setBodyEncoded( body );
+    innerBodyPart.setBodyEncoded( body ); // do we need this, since \
                setBodyAndGuessCte does this already?
     DwBodyPart* innerDwPart = theMessage.createDWBodyPart( &innerBodyPart );
     innerDwPart->Assemble();
     body  = "--";
@@ -2058,6 +2231,7 @@
                                    doSign);
     oldBodyPart.setCharset(mCharset);
   }
+kdDebug(5006) << "body is now : \n" << body << endl;
   // create S/MIME body part for signing and/or encrypting
   oldBodyPart.setBodyEncoded( body );
 
@@ -2205,7 +2379,7 @@
                             newBodyPart,
                                signCertFingerprint );
     }
-    //        kdDebug(5006) << "###AFTER ENCRYPTION\"" << theMessage.asString() << \
"\""<<endl; +    kdDebug(5006) << "###AFTER ENCRYPTION : \"" << theMessage.asString() \
<< "\""<<endl;  }
   return result;
 }
@@ -2311,6 +2485,10 @@
                                    KMMessagePart newBodyPart,
                                    QCString& signCertFingerprint )
 {
+#ifdef DEBUG
+  kdDebug(5006) << "entering KMComposeWin::encryptMessage" << endl;
+#endif
+
   Kpgp::Result result = Kpgp::Ok;
   if(!msg)
   {
@@ -2442,7 +2620,7 @@
         && ( !earlyAddAttachments || !allAttachmentsAreInBody ) ) {
       // set the content type header
       msg->headers().ContentType().FromString( "Multipart/Mixed" );
-kdDebug(5006) << "KMComposeWin::encryptMessage() : set top level Content-Type to \
Multipart/Mixed" << endl; +      kdDebug(5006) << "KMComposeWin::encryptMessage() : \
set top level Content-Type to Multipart/Mixed" << endl;  //      msg->setBody( "This \
message is in MIME format.\n"  //                    "Since your mail reader does not \
understand this format,\n"  //                    "some or all parts of this message \
may not be legible." ); @@ -2587,13 +2765,18 @@
         msg->headers().ContentType().Parse();
         //msg->headers().Assemble();
         //kdDebug(5006) << "\n\n\nKMComposeWin::composeMessage():\n      C.:\n\n" << \
                msg->headerAsString() << "|||\n\n\n\n\n" << endl;
-kdDebug(5006) << "KMComposeWin::encryptMessage() : set top level Content-Type from \
originalContentTypeStr()" << endl; +        //kdDebug(5006) << \
"KMComposeWin::encryptMessage() : set top level Content-Type from \
originalContentTypeStr()" << endl;  } else {
+        kdDebug(5006) << "KMComposeWin::composeMessage():\n      98.:\n\n|||" << \
msg->asString() << "|||\n\n" << endl; +        //kdDebug(5006) << \
"\n\n\nKMComposeWin::composeMessage(): ourFineBodyPart.originalContentTypeStr()='"<< \
                +	//		ourFineBodyPart.originalContentTypeStr()<<"'" << endl;
         msg->headers().ContentType().FromString( ourFineBodyPart.typeStr() + "/" + \
                ourFineBodyPart.subtypeStr() );
-kdDebug(5006) << "KMComposeWin::encryptMessage() : set top level Content-Type from \
typeStr()/subtypeStr()" << endl; +        //kdDebug(5006) << \
"ourFineBodyPart.typeStr()=" << ourFineBodyPart.typeStr() << ", \
ourFineBodyPart.subtypeStr()=" << ourFineBodyPart.subtypeStr() << endl; +
+	//kdDebug(5006) << "5. KMComposeWin::encryptMessage() : set top level Content-Type \
from typeStr()/subtypeStr()" << endl;  }
       //msg->headers().Assemble();
-      //kdDebug(5006) << "\n\n\nKMComposeWin::composeMessage():\n      D.:\n\n" << \
msg->headerAsString() << "|||\n\n\n\n\n" << endl; +      //kdDebug(5006) << \
"KMComposeWin::composeMessage():\n      D.:\n\n" << msg->headerAsString() << \
"|||\n\n\n\n\n" << endl;  msg->setCharset( ourFineBodyPart.charset() );
       //msg->headers().Assemble();
       //kdDebug(5006) << "\n\n\nKMComposeWin::composeMessage():\n      E.:\n\n" << \
msg->headerAsString() << "|||\n\n\n\n\n" << endl; @@ -2606,12 +2789,12 @@
       msg->setHeaderField( "Content-Disposition",
                             ourFineBodyPart.contentDisposition() );
 
-kdDebug(5006) << "KMComposeWin::encryptMessage() : top level headers and body \
adjusted" << endl; +      kdDebug(5006) << "KMComposeWin::encryptMessage() : top \
level headers and body adjusted" << endl;  
       // set body content
-      // msg->setBody( ourFineBodyPart.body() );
+      kdDebug(5006) << "\n\n\n\n\n\n\nKMComposeWin::composeMessage():\n      \
98.a:\n\n\n\n|||" << ourFineBodyPart.body() << "|||\n\n\n\n\n\n" << endl;  \
                msg->setMultiPartBody( ourFineBodyPart.body() );
-      //kdDebug(5006) << "\n\n\n\n\n\n\nKMComposeWin::composeMessage():\n      \
99.:\n\n\n\n|||" << msg->asString() << "|||\n\n\n\n\n\n" << endl; +      \
kdDebug(5006) << "\n\n\n\n\n\n\nKMComposeWin::composeMessage():\n      \
99.:\n\n\n\n|||" << msg->asString() << "|||\n\n\n\n\n\n" << endl;  \
                //msg->headers().Assemble();
       //kdDebug(5006) << "\n\n\nKMComposeWin::composeMessage():\n      Z.:\n\n" << \
msg->headerAsString() << "|||\n\n\n\n\n" << endl;  }
@@ -2986,7 +3169,7 @@
   QString text;
   QCString cText;
 
-  if (mDisableBreaking)
+  if (mDisableBreaking || mEditor->textFormat() == Qt::RichText)
       text = mEditor->text();
   else
       text = mEditor->brokenText();
@@ -3014,7 +3197,7 @@
     if (!text.isEmpty() && (newText != text))
     {
       QString oldText = mEditor->text();
-      mEditor->setText(newText);
+      setBody(newText);
       KCursorSaver idle(KBusyPtr::idle());
       bool anyway = (KMessageBox::warningYesNo(this,
                                                i18n("<qt>Not all characters fit into \
the chosen" @@ -3023,7 +3206,7 @@
                                                i18n("Send"), i18n("Change Encoding") \
) == KMessageBox::Yes);  if (!anyway)
       {
-        mEditor->setText(oldText);
+        setBody(oldText);
         return QCString();
       }
     }
@@ -4985,6 +5168,9 @@
   mAutoDeleteMsg = FALSE;
   mFolder = 0;
   close();
+#ifdef DEBUG
+    kdDebug(5006) << "leaving KMComposeWin::doSend()" << endl;
+#endif
   return true;
 }
 
@@ -5064,6 +5250,48 @@
   mEditor->cleanWhiteSpace();
 }
 
+//-----------------------------------------------------------------------------
+void KMComposeWin::slotToggleToPlaintext()
+{
+  if ( useHTMLEditor == true) { // don't do it twice
+    kdDebug(5006) << "setting PlainText editor" << endl;
+    useHTMLEditor = false;
+    mEditor->setTextFormat(Qt::PlainText);
+    QString text = mEditor->text();
+    mEditor->setText(text); // otherwise the text still looks formatted
+    mEditor->setModified(true);
+    markupAction->setChecked(false);
+    plainTextAction->setChecked(true);
+    mEditor->initializeAutoSpellChecking( mDictionaryCombo->spellConfig());
+    //mAutoSpellCheckingAction->setChecked(true);
+    slotAutoSpellCheckingToggled(true);
+  }
+}
+
+//-----------------------------------------------------------------------------
+void KMComposeWin::slotToggleToHTML()
+{
+  if ( useHTMLEditor == false ) { // don't do it twice
+    kdDebug(5006) << "setting RichText editor" << endl;
+    useHTMLEditor = true; // set it directly to true. setColor hits another \
slotToggleToHTML +
+    // set all highlighted text caused by spelling back to black
+    int paraFrom, indexFrom, paraTo, indexTo;
+    mEditor->getSelection ( &paraFrom, &indexFrom, &paraTo, &indexTo);
+    mEditor->selectAll();
+    mEditor->setColor(QColor(0,0,0));
+    mEditor->setSelection ( paraFrom, indexFrom, paraTo, indexTo);
+
+    mEditor->setTextFormat(Qt::RichText);
+    mEditor->setModified(true);
+    plainTextAction->setChecked(false);
+    markupAction->setChecked(true);
+    mEditor->deleteAutoSpellChecking();
+    mAutoSpellCheckingAction->setChecked(false);
+    slotAutoSpellCheckingToggled(false);
+  }
+}
+
 
 //-----------------------------------------------------------------------------
 void KMComposeWin::slotSpellcheck()
@@ -5202,7 +5430,7 @@
   {
     if( !mOldSigText.isEmpty() && mAutoSign )
       edtText.append( mOldSigText );
-    mEditor->setText( edtText );
+    setBody( edtText );
   }
 
   // disable certain actions if there is no PGP user identity set
@@ -5238,6 +5466,12 @@
 }
 
 //-----------------------------------------------------------------------------
+void KMComposeWin::slotAutoSpellCheckingToggled( bool on )
+{
+  if (mEditor->AutoSpellChecking(on) == -1 )
+    mAutoSpellCheckingAction->setChecked(false); // set it to false again
+}
+//-----------------------------------------------------------------------------
 void KMComposeWin::slotSpellcheckConfig()
 {
   KWin kwin;
@@ -5338,6 +5572,117 @@
     mAlwaysSend = bAlways;
 }
 
+void KMComposeWin::slotListAction( const QString& style )
+{
+    if ( style == i18n( "Standard" ) )
+	mEditor->setParagType( QStyleSheetItem::DisplayBlock, QStyleSheetItem::ListDisc );
+    else if ( style == i18n( "Bullet List (Disc)" ) )
+	mEditor->setParagType( QStyleSheetItem::DisplayListItem, QStyleSheetItem::ListDisc \
); +    else if ( style == i18n( "Bullet List (Circle)" ) )
+	mEditor->setParagType( QStyleSheetItem::DisplayListItem, \
QStyleSheetItem::ListCircle ); +    else if ( style == i18n( "Bullet List (Square)" ) \
) +	mEditor->setParagType( QStyleSheetItem::DisplayListItem, \
QStyleSheetItem::ListSquare ); +    else if ( style == i18n( "Ordered List (Decimal)" \
)) +	mEditor->setParagType( QStyleSheetItem::DisplayListItem, \
QStyleSheetItem::ListDecimal ); +    else if ( style == i18n( "Ordered List (Alpha \
lower)" ) ) +	mEditor->setParagType( QStyleSheetItem::DisplayListItem, \
QStyleSheetItem::ListLowerAlpha ); +    else if ( style == i18n( "Ordered List (Alpha \
upper)" ) ) +	mEditor->setParagType( QStyleSheetItem::DisplayListItem, \
QStyleSheetItem::ListUpperAlpha ); +    mEditor->viewport()->setFocus();
+}
+
+void KMComposeWin::slotFontAction( const QString& font)
+{
+    slotToggleToHTML();
+    mEditor->QTextEdit::setFamily( font );
+    mEditor->viewport()->setFocus();
+    qDebug( "font %s", font.latin1() );
+}
+
+void KMComposeWin::slotSizeAction( int size )
+{
+    slotToggleToHTML();
+    mEditor->setPointSize( size );
+    mEditor->viewport()->setFocus();
+    qDebug( "font size %d", size );
+}
+
+void KMComposeWin::slotAlignLeft()
+{
+    slotToggleToHTML();
+    mEditor->QTextEdit::setAlignment( AlignLeft );
+}
+
+void KMComposeWin::slotAlignCenter()
+{
+    slotToggleToHTML();
+    mEditor->QTextEdit::setAlignment( AlignHCenter );
+}
+
+void KMComposeWin::slotAlignRight()
+{
+    slotToggleToHTML();
+    mEditor->QTextEdit::setAlignment( AlignRight );
+}
+
+void KMComposeWin::slotAlignJustify()
+{
+    slotToggleToHTML();
+    mEditor->QTextEdit::setAlignment( AlignJustify );
+}
+
+void KMComposeWin::slotTextBold()
+{
+    kdDebug(5006) << "entering KMComposeWin::slotTextBold()" << endl;
+    slotToggleToHTML();
+    mEditor->setBold( textBoldAction->isChecked() );
+    //mEditor->QTextEdit::setBold( textBoldAction->isChecked() );
+    kdDebug(5006) << "leaving KMComposeWin::slotTextBold()" << endl;
+}
+
+void KMComposeWin::slotTextItalic()
+{
+    slotToggleToHTML();
+    mEditor->QTextEdit::setItalic( textItalicAction->isChecked() );
+}
+
+void KMComposeWin::slotTextUnder()
+{
+    slotToggleToHTML();
+    mEditor->QTextEdit::setUnderline( textUnderAction->isChecked() );
+}
+
+void KMComposeWin::slotTextColor()
+{
+  QColor color = mEditor->color();
+  if ( KColorDialog::getColor( color ) ) {
+    slotToggleToHTML();
+    mEditor->setColor( color );
+  }
+}
+
+void KMComposeWin::fontChanged( const QFont &f )
+{
+    kdDebug(5006) << "KMComposeWin::fontChanged()" << endl;
+    //if ( useHTMLEditor == true) {
+    //slotToggleToHTML(); don't toggle.
+    fontAction->setFont( f.family() );
+    fontSizeAction->setFontSize( f.pointSize() );
+    textBoldAction->setChecked( f.bold() );
+    textItalicAction->setChecked( f.italic() );
+    textUnderAction->setChecked( f.underline() );
+    //}
+}
+
+void KMComposeWin::alignmentChanged( int a )
+{
+    slotToggleToHTML();
+    alignLeftAction->setChecked( ( a == AlignAuto ) || ( a & AlignLeft ) );
+    alignCenterAction->setChecked( ( a & AlignHCenter ) );
+    alignRightAction->setChecked( ( a & AlignRight ) );
+    alignJustifyAction->setChecked( ( a & AlignJustify ) );
+}
+
 void KMEdit::contentsDragEnterEvent(QDragEnterEvent *e)
 {
     if (e->provides(MailListDrag::format()))
@@ -5681,7 +6026,7 @@
         newText.replace( QRegExp("\\s*\\(at\\)\\s*"), "@" );
     }
     contents = contents.left(pos)+newText+contents.mid(pos);
-    setText(contents);
+    setBody(contents);
     setEdited( true );
     setCursorPosition(pos+newText.length());
 }
@@ -5767,6 +6112,7 @@
   QColor defaultColor2( 0x00, 0x70, 0x00 );
   QColor defaultColor3( 0x00, 0x60, 0x00 );
   QColor defaultForeground( kapp->palette().active().text() );
+
   QColor col1 = readerConfig.readColorEntry( "ForegroundColor", &defaultForeground \
);  QColor col2 = readerConfig.readColorEntry( "QuotedText3", &defaultColor3 );
   QColor col3 = readerConfig.readColorEntry( "QuotedText2", &defaultColor2 );
@@ -5787,18 +6133,34 @@
 }
 
 //-----------------------------------------------------------------------------
+void KMEdit::deleteAutoSpellChecking()
+{ // because the highlighter doesn''t support RichText, delete its instance.
+  delete mSpellChecker;
+}
+//-----------------------------------------------------------------------------
 void KMEdit::addSuggestion(const QString& text, const QStringList& lst, unsigned int \
)  {
   mReplacements[text] = lst;
 }
 
+
+void KMEdit::setSpellCheckingActive(bool spellCheckingActive)
+{
+  if (textFormat() != Qt::RichText) {
+  mSpellChecker->setActive(spellCheckingActive);
+  }
+}
+
+
 //-----------------------------------------------------------------------------
 KMEdit::~KMEdit()
 {
   removeEventFilter(this);
 
   delete mKSpell;
+  if (textFormat() != Qt::RichText) {
   delete mSpellChecker;
+  }
 }
 
 
@@ -5966,11 +6328,17 @@
 
 
 //-----------------------------------------------------------------------------
-void KMEdit::slotAutoSpellCheckingToggled( bool on )
+int KMEdit::AutoSpellChecking( bool on )
 {
+  if (textFormat() == Qt::RichText ) {
+     // syntax highlighter doesn't support extended text properties
+     if (on) KMessageBox::sorry(this, i18n("Automatic spellchecking is not possible \
on text with markup.")); +     return -1;
+  }
   // don't autoEnable spell checking if the user turned spell checking off
   mSpellChecker->setAutomatic( on );
   mSpellChecker->setActive( on );
+  return 1;
 }
 
 
@@ -6028,8 +6396,16 @@
     return;
   mWasModifiedBeforeSpellCheck = isModified();
   mSpellLineEdit = !mSpellLineEdit;
-  mKSpell = new KSpell(this, i18n("Spellcheck - KMail"), this,
-                       SLOT(slotSpellcheck2(KSpell*)));
+//  maybe for later, for now plaintext is given to KSpell
+//  if (textFormat() == Qt::RichText ) {
+//    kdDebug(5006) << "KMEdit::spellcheck, spellchecking for RichText" << endl;
+//    mKSpell = new KSpell(this, i18n("Spellcheck - KMail"), this,
+//		       SLOT(slotSpellcheck2(KSpell*)),0,true,false,KSpell::HTML);
+//  }
+//  else {
+    mKSpell = new KSpell(this, i18n("Spellcheck - KMail"), this,
+		       SLOT(slotSpellcheck2(KSpell*)));
+//  }
   QStringList l = KSpellingHighlighter::personalWords();
   for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it ) {
       mKSpell->addPersonal( *it );
@@ -6047,20 +6423,26 @@
 #if KDE_IS_VERSION( 3, 1, 92 )
 void KMEdit::cut()
 {
-    KEdit::cut();
-    mSpellChecker->restartBackgroundSpellCheck();
+  KEdit::cut();
+  if (textFormat() != Qt::RichText) {
+  mSpellChecker->restartBackgroundSpellCheck();
+  }
 }
 
 void KMEdit::clear()
 {
-    KEdit::clear();
-    mSpellChecker->restartBackgroundSpellCheck();
+  KEdit::clear();
+  if (textFormat() != Qt::RichText) {
+  mSpellChecker->restartBackgroundSpellCheck();
+  }
 }
 
 void KMEdit::del()
 {
-    KEdit::del();
-    mSpellChecker->restartBackgroundSpellCheck();
+  KEdit::del();
+  if (textFormat() != Qt::RichText) {
+  mSpellChecker->restartBackgroundSpellCheck();
+  }
 }
 #else
 // can't #ifdef slots :-(
@@ -6084,8 +6466,28 @@
     kdDebug()<<"slotCorrected (const QString &oldWord, const QString &newWord, \
unsigned int pos) : "<<oldWord<<endl;  if( mSpellLineEdit )
         mComposer->sujectLineWidget()->spellCheckerCorrected( oldWord, newWord, \
                pos);
-     else
-         corrected(oldWord, newWord, pos);
+    else {
+        unsigned int l = 0;
+        unsigned int cnt = 0;
+	bool _bold,_underline,_italic;
+        QColor _color;
+        QFont _font;
+        posToRowCol (pos, l, cnt);
+	setCursorPosition(l, cnt+1); // the new word will get the same markup now
+	_bold = bold();
+	_underline = underline();
+	_italic = italic();
+        _color = color();
+        _font = currentFont();
+        corrected(oldWord, newWord, pos);
+	setSelection (l, cnt, l, cnt+newWord.length());
+	setBold(_bold);
+	setItalic(_italic);
+	setUnderline(_underline);
+        setColor(_color);
+        setCurrentFont(_font);
+    }
+
 }
 
 //-----------------------------------------------------------------------------
@@ -6110,7 +6512,10 @@
         }
 
         kdDebug(5006) << "spelling: new SpellingFilter with prefix=\"" << \
                quotePrefix << "\"" << endl;
-        mSpellingFilter = new SpellingFilter(text(), quotePrefix, \
SpellingFilter::FilterUrls, +	QTextEdit plaintext;
+	plaintext.setText(text());
+	plaintext.setTextFormat(Qt::PlainText);
+        mSpellingFilter = new SpellingFilter(plaintext.text(), quotePrefix, \
                SpellingFilter::FilterUrls,
                                              SpellingFilter::FilterEmailAddresses);
 
         mKSpell->check(mSpellingFilter->filteredText());
@@ -6140,8 +6545,9 @@
       }
       else
       {
-          kdDebug(5006) << "spelling: canceled - restoring text from SpellingFilter" \
                << endl;
-          setText(mSpellingFilter->originalText());
+          // don't restore, why undo all explicit replacements?
+          //kdDebug(5006) << "spelling: canceled - restoring text from \
SpellingFilter" << endl; +          //setText(mSpellingFilter->originalText());
           setModified(mWasModifiedBeforeSpellCheck);
       }
   }
Index: kmail/kmcomposewin.h
===================================================================
RCS file: /home/kde/kdepim/kmail/kmcomposewin.h,v
retrieving revision 1.226
diff -u -r1.226 kmcomposewin.h
--- kmail/kmcomposewin.h	28 Dec 2003 14:10:34 -0000	1.226
+++ kmail/kmcomposewin.h	26 Jan 2004 19:12:26 -0000
@@ -55,6 +55,9 @@
 class KProcess;
 class KDirWatch;
 class KSelectAction;
+class KFontAction;
+class KFontSizeAction;
+class KSelectAction;
 class KSpell;
 class KSpellConfig;
 class KDictSpellingHighlighter;
@@ -64,6 +67,7 @@
 class KTempFile;
 class KToolBar;
 class KToggleAction;
+class KSelectColorAction;
 class KURL;
 class IdentityCombo;
 class SpellingFilter;
@@ -98,6 +102,11 @@
   QString brokenText();
 
   /**
+   * Toggle automatic spellchecking
+   */
+  int AutoSpellChecking( bool );
+
+  /**
    * For the external editor
    */
   void setUseExternalEditor( bool use ) { mUseExtEditor = use; }
@@ -112,15 +121,18 @@
   bool checkExternalEditorFinished();
 
 
+  void setSpellCheckingActive(bool spellCheckingActive);
+
   /** Drag and drop methods */
   void contentsDragEnterEvent(QDragEnterEvent *e);
   void contentsDragMoveEvent(QDragMoveEvent *e);
   void contentsDropEvent(QDropEvent *e);
 
+  void initializeAutoSpellChecking( KSpellConfig* autoSpellConfig );
+  void deleteAutoSpellChecking();
 signals:
   void spellcheck_done(int result);
 public slots:
-  void slotAutoSpellCheckingToggled( bool );
   void slotSpellcheck2(KSpell*);
   void slotSpellResult(const QString&);
   void slotSpellDone();
@@ -145,7 +157,6 @@
 
 private:
   void killExternalEditor();
-  void initializeAutoSpellChecking( KSpellConfig* autoSpellConfig );
 
 private:
   KSpell *mKSpell;
@@ -505,6 +516,9 @@
 
   void slotCleanSpace();
 
+  void slotToggleToPlaintext();
+  void slotToggleToHTML();
+
 
 //  void slotSpellConfigure();
   void slotSpellcheckDone(int result);
@@ -542,6 +556,20 @@
    */
    void addAttach(const KMMessagePart* msgPart);
 
+   void slotListAction(const QString &);
+   void slotFontAction(const QString &);
+   void slotSizeAction(int);
+   void slotAlignLeft();
+   void slotAlignCenter();
+   void slotAlignRight();
+   void slotAlignJustify();
+   void slotTextBold();
+   void slotTextItalic();
+   void slotTextUnder();
+   void slotTextColor();
+   void fontChanged( const QFont & );
+   void alignmentChanged( int );
+
 signals:
   /**
    * A message has been queued or saved in the drafts folder
@@ -685,10 +713,10 @@
    * called via pgpSignedMsg() (or pgpEncryptedMsg(), resp.).
    *
    * NOTE: The c string representation of the MIME object (or the
-   *       flat text, resp.) is returned in resultingData, so just
+   *       flat text, resp.) is returned in resultingPart, so just
    *       use this string as body text of the surrounding MIME object.
    *       This string *is* encoded according to contentTEncClear
-   *       and thus should be ready for neing sended via SMTP.
+   *       and thus should be ready for being sent via SMTP.
    */
   bool processStructuringInfo( const QString   bugURL,
                                uint            boundaryLevel,
@@ -783,6 +811,7 @@
   KMFolder *mFolder;
   long mShowHeaders;
   QString mExtEditor;
+  bool useHTMLEditor;
   bool mUseExtEditor;
   QPtrList<_StringPair> mCustHeaders;
   bool mConfirmSend;
@@ -813,6 +842,15 @@
   KToggleAction *mWordWrapAction, *mFixedFontAction, *mAutoSpellCheckingAction;
   KToggleAction *mDictionaryAction;
 
+  KSelectAction *listAction;
+  KFontAction *fontAction;
+  KFontSizeAction *fontSizeAction;
+  KToggleAction *alignLeftAction, *alignCenterAction, *alignRightAction,
+      *alignJustifyAction;
+  KToggleAction *textBoldAction, *textItalicAction, *textUnderAction;
+  KToggleAction *plainTextAction, *markupAction;
+  KAction *actionFormatColor;
+
   KSelectAction *mEncodingAction;
   KSelectAction *mCryptoModuleAction;
 
@@ -830,6 +868,12 @@
   void slotCompletionModeChanged( KGlobalSettings::Completion );
   void slotConfigChanged();
 
+  /**
+   *  toggle automatic spellchecking
+   */
+  void slotAutoSpellCheckingToggled(bool);
+
+
 private:
   QColor mForeColor,mBackColor;
   struct atmLoadData
Index: kmail/kmmessage.h
===================================================================
RCS file: /home/kde/kdepim/kmail/kmmessage.h,v
retrieving revision 1.159
diff -u -r1.159 kmmessage.h
--- kmail/kmmessage.h	20 Jan 2004 12:28:09 -0000	1.159
+++ kmail/kmmessage.h	26 Jan 2004 19:12:29 -0000
@@ -589,7 +589,7 @@
   DwBodyPart * getFirstDwBodyPart() const;
 
   /** Fill the KMMessagePart structure for a given DwBodyPart.
-      Iff withBody is false the body of the KMMessagePart will be left
+      If withBody is false the body of the KMMessagePart will be left
       empty and only the headers of the part will be filled in*/
   static void bodyPart(DwBodyPart* aDwBodyPart, KMMessagePart* aPart,
 		       bool withBody = true );



_______________________________________________
KMail developers mailing list
KMail-devel@kde.org
https://mail.kde.org/mailman/listinfo/kmail-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic