[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-02-08 11:22:08
Message-ID: 200402081222.08275.yez () home ! nl
[Download RAW message or body]
Hi,
Finally it looks I have something workable.
It's not final: indentation, deleting some kDebug's and naming has to be
changed.
Could you (someone) review ?
If this is the way to go, and when it looks quite stable, can I commit (after
the changes to make it final)?
This feature also requires a small patch in kdelibs/kdeui/ksyntaxhighlighter.
Would that be a problem for kdepim-3.3 ?
Regards,
Edwin
["htmlmail.diff" (text/x-diff)]
? kmail/.kmcomposewin.cpp.swp
? kmail/.kmmessage.h.swp
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 8 Feb 2004 11:06:02 -0000
@@ -1,4 +1,4 @@
-<!DOCTYPE kpartgui ><kpartgui version="18" name="kmcomposer" >
+<!DOCTYPE kpartgui ><kpartgui version="19" name="kmcomposer" >
<MenuBar>
<Menu noMerge="1" name="file" >
<text>&Message</text>
@@ -32,6 +32,7 @@
<Action name="encrypt_message" />
<Separator/>
<Action name="options_select_crypto" />
+ <Action name="html"/>
<Action name="charsets" />
<Action name="wordwrap" />
<Action name="options_auto_spellchecking" />
@@ -74,6 +75,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 +90,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.782
diff -u -r1.782 kmcomposewin.cpp
--- kmail/kmcomposewin.cpp 7 Feb 2004 16:52:47 -0000 1.782
+++ kmail/kmcomposewin.cpp 8 Feb 2004 11:06:18 -0000
@@ -7,6 +7,7 @@
#define DEFAULT_EDITOR_STR "kate %f"
//#define STRICT_RULES_OF_GERMAN_GOVERNMENT_01
+#define DEBUG
#undef GrayScale
#undef Color
@@ -77,6 +78,7 @@
#include <kspelldlg.h>
#include <spellingfilter.h>
#include <ksyntaxhighlighter.h>
+#include <kcolordialog.h>
#include <qtabdialog.h>
#include <qregexp.h>
@@ -215,10 +217,29 @@
SLOT( slotUpdateAttachActions() ) );
mAttachMenu = 0;
+ useHTMLEditor = false;
+ mEditor->setAcceptDrops( true );
readConfig();
setupStatusBar();
setupEditor();
setupActions();
+
+ // configuration is read now
+ if (useHTMLEditor)
+ toggleMarkup(true);
+ else {
+ if ( aMsg ) {
+ if ( aMsg->typeStr()=="multipart" && aMsg->subtypeStr()=="alternative") {
+ toggleMarkup(true);
+ }
+ else {
+ toggleMarkup(false);
+ }
+ }
+ else
+ toggleMarkup(false);
+ }
+
applyMainWindowSettings(KMKernel::config(), "Composer");
connect(mEdtSubject,SIGNAL(textChanged(const QString&)),
@@ -290,6 +311,7 @@
kdDebug(5006) << "KMAIL_DEBUG_COMPOSER_CRYPTO = FALSE" << endl;
}
mDone = true;
+
}
@@ -962,9 +984,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"));
@@ -972,6 +994,14 @@
mEncodingAction->setCurrentItem( -1 );
//these are checkable!!!
+ //plainTextAction = new KToggleAction (i18n("Plain text"), 0, this, \
SLOT(slotToggleToPlaintext()), + // actionCollection(), \
"plaintext"); +
+ markupAction = new KToggleAction (i18n("HTML"), 0, this, SLOT(slotToggleMarkup()),
+ actionCollection(), "html");
+ //plainTextAction->setChecked(!useHTMLEditor);
+ markupAction->setChecked(useHTMLEditor);
+
mAllFieldsAction = new KToggleAction (i18n("&All Fields"), 0, this,
SLOT(slotView()),
actionCollection(), "show_all_fields");
@@ -1007,6 +1037,10 @@
actionCollection(), "show_subject");
//end of checkable
+ //mHtmlToolbar = new KAction (i18n("Html Toolbar"), 0, this,
+ // NULL,
+ // actionCollection(), "htmlToolBar");
+
(void) new KAction (i18n("Append S&ignature"), 0, this,
SLOT(slotAppendSignature()),
actionCollection(), "append_signature");
@@ -1110,6 +1144,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");
}
@@ -1183,6 +1267,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 ) ) );
}
@@ -1243,11 +1331,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;
@@ -1365,10 +1456,33 @@
if (num > 0)
{
QCString bodyDecoded;
- mMsg->bodyPart(0, &bodyPart);
+ int firstAttachment=0;
- int firstAttachment = (bodyPart.typeStr().lower() == "text") ? 1 : 0;
- if (firstAttachment)
+//JES : this part has to be refined
+// met attachment wordt een mail multipart/mixed. text/html is dan niet meer de 2e \
bodypart + mMsg->bodyPart(1, &bodyPart);
+ if (bodyPart.typeStr().lower() == "text" && bodyPart.subtypeStr().lower() == \
"html" ) { + kdDebug(5006) << "KMComposeWin::setMsg() : text/html found" << \
endl; + firstAttachment = 2;
+ toggleMarkup(true);
+ } else {
+ mMsg->bodyPart(2, &bodyPart);
+ if (bodyPart.typeStr().lower() == "text" && bodyPart.subtypeStr().lower() == \
"html" ) { + kdDebug(5006) << "KMComposeWin::setMsg() : text/html found" << \
endl; + firstAttachment = 3;
+ toggleMarkup(true);
+ }
+ else {
+ mMsg->bodyPart(0, &bodyPart);
+ if (bodyPart.typeStr().lower() == "text" ) {
+ kdDebug(5006) << "KMComposeWin::setMsg() : text/ found" << endl;
+ firstAttachment = 1;
+ toggleMarkup(true);
+ }
+ }
+ }
+
+ if (firstAttachment != 0) // there's text to show
{
mCharset = bodyPart.charset();
if ( mCharset.isEmpty() || mCharset == "default" )
@@ -1387,11 +1501,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;
@@ -1416,9 +1531,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);
@@ -1435,6 +1550,7 @@
kmkernel->dumpDeadLetters();
}
mEditor->setModified(isModified);
+ kdDebug(5006) << "leaving KMComposeWin::setMsg()" << endl;
}
@@ -1553,6 +1669,13 @@
//-----------------------------------------------------------------------------
bool KMComposeWin::applyChanges( bool backgroundMode )
{
+ QString str, atmntStr;
+ QString temp, replyAddr;
+#ifdef DEBUG
+ kdDebug(5006) << "entering KMComposeWin::applyChanges" << endl;
+#endif
+
+ //assert(mMsg!=0);
if(!mMsg) {
kdDebug(5006) << "KMComposeWin::applyChanges() : mMsg == 0!\n" << endl;
return FALSE;
@@ -1600,7 +1723,6 @@
mMsg->removeHeaderField("X-KMail-Identity");
else mMsg->setHeaderField("X-KMail-Identity", QString::number( id.uoid() ));
- QString replyAddr;
if (!replyTo().isEmpty()) replyAddr = replyTo();
else replyAddr = from();
@@ -1917,6 +2039,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
@@ -1984,14 +2112,73 @@
}
KMMessagePart oldBodyPart;
- oldBodyPart.setTypeStr( earlyAddAttachments ? "multipart" : "text" );
- oldBodyPart.setSubtypeStr(earlyAddAttachments ? "mixed" : "plain");
+ // if an html message is to be generated, make a text/plain and text/html part
+ 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) { // create a multipart body
+ // 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;
+ oldBodyPart.setBodyEncoded( newbody );
+
+// this is ugly, but I don't know another way right now. anyone?
+myGlobalBoundary = tmpCT.Boundary();
+ }
+ QCString boundaryCStr;
+
if( earlyAddAttachments ) {
// calculate a boundary string
++previousBoundaryLevel;
@@ -2000,15 +2187,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,7 +2251,7 @@
body += boundaryCStr;
body += "--\n";
}
- else
+ else // !earlyAddAttachments
{
QValueList<int> allowedCTEs;
// the signed body must not be 8bit encoded
@@ -2066,6 +2259,7 @@
doSign);
oldBodyPart.setCharset(mCharset);
}
+kdDebug(5006) << "body is now (3): \n" << body << endl;
// create S/MIME body part for signing and/or encrypting
oldBodyPart.setBodyEncoded( body );
@@ -2202,6 +2396,7 @@
theMessage.setHeaderField( "X-KMail-Recipients", \
recipientsWithoutBcc.join(",") ); }
+ kdDebug(5006) << "###BEFORE \"" << oldBodyPart.body() << "\""<< endl;
// run encrypting for public recipient(s)
if( result == Kpgp::Ok ){
result = encryptMessage( &theMessage,
@@ -2213,7 +2408,7 @@
newBodyPart,
signCertFingerprint );
}
- // kdDebug(5006) << "###AFTER ENCRYPTION\"" << theMessage.asString() << \
"\""<<endl; + kdDebug(5006) << "###AFTER ENCRYPTION : \"" << theMessage.asString() \
<< "\""<<endl; }
return result;
}
@@ -2319,6 +2514,10 @@
KMMessagePart newBodyPart,
QCString& signCertFingerprint )
{
+#ifdef DEBUG
+ kdDebug(5006) << "entering KMComposeWin::encryptMessage" << endl;
+#endif
+
Kpgp::Result result = Kpgp::Ok;
if(!msg)
{
@@ -2450,12 +2649,20 @@
&& ( !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;
-// 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." );
+ 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." );
// add our Body Part
- msg->addBodyPart( &ourFineBodyPart );
+DwBodyPart* myDwPart = msg->createDWBodyPart( &ourFineBodyPart );
+DwHeaders& headers = myDwPart->Headers();
+DwMediaType& ct = headers.ContentType();
+ct.SetBoundary(myGlobalBoundary);
+myDwPart->Assemble();
+
+ KMMessagePart newPart;
+ newPart.setBody(myDwPart->AsString().c_str());
+ msg->addDwBodyPart(myDwPart); // only this method doesn't add a bodypart \
text/plain
// add Attachments
// create additional bodyparts for the attachments (if any)
@@ -2577,8 +2784,9 @@
}
}
msg->addBodyPart( &newAttachPart );
- } else
+ } else {
msg->addBodyPart( attachPart );
+ }
kdDebug(5006) << " added " << idx << ". attachment \
to this Multipart/Mixed" << endl; } else {
@@ -2595,13 +2803,16 @@
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;
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; @@ -2614,13 +2825,18 @@
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() );
- 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 \
98.a:\n\n\n\n|||" << ourFineBodyPart.body() << "|||\n\n\n\n\n\n" << endl; + if ( \
useHTMLEditor) { // add the boundary to the header + DwMediaType & contentType \
= msg->dwContentType(); + contentType.SetBoundary(myGlobalBoundary);
+ }
+ msg->setBody(ourFineBodyPart.body() );
+ kdDebug(5006) << "\n\n\n\n\n\n\nKMComposeWin::composeMessage():\n \
99.:\n|||" << msg->asString() << "|||\n\n\n\n\n\n" << endl; \
//msg->headers().Assemble(); + kdDebug(5006) << \
"\n\n\n\n\n\n\nKMComposeWin::composeMessage():\n 100.:\n\n\n\n|||" << \
msg->asString() << "|||\n\n\n\n\n\n" << endl;
//kdDebug(5006) << "\n\n\nKMComposeWin::composeMessage():\n Z.:\n\n" << \
msg->headerAsString() << "|||\n\n\n\n\n" << endl; }
@@ -2994,7 +3210,7 @@
QString text;
QCString cText;
- if (mDisableBreaking)
+ if (mDisableBreaking || mEditor->textFormat() == Qt::RichText)
text = mEditor->text();
else
text = mEditor->brokenText();
@@ -3022,7 +3238,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" @@ -3031,7 +3247,7 @@
i18n("Send"), i18n("Change Encoding") \
) == KMessageBox::Yes); if (!anyway)
{
- mEditor->setText(oldText);
+ setBody(oldText);
return QCString();
}
}
@@ -4995,6 +5211,9 @@
mAutoDeleteMsg = FALSE;
mFolder = 0;
close();
+#ifdef DEBUG
+ kdDebug(5006) << "leaving KMComposeWin::doSend()" << endl;
+#endif
return true;
}
@@ -5074,6 +5293,62 @@
mEditor->cleanWhiteSpace();
}
+//-----------------------------------------------------------------------------
+void KMComposeWin::slotToggleMarkup()
+{
+ if ( markupAction->isChecked() ) {
+ kdDebug(5006) << "KMComposeWin::slotToggleMarkup, markupAction isChecked" << \
endl; + toggleMarkup(true);
+ }
+ else
+ toggleMarkup(false);
+
+}
+//-----------------------------------------------------------------------------
+void KMComposeWin::toggleMarkup(bool markup)
+{
+ if (markup)kdDebug(5006) << "KMComposeWin::toggleMarkup, entering. markup==true" \
<< endl; + if(!markup)kdDebug(5006) << "KMComposeWin::toggleMarkup, entering. \
markup==false" << endl; + if ( markup ) {
+ if (!useHTMLEditor) {
+ kdDebug(5006) << "setting RichText editor" << endl;
+ useHTMLEditor = true; // set it directly to true. setColor hits another \
toggleMarkup +
+ // set all highlighted text caused by spelling back to black
+ int paraFrom, indexFrom, paraTo, indexTo;
+ mEditor->getSelection ( ¶From, &indexFrom, ¶To, &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);
+ toolBar("htmlToolBar")->show();
+ markupAction->setChecked(true);
+ mEditor->deleteAutoSpellChecking();
+ mAutoSpellCheckingAction->setChecked(false);
+ slotAutoSpellCheckingToggled(false);
+ }
+ }
+ else {
+ 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);
+ toolBar("htmlToolBar")->hide();
+ //plainTextAction->setChecked(true);
+ kdDebug(5006) << "here" << endl;
+ mEditor->initializeAutoSpellChecking( mDictionaryCombo->spellConfig());
+ //mAutoSpellCheckingAction->setChecked(true);
+ slotAutoSpellCheckingToggled(true);
+ }
+
+}
+
//-----------------------------------------------------------------------------
void KMComposeWin::slotSpellcheck()
@@ -5212,7 +5487,7 @@
{
if( !mOldSigText.isEmpty() && mAutoSign )
edtText.append( mOldSigText );
- mEditor->setText( edtText );
+ setBody( edtText );
}
// disable certain actions if there is no PGP user identity set
@@ -5248,6 +5523,12 @@
}
//-----------------------------------------------------------------------------
+void KMComposeWin::slotAutoSpellCheckingToggled( bool on )
+{
+ if (mEditor->AutoSpellChecking(on) == -1 )
+ mAutoSpellCheckingAction->setChecked(false); // set it to false again
+}
+//-----------------------------------------------------------------------------
void KMComposeWin::slotSpellcheckConfig()
{
KWin kwin;
@@ -5348,6 +5629,119 @@
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)
+{
+ toggleMarkup(true);
+ mEditor->QTextEdit::setFamily( font );
+ mEditor->viewport()->setFocus();
+ qDebug( "font %s", font.latin1() );
+}
+
+void KMComposeWin::slotSizeAction( int size )
+{
+ toggleMarkup(true);
+ mEditor->setPointSize( size );
+ mEditor->viewport()->setFocus();
+ qDebug( "font size %d", size );
+}
+
+void KMComposeWin::slotAlignLeft()
+{
+ toggleMarkup(true);
+ mEditor->QTextEdit::setAlignment( AlignLeft );
+}
+
+void KMComposeWin::slotAlignCenter()
+{
+ toggleMarkup(true);
+ mEditor->QTextEdit::setAlignment( AlignHCenter );
+}
+
+void KMComposeWin::slotAlignRight()
+{
+ toggleMarkup(true);
+ mEditor->QTextEdit::setAlignment( AlignRight );
+}
+
+void KMComposeWin::slotAlignJustify()
+{
+ toggleMarkup(true);
+ mEditor->QTextEdit::setAlignment( AlignJustify );
+}
+
+void KMComposeWin::slotTextBold()
+{
+ kdDebug(5006) << "entering KMComposeWin::slotTextBold()" << endl;
+ toggleMarkup(true);
+ mEditor->setBold( textBoldAction->isChecked() );
+ //mEditor->QTextEdit::setBold( textBoldAction->isChecked() );
+ kdDebug(5006) << "leaving KMComposeWin::slotTextBold()" << endl;
+}
+
+void KMComposeWin::slotTextItalic()
+{
+ toggleMarkup(true);
+ mEditor->QTextEdit::setItalic( textItalicAction->isChecked() );
+}
+
+void KMComposeWin::slotTextUnder()
+{
+ toggleMarkup(true);
+ mEditor->QTextEdit::setUnderline( textUnderAction->isChecked() );
+}
+
+void KMComposeWin::slotTextColor()
+{
+ QColor color = mEditor->color();
+ if ( KColorDialog::getColor( color ) ) {
+ toggleMarkup(true);
+ mEditor->setColor( color );
+ }
+}
+
+void KMComposeWin::fontChanged( const QFont &f )
+{
+ kdDebug(5006) << "KMComposeWin::fontChanged()" << endl;
+ //if ( useHTMLEditor == true) {
+ //toggleMarkup(); don't toggle.
+ fontAction->setFont( f.family() );
+ fontSizeAction->setFontSize( f.pointSize() );
+if(f.bold())kdDebug(5006) << "KMComposeWin::fontChanged, f.bold()==true" << endl;
+if(!f.bold())kdDebug(5006) << "KMComposeWin::fontChanged, f.bold()==false" << endl;
+ textBoldAction->setChecked( f.bold() );
+ textItalicAction->setChecked( f.italic() );
+ textUnderAction->setChecked( f.underline() );
+ //}
+}
+
+void KMComposeWin::alignmentChanged( int a )
+{
+ //toggleMarkup();
+ 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()))
@@ -5718,7 +6112,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());
}
@@ -5805,6 +6199,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 );
@@ -5825,18 +6220,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;
+ }
}
@@ -6004,11 +6415,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;
}
@@ -6066,8 +6483,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 );
@@ -6085,20 +6510,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 :-(
@@ -6122,8 +6553,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);
+ }
+
}
//-----------------------------------------------------------------------------
@@ -6148,7 +6599,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());
@@ -6178,8 +6632,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.230
diff -u -r1.230 kmcomposewin.h
--- kmail/kmcomposewin.h 3 Feb 2004 23:11:25 -0000 1.230
+++ kmail/kmcomposewin.h 8 Feb 2004 11:06:22 -0000
@@ -31,6 +31,7 @@
#include "cryptplugwrapper.h"
#include <kabc/addresslineedit.h>
+#include <mimelib/mediatyp.h>
class _StringPair {
public:
@@ -55,6 +56,9 @@
class KProcess;
class KDirWatch;
class KSelectAction;
+class KFontAction;
+class KFontSizeAction;
+class KSelectAction;
class KSpell;
class KSpellConfig;
class KDictSpellingHighlighter;
@@ -64,6 +68,7 @@
class KTempFile;
class KToolBar;
class KToggleAction;
+class KSelectColorAction;
class KURL;
class IdentityCombo;
class SpellingFilter;
@@ -98,6 +103,11 @@
QString brokenText();
/**
+ * Toggle automatic spellchecking
+ */
+ int AutoSpellChecking( bool );
+
+ /**
* For the external editor
*/
void setUseExternalEditor( bool use ) { mUseExtEditor = use; }
@@ -112,15 +122,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 +158,6 @@
private:
void killExternalEditor();
- void initializeAutoSpellChecking( KSpellConfig* autoSpellConfig );
private:
KSpell *mKSpell;
@@ -511,6 +523,9 @@
void slotCleanSpace();
+ void slotToggleMarkup();
+ void toggleMarkup(bool markup);
+
// void slotSpellConfigure();
void slotSpellcheckDone(int result);
@@ -548,6 +563,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
@@ -692,10 +721,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,
@@ -790,6 +819,7 @@
KMFolder *mFolder;
long mShowHeaders;
QString mExtEditor;
+ bool useHTMLEditor;
bool mUseExtEditor;
QPtrList<_StringPair> mCustHeaders;
bool mConfirmSend;
@@ -821,6 +851,16 @@
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;
+ KAction *mHtmlToolbar;
+
KSelectAction *mEncodingAction;
KSelectAction *mCryptoModuleAction;
@@ -838,7 +878,14 @@
void slotCompletionModeChanged( KGlobalSettings::Completion );
void slotConfigChanged();
+ /**
+ * toggle automatic spellchecking
+ */
+ void slotAutoSpellCheckingToggled(bool);
+
+
private:
+DwString myGlobalBoundary;
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 8 Feb 2004 11:06:32 -0000
@@ -196,7 +196,7 @@
KMMessage* createDeliveryReceipt() const;
/** Create a new message that is a MDN for this message, filling all
- required felds with proper values. Th ereturned message is not
+ required fields with proper values. The returned message is not
stored in any folder.
@param a Use AutomaticAction for filtering and ManualAction for
@@ -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 );
["ksyntaxhighlighter.diff" (text/x-diff)]
Index: kdeui/ksyntaxhighlighter.cpp
===================================================================
RCS file: /home/kdecvs/kde/kdelibs/kdeui/ksyntaxhighlighter.cpp,v
retrieving revision 1.20
diff -u -p -u -r1.20 ksyntaxhighlighter.cpp
--- kdeui/ksyntaxhighlighter.cpp 10 Dec 2003 06:00:22 -0000 1.20
+++ kdeui/ksyntaxhighlighter.cpp 8 Feb 2004 11:04:32 -0000
@@ -131,6 +131,7 @@ KSyntaxHighlighter::KSyntaxHighlighter(
d->col5 = depth0;
d->mode = mode;
+ mTextEdit = textEdit; // to be able to check if RichText is being used
}
KSyntaxHighlighter::~KSyntaxHighlighter()
@@ -140,6 +141,7 @@ KSyntaxHighlighter::~KSyntaxHighlighter(
int KSyntaxHighlighter::highlightParagraph( const QString &text, int )
{
+ if (mTextEdit->textFormat() == RichText) return 0;
if (!d->enabled) {
setFormat( 0, text.length(), textEdit()->viewport()->paletteForegroundColor() );
return 0;
Index: kdeui/ksyntaxhighlighter.h
===================================================================
RCS file: /home/kdecvs/kde/kdelibs/kdeui/ksyntaxhighlighter.h,v
retrieving revision 1.11
diff -u -p -u -r1.11 ksyntaxhighlighter.h
--- kdeui/ksyntaxhighlighter.h 10 Dec 2003 06:00:22 -0000 1.11
+++ kdeui/ksyntaxhighlighter.h 8 Feb 2004 11:04:32 -0000
@@ -55,6 +55,7 @@ public:
private:
class KSyntaxHighlighterPrivate;
KSyntaxHighlighterPrivate *d;
+ QTextEdit *mTextEdit;
};
class KSpellingHighlighter : public KSyntaxHighlighter
_______________________________________________
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